summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorsobomax <sobomax@FreeBSD.org>2001-02-08 17:44:00 +0000
committersobomax <sobomax@FreeBSD.org>2001-02-08 17:44:00 +0000
commit391b1060843d1e99546c0c4b871c89ef16217a94 (patch)
tree5c4a922cdaca2a0d079072c7efa1182372c56a31 /usr.sbin
parent4331c8a979db44fc3779e72b294c0a5d6a78d619 (diff)
downloadFreeBSD-src-391b1060843d1e99546c0c4b871c89ef16217a94.zip
FreeBSD-src-391b1060843d1e99546c0c4b871c89ef16217a94.tar.gz
- By default treat supplied arguments as a shell globs to be matched against
names of installed packages; - add new `-G' option to disable glob matching and revert to previous behaviour (I have no idea why this could be necessary, though); - add a new `-x' option, which instructs pkg_info(1) to treat supplied arguments as a regular expressions. For example: $ pkg_info foo\* - displays information about all packages whose names start from foo $ pkg_info -G foo\*-1.1 - displays information about package named "foo*-1.1" $ pkg_info -x ^foo.\* - displays information about all packages whose names start from foo Original idea submitted by: Edwin Groothuis <mavetju@chello.nl> (bin/24695) Reviewed by: jkh, roam Approved by: jkh
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/pkg_install/info/info.h8
-rw-r--r--usr.sbin/pkg_install/info/main.c50
-rw-r--r--usr.sbin/pkg_install/info/perform.c155
-rw-r--r--usr.sbin/pkg_install/info/pkg_info.119
4 files changed, 191 insertions, 41 deletions
diff --git a/usr.sbin/pkg_install/info/info.h b/usr.sbin/pkg_install/info/info.h
index cbd5cfe..ba56efb 100644
--- a/usr.sbin/pkg_install/info/info.h
+++ b/usr.sbin/pkg_install/info/info.h
@@ -47,12 +47,18 @@
#define SHOW_ORIGIN 0x2000
#define SHOW_CKSUM 0x4000
+enum _match_t {
+ MATCH_ALL, MATCH_EXACT, MATCH_GLOB, MATCH_REGEX
+};
+
+typedef enum _match_t match_t;
+
extern int Flags;
-extern Boolean AllInstalled;
extern Boolean Quiet;
extern char *InfoPrefix;
extern char PlayPen[];
extern char *CheckPkg;
+extern match_t MatchType;
extern void show_file(char *, char *);
extern void show_plist(char *, Package *, plist_t);
diff --git a/usr.sbin/pkg_install/info/main.c b/usr.sbin/pkg_install/info/main.c
index da5330a..37947cc 100644
--- a/usr.sbin/pkg_install/info/main.c
+++ b/usr.sbin/pkg_install/info/main.c
@@ -28,10 +28,10 @@ static const char rcsid[] =
"$FreeBSD$";
#endif
-static char Options[] = "acdDe:fghiIkl:LmopqrRst:v";
+static char Options[] = "acdDe:fgGhiIkl:LmopqrRst:vx";
int Flags = 0;
-Boolean AllInstalled = FALSE;
+match_t MatchType = MATCH_GLOB;
Boolean Quiet = FALSE;
char *InfoPrefix = "";
char PlayPen[FILENAME_MAX];
@@ -48,13 +48,13 @@ main(int argc, char **argv)
pkgs = start = argv;
if (argc == 1) {
- AllInstalled = TRUE;
+ MatchType = MATCH_ALL;
Flags = SHOW_INDEX;
}
else while ((ch = getopt(argc, argv, Options)) != -1) {
switch(ch) {
case 'a':
- AllInstalled = TRUE;
+ MatchType = MATCH_ALL;
break;
case 'v':
@@ -92,6 +92,10 @@ main(int argc, char **argv)
Flags |= SHOW_CKSUM;
break;
+ case 'G':
+ MatchType = MATCH_EXACT;
+ break;
+
case 'i':
Flags |= SHOW_INSTALL;
break;
@@ -116,9 +120,9 @@ main(int argc, char **argv)
Flags |= SHOW_MTREE;
break;
- case 's':
- Flags |= SHOW_SIZE;
- break;
+ case 's':
+ Flags |= SHOW_SIZE;
+ break;
case 'o':
Flags |= SHOW_ORIGIN;
@@ -136,6 +140,10 @@ main(int argc, char **argv)
strcpy(PlayPen, optarg);
break;
+ case 'x':
+ MatchType = MATCH_REGEX;
+ break;
+
case 'e':
CheckPkg = optarg;
break;
@@ -157,23 +165,27 @@ main(int argc, char **argv)
/* Get all the remaining package names, if any */
while (*argv) {
- while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) {
- *pkgs_split++ = '\0';
- /*
- * If character after the '/' is alphanumeric, then we've found the
- * package name. Otherwise we've come across a trailing '/' and
- * need to continue our quest.
- */
- if (isalpha(*pkgs_split)) {
- *argv = pkgs_split;
- break;
+ /* Don't try to apply heuristics if arguments are regexs */
+ if (MatchType != MATCH_REGEX)
+ while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) {
+ *pkgs_split++ = '\0';
+ /*
+ * If character after the '/' is alphanumeric or shell
+ * metachar, then we've found the package name. Otherwise
+ * we've come across a trailing '/' and need to continue our
+ * quest.
+ */
+ if (isalpha(*pkgs_split) || ((MatchType == MATCH_GLOB) && \
+ strpbrk(pkgs_split, "*?[]") != NULL)) {
+ *argv = pkgs_split;
+ break;
+ }
}
- }
*pkgs++ = *argv++;
}
/* If no packages, yelp */
- if (pkgs == start && !AllInstalled && !CheckPkg)
+ if (pkgs == start && MatchType != MATCH_ALL && !CheckPkg)
warnx("missing package name(s)"), usage();
*pkgs = NULL;
return pkg_perform(start);
diff --git a/usr.sbin/pkg_install/info/perform.c b/usr.sbin/pkg_install/info/perform.c
index f9955bc..80de910 100644
--- a/usr.sbin/pkg_install/info/perform.c
+++ b/usr.sbin/pkg_install/info/perform.c
@@ -26,12 +26,16 @@ static const char rcsid[] =
#include "lib.h"
#include "info.h"
+#include <sys/types.h>
+#include <err.h>
+#include <glob.h>
#include <fts.h>
+#include <regex.h>
#include <signal.h>
-#include <err.h>
static int fname_cmp(const FTSENT **, const FTSENT **);
static int pkg_do(char *);
+static int rexs_match(char **, char *);
int
pkg_perform(char **pkgs)
@@ -50,31 +54,93 @@ pkg_perform(char **pkgs)
snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg);
return abs(access(buf, R_OK));
+ /* Not reached */
}
- else if (AllInstalled) {
- FTS *ftsp;
- FTSENT *f;
- char *paths[2];
- if (!isdir(tmp))
- return 1;
- paths[0] = tmp;
- paths[1] = NULL;
- ftsp = fts_open(paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT,
- fname_cmp);
- if (ftsp != NULL) {
- while ((f = fts_read(ftsp)) != NULL) {
- if (f->fts_info == FTS_D && f->fts_level == 1) {
- err_cnt += pkg_do(f->fts_name);
- fts_set(ftsp, f, FTS_SKIP);
+ switch (MatchType) {
+ case MATCH_ALL:
+ case MATCH_REGEX:
+ {
+ FTS *ftsp;
+ FTSENT *f;
+ char *paths[2];
+ int errcode;
+
+ if (!isdir(tmp))
+ return 1;
+ paths[0] = tmp;
+ paths[1] = NULL;
+ ftsp = fts_open(paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT,
+ fname_cmp);
+ if (ftsp != NULL) {
+ while ((f = fts_read(ftsp)) != NULL) {
+ if (f->fts_info == FTS_D && f->fts_level == 1) {
+ fts_set(ftsp, f, FTS_SKIP);
+ if (MatchType == MATCH_REGEX) {
+ errcode = rexs_match(pkgs, f->fts_name);
+ if (errcode == -1) {
+ err_cnt += 1;
+ break;
+ }
+ else if (errcode == 0)
+ continue;
+ }
+ err_cnt += pkg_do(f->fts_name);
+ }
}
+ fts_close(ftsp);
}
- fts_close(ftsp);
}
- }
- else
+ break;
+ case MATCH_GLOB:
+ {
+ glob_t g;
+ char *gexpr;
+ char *cp;
+ int gflags;
+ int prev_matchc;
+
+ gflags = GLOB_ERR;
+ prev_matchc = 0;
+ for (i = 0; pkgs[i]; i++) {
+ asprintf(&gexpr, "%s/%s", tmp, pkgs[i]);
+
+ if (glob(gexpr, gflags, NULL, &g) != 0) {
+ warn("%s: error encountered when matching glob", pkgs[i]);
+ return 1;
+ }
+
+ /*
+ * If glob doesn't match try to use pkgs[i] directly - it
+ * could be name of the tarball.
+ */
+ if (g.gl_matchc == prev_matchc)
+ err_cnt += pkg_do(pkgs[i]);
+
+ prev_matchc = g.gl_matchc;
+ gflags |= GLOB_APPEND;
+ free(gexpr);
+ }
+
+ for (i = 0; i < g.gl_matchc; i++) {
+ cp = strrchr(g.gl_pathv[i], '/');
+ if (cp == NULL)
+ cp = g.gl_pathv[i];
+ else
+ cp++;
+
+ err_cnt += pkg_do(cp);
+ }
+
+ globfree(&g);
+ }
+ break;
+ default:
for (i = 0; pkgs[i]; i++)
err_cnt += pkg_do(pkgs[i]);
+ break;
+ }
+
return err_cnt;
}
@@ -227,7 +293,7 @@ cleanup(int sig)
if (!in_cleanup) {
in_cleanup = 1;
- leave_playpen();
+ leave_playpen();
}
if (sig)
exit(1);
@@ -238,3 +304,52 @@ fname_cmp(const FTSENT **a, const FTSENT **b)
{
return strcmp((*a)->fts_name, (*b)->fts_name);
}
+
+/*
+ * Returns 1 if specified pkgname matches at least one
+ * of the RE from patterns. Otherwise return 0 if no
+ * matches were found or -1 if RE engine reported an
+ * error (usually invalid syntax).
+ */
+static int
+rexs_match(char **patterns, char *pkgname)
+{
+ Boolean matched;
+ char errbuf[128];
+ int i;
+ int errcode;
+ int retval;
+ regex_t rex;
+
+ errcode = 0;
+ retval = 0;
+ matched = FALSE;
+ for (i = 0; patterns[i]; i++) {
+ errcode = regcomp(&rex, patterns[i], REG_BASIC | REG_NOSUB);
+ if (errcode != 0)
+ break;
+
+ errcode = regexec(&rex, pkgname, 0, NULL, 0);
+ if (errcode == 0) {
+ matched = TRUE;
+ retval = 1;
+ break;
+ }
+ else if (errcode != REG_NOMATCH)
+ break;
+
+ regfree(&rex);
+ errcode = 0;
+ }
+
+ if (errcode != 0) {
+ regerror(errcode, &rex, errbuf, sizeof(errbuf));
+ warnx("%s: %s", patterns[i], errbuf);
+ retval = -1;
+ }
+
+ if ((errcode != 0) || (matched == TRUE))
+ regfree(&rex);
+
+ return retval;
+}
diff --git a/usr.sbin/pkg_install/info/pkg_info.1 b/usr.sbin/pkg_install/info/pkg_info.1
index 8a0da3f..4977359 100644
--- a/usr.sbin/pkg_install/info/pkg_info.1
+++ b/usr.sbin/pkg_install/info/pkg_info.1
@@ -25,7 +25,7 @@
.Nd a utility for displaying information on software packages
.Sh SYNOPSIS
.Nm
-.Op Fl cdDfgiIkLmopqrRsv
+.Op Fl cdDfgGiIkLmopqrRsvx
.Op Fl e Ar package
.Op Fl l Ar prefix
.Op Fl t Ar template
@@ -98,6 +98,23 @@ intended to give an idea as to where the underlying port, from which
package was generated, is located in the
.Fx
.Em "Ports Collection" .
+.It Fl G
+Do not try to expand shell glob patterns in the
+.Ar pkg-name
+when selecting packages to be displayed (by default
+.Nm
+automatically expands shell glob patterns in the
+.Ar pkg-name
+).
+.It Fl x
+Treat the
+.Ar pkg-name
+as a regular expression and display information only for packages
+whose names match that regular expression. Multiple regular
+expressions could be provided, in that case
+.Nm
+displays information about all packages that match at least one
+regular expression from the list.
.It Fl e Ar pkg-name
If the package identified by
.Ar pkg-name
OpenPOWER on IntegriCloud