diff --git a/usr.sbin/pkg_install/info/info.h b/usr.sbin/pkg_install/info/info.h index 3f0bb9a627dd..9f4b52f7a996 100644 --- a/usr.sbin/pkg_install/info/info.h +++ b/usr.sbin/pkg_install/info/info.h @@ -63,6 +63,7 @@ extern Boolean Quiet; extern char *InfoPrefix; extern char PlayPen[]; extern char *CheckPkg; +extern char *LookUpOrigin; extern match_t MatchType; extern struct which_head *whead; diff --git a/usr.sbin/pkg_install/info/main.c b/usr.sbin/pkg_install/info/main.c index 807f9608c7ea..29c0554e94ce 100644 --- a/usr.sbin/pkg_install/info/main.c +++ b/usr.sbin/pkg_install/info/main.c @@ -26,7 +26,7 @@ __FBSDID("$FreeBSD$"); #include "info.h" #include -static char Options[] = "acdDe:fgGhiIkl:LmopqrRst:vVW:x"; +static char Options[] = "acdDe:fgGhiIkl:LmoO:pqrRst:vVW:x"; int Flags = 0; match_t MatchType = MATCH_GLOB; @@ -34,6 +34,7 @@ Boolean Quiet = FALSE; char *InfoPrefix = (char *)(uintptr_t)""; char PlayPen[FILENAME_MAX]; char *CheckPkg = NULL; +char *LookUpOrigin = NULL; struct which_head *whead; static void usage __P((void)); @@ -132,6 +133,12 @@ main(int argc, char **argv) Flags |= SHOW_ORIGIN; break; + case 'O': + LookUpOrigin = strdup(optarg); + if (LookUpOrigin == NULL) + err(2, NULL); + break; + case 'V': Flags |= SHOW_FMTREV; break; @@ -211,7 +218,7 @@ main(int argc, char **argv) /* If no packages, yelp */ if (pkgs == start && MatchType != MATCH_ALL && !CheckPkg && - TAILQ_EMPTY(whead)) + TAILQ_EMPTY(whead) && LookUpOrigin == NULL) 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 d06f5e6dd24e..99967e3d2940 100644 --- a/usr.sbin/pkg_install/info/perform.c +++ b/usr.sbin/pkg_install/info/perform.c @@ -30,6 +30,7 @@ static int pkg_do(char *); static int find_pkg(const char *, struct which_head *); static int cmp_path(const char *, const char *, const char *); static char *abspath(const char *); +static int find_pkgs_by_origin(const char *, const char *); int pkg_perform(char **pkgs) @@ -52,6 +53,8 @@ pkg_perform(char **pkgs) /* Not reached */ } else if (!TAILQ_EMPTY(whead)) { return find_pkg(tmp, whead); + } else if (LookUpOrigin != NULL) { + return find_pkgs_by_origin(tmp, LookUpOrigin); } if (MatchType != MATCH_EXACT) { @@ -412,3 +415,61 @@ find_pkg(const char *db_dir, struct which_head *which_list) free(which_list); return 0; } + +/* + * Look through package dbs in db_dir and find which + * packages have the given origin. Don't use read_plist() + * because this increases time necessary for lookup by 40 + * times, as we don't really have to parse all plist to + * get origin. + */ +static int +find_pkgs_by_origin(const char *db_dir, const char *origin) +{ + char **installed; + int errcode, i; + + installed = matchinstalled(MATCH_ALL, NULL, &errcode); + if (installed == NULL) + return errcode; + + if (!Quiet) + printf("The following installed package(s) has %s origin:\n", origin); + for (i = 0; installed[i] != NULL; i++) { + FILE *fp; + char *cp, tmp[PATH_MAX]; + int cmd; + + snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i], + CONTENTS_FNAME); + fp = fopen(tmp, "r"); + if (fp == NULL) { + warn("%s", tmp); + return 1; + } + + cmd = -1; + while (fgets(tmp, sizeof(tmp), fp)) { + int len = strlen(tmp); + + while (len && isspace(tmp[len - 1])) + tmp[--len] = '\0'; + if (!len) + continue; + cp = tmp; + if (tmp[0] != CMD_CHAR) + continue; + cmd = plist_cmd(tmp + 1, &cp); + if (cmd == PLIST_ORIGIN) { + if (strcmp(origin, cp) == 0) + puts(installed[i]); + break; + } + } + if (cmd != PLIST_ORIGIN) + warnx("package %s has no origin recorded", installed[i]); + fclose(fp); + } + + return 0; +} diff --git a/usr.sbin/pkg_install/info/pkg_info.1 b/usr.sbin/pkg_install/info/pkg_info.1 index 37b52536de8b..c973209f362f 100644 --- a/usr.sbin/pkg_install/info/pkg_info.1 +++ b/usr.sbin/pkg_install/info/pkg_info.1 @@ -30,6 +30,7 @@ .Op Fl l Ar prefix .Op Fl t Ar template .Op Fl W Ar filename +.Op Fl O Ar origin .Op Ar pkg-name ... .Nm .Fl a @@ -114,6 +115,10 @@ current directory, and does not have an absolute path, then the .Ev PATH is searched using .Xr which 1 . +.It Fl O +For the specified +.Ar origin +argument list all packages having this origin. .It Fl x Treat the .Ar pkg-name diff --git a/usr.sbin/pkg_install/info/show.c b/usr.sbin/pkg_install/info/show.c index 95550d1a04f6..7421fbd6d069 100644 --- a/usr.sbin/pkg_install/info/show.c +++ b/usr.sbin/pkg_install/info/show.c @@ -312,21 +312,17 @@ show_cksum(const char *title, Package *plist) void show_origin(const char *title, Package *plist) { - PackingList p; if (!Quiet) printf("%s%s", InfoPrefix, title); - for (p = plist->head; p != NULL; p = p->next) - if (p->type == PLIST_COMMENT && !strncmp(p->name, "ORIGIN:", 7)) { - printf("%s\n", p->name + 7); - break; - } + printf("%s\n", plist->origin != NULL ? plist->origin : ""); } /* Show revision number of the packing list */ void show_fmtrev(const char *title, Package *plist) { + if (!Quiet) printf("%s%s", InfoPrefix, title); printf("%d.%d\n", plist->fmtver_maj, plist->fmtver_mnr); diff --git a/usr.sbin/pkg_install/lib/lib.h b/usr.sbin/pkg_install/lib/lib.h index 55fd2fa52e42..2b12d2f3528c 100644 --- a/usr.sbin/pkg_install/lib/lib.h +++ b/usr.sbin/pkg_install/lib/lib.h @@ -91,7 +91,7 @@ enum _plist_t { PLIST_CHOWN, PLIST_CHGRP, PLIST_COMMENT, PLIST_IGNORE, PLIST_NAME, PLIST_UNEXEC, PLIST_SRC, PLIST_DISPLAY, PLIST_PKGDEP, PLIST_MTREE, PLIST_DIR_RM, PLIST_IGNORE_INST, - PLIST_OPTION + PLIST_OPTION, PLIST_ORIGIN }; typedef enum _plist_t plist_t; @@ -113,6 +113,8 @@ typedef struct _plist *PackingList; struct _pack { struct _plist *head, *tail; + char *name; + char *origin; int fmtver_maj, fmtver_mnr; }; typedef struct _pack Package; diff --git a/usr.sbin/pkg_install/lib/plist.c b/usr.sbin/pkg_install/lib/plist.c index c60e589d7d8c..e46d6deda593 100644 --- a/usr.sbin/pkg_install/lib/plist.c +++ b/usr.sbin/pkg_install/lib/plist.c @@ -42,6 +42,18 @@ add_plist(Package *p, plist_t type, const char *arg) p->tail->next = tmp; p->tail = tmp; } + switch (type) { + case PLIST_NAME: + p->name = tmp->name; + break; + + case PLIST_ORIGIN: + p->origin = tmp->name; + break; + + default: + break; + } } void @@ -210,9 +222,13 @@ plist_cmd(const char *s, char **arg) return PLIST_CHOWN; else if (!strcmp(cmd, "group")) return PLIST_CHGRP; - else if (!strcmp(cmd, "comment")) + else if (!strcmp(cmd, "comment")) { + if (!strncmp(*arg, "ORIGIN:", 7)) { + *arg += 7; + return PLIST_ORIGIN; + } return PLIST_COMMENT; - else if (!strcmp(cmd, "ignore")) + } else if (!strcmp(cmd, "ignore")) return PLIST_IGNORE; else if (!strcmp(cmd, "ignore_inst")) return PLIST_IGNORE_INST;