From owner-freebsd-ports Thu Mar 1 10:30:39 2001 Delivered-To: freebsd-ports@freebsd.org Received: from isris.pair.com (isris.pair.com [209.68.2.39]) by hub.freebsd.org (Postfix) with SMTP id 5A58237B71C for ; Thu, 1 Mar 2001 10:30:22 -0800 (PST) (envelope-from rooneg@isris.pair.com) Received: (qmail 26440 invoked by uid 3130); 1 Mar 2001 18:30:20 -0000 Date: Thu, 1 Mar 2001 13:30:20 -0500 From: Garrett Rooney To: Maxim Sobolev Cc: ports@FreeBSD.org, jhk@FreeBSD.org, gad@FreeBSD.org, reg@FreeBSD.org Subject: Re: [patch] which package functionality for pkg_info Message-ID: <20010301133020.A23453@electricjellyfish.net> References: <3A9E8D0C.A24FD064@FreeBSD.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="zhXaljGHf11kAtnf" Content-Disposition: inline User-Agent: Mutt/1.2.5i In-Reply-To: <3A9E8D0C.A24FD064@FreeBSD.org>; from sobomax@FreeBSD.org on Thu, Mar 01, 2001 at 07:55:24PM +0200 Sender: owner-freebsd-ports@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org --zhXaljGHf11kAtnf Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Thu, Mar 01, 2001 at 07:55:24PM +0200, Maxim Sobolev wrote: > Attached please find revised patch that uses matchinstalled() instead of fts > loop. IMO the code looks much cleaner. I fixed several other issues as well > (leak of opened file, useless snprintf(&a, strlen(b), b) useless include etc.). thanks, that does look quite a bit better. i don't know why that didn't occur to me. > Please also try to review usage of MAXPATHLEN vs. FILENAME_MAX, I supect that > you should use one of these uniformely across the code. after looking at the rest of the code, i've changed everything to use FILENAME_MAX. it's more consistent, and they're defined to be the same thing anyway. > Also please extend your patch to print only names of matching packages when > invoked in the quiet mode (should be usefull in scripts and such). done! one more thing. i notice that matchinstalled() returns a null terminated array of strings, but they don't seem to be being freed anywhere. should they? thanks, -garrett -- garrett rooney Unix was not designed to stop you from rooneg@electricjellyfish.net doing stupid things, because that would http://electricjellyfish.net/ stop you from doing clever things. --zhXaljGHf11kAtnf Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="pkg_info.diff" Index: info/info.h =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/info/info.h,v retrieving revision 1.18 diff -u -r1.18 info.h --- info/info.h 2001/02/27 09:00:18 1.18 +++ info/info.h 2001/03/01 18:20:10 @@ -47,12 +47,21 @@ #define SHOW_ORIGIN 0x2000 #define SHOW_CKSUM 0x4000 +struct which_entry { + TAILQ_ENTRY(which_entry) next; + char file[FILENAME_MAX]; + char package[FILENAME_MAX]; + Boolean skip; +}; +TAILQ_HEAD(which_head, which_entry); + extern int Flags; extern Boolean Quiet; extern char *InfoPrefix; extern char PlayPen[]; extern char *CheckPkg; extern match_t MatchType; +extern struct which_head *whead; extern void show_file(char *, char *); extern void show_plist(char *, Package *, plist_t); Index: info/main.c =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/info/main.c,v retrieving revision 1.30 diff -u -r1.30 main.c --- info/main.c 2001/02/24 14:10:31 1.30 +++ info/main.c 2001/03/01 18:20:27 @@ -19,7 +19,9 @@ * */ +#include #include + #include "lib.h" #include "info.h" @@ -28,7 +30,7 @@ "$FreeBSD$"; #endif -static char Options[] = "acdDe:fgGhiIkl:LmopqrRst:vx"; +static char Options[] = "acdDe:fgGhiIkl:LmopqrRst:vW:x"; int Flags = 0; match_t MatchType = MATCH_GLOB; @@ -36,6 +38,7 @@ char *InfoPrefix = ""; char PlayPen[FILENAME_MAX]; char *CheckPkg = NULL; +struct which_head *whead; static void usage __P((void)); @@ -46,6 +49,11 @@ char **pkgs, **start; char *pkgs_split; + whead = malloc(sizeof(struct which_head)); + if (whead == NULL) + err(2, NULL); + TAILQ_INIT(whead); + pkgs = start = argv; if (argc == 1) { MatchType = MATCH_ALL; @@ -148,6 +156,20 @@ CheckPkg = optarg; break; + case 'W': + { + struct which_entry *entp; + + entp = calloc(1, sizeof(struct which_entry)); + if (entp == NULL) + err(2, NULL); + + strlcpy(entp->file, optarg, FILENAME_MAX); + entp->skip = FALSE; + TAILQ_INSERT_TAIL(whead, entp, next); + break; + } + case 'h': case '?': default: @@ -185,7 +207,8 @@ } /* If no packages, yelp */ - if (pkgs == start && MatchType != MATCH_ALL && !CheckPkg) + if (pkgs == start && MatchType != MATCH_ALL && !CheckPkg && + TAILQ_EMPTY(whead)) warnx("missing package name(s)"), usage(); *pkgs = NULL; return pkg_perform(start); @@ -196,7 +219,7 @@ { fprintf(stderr, "%s\n%s\n%s\n", "usage: pkg_info [-cdDfGiIkLmopqrRsvx] [-e package] [-l prefix]", - " [-t template] [pkg-name ...]", + " [-t template] [-W filename] [pkg-name ...]", " pkg_info -a [flags]"); exit(1); } Index: info/perform.c =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/info/perform.c,v retrieving revision 1.36 diff -u -r1.36 perform.c --- info/perform.c 2001/03/01 13:08:07 1.36 +++ info/perform.c 2001/03/01 18:23:19 @@ -23,14 +23,16 @@ * */ -#include "lib.h" -#include "info.h" - -#include #include #include +#include +#include "lib.h" +#include "info.h" + static int pkg_do(char *); +static int find_pkg(char *, struct which_head *); +static int cmp_path(const char *, const char *, const char *); int pkg_perform(char **pkgs) @@ -42,16 +44,19 @@ signal(SIGINT, cleanup); + tmp = getenv(PKG_DBDIR); + if (!tmp) + tmp = DEF_LOG_DIR; + /* Overriding action? */ if (CheckPkg) { char buf[FILENAME_MAX]; - tmp = getenv(PKG_DBDIR); - if (!tmp) - tmp = DEF_LOG_DIR; snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg); return abs(access(buf, R_OK)); /* Not reached */ + } else if (!TAILQ_EMPTY(whead)) { + return find_pkg(tmp, whead); } if (MatchType != MATCH_EXACT) { @@ -239,3 +244,155 @@ exit(1); } +/* comparison to see if the path we're on matches the one we are looking + * for. */ +static int +cmp_path(const char *target, const char *current, const char *cwd) +{ + char *fixed_path; + char *temp; + char *itr1; + char *itr2; + int rval, fixed_len; + + fixed_path = calloc(strlen(current) + strlen(cwd) + 2, sizeof(char)); + asprintf(&temp, "%s/%s", cwd, current); + if (fixed_path == NULL || temp == NULL) { + errx(2, "out of memory\n"); + } + + /* make sure there's no multiple /'s, since some plists seem to have them + * and it could screw up our strncmp. */ + for (itr1 = temp, itr2 = fixed_path; *itr1 != '\0'; itr1++) { + *itr2 = *itr1; + if (*itr2 == '/') { + if (*(itr1 + 1) != '/') + itr2++; + } else + itr2++; + } + + fixed_len = strlen(fixed_path); + if (strlen(target) == fixed_len && !strncmp(target, fixed_path, fixed_len)) + rval = 1; + else + rval = 0; + free(fixed_path); + free(temp); + return rval; +} + +/* look through package dbs in db_dir and find which packages installed the + * files in which_list. */ +static int +find_pkg(char *db_dir, struct which_head *which_list) +{ + struct which_entry *wp; + char **installed; + int errcode, i; + + TAILQ_FOREACH(wp, which_list, next) { + /* if it's not a file, we'll see if it's an executable. */ + if (isfile(wp->file) == FALSE) { + if (strchr(wp->file, '/') == NULL) { + char *tmp; + tmp = vpipe("which %s", wp->file); + if (tmp == NULL) { + warnx("file %s is not in path", wp->file); + wp->skip = TRUE; + } else + strlcpy(wp->file, tmp, FILENAME_MAX); + free(tmp); + } else { + warnx("file %s cannot be found", wp->file); + wp->skip = TRUE; + } + } else if (strncmp(wp->file, "/", 1) != 0) { + /* if it is a file, and it doesn't start with a /, then it's a + * relative path. in order to give us some chance of getting a + * successful match, tack the current working directory on the + * beginning. this won't work for filenames that include .. or . + * or extra /'s, but it's better than nothing). */ + char *curdir; + char *tmp; + + curdir = getcwd(NULL, FILENAME_MAX); + if (curdir == NULL) + err(2, NULL); + + asprintf(&tmp, "%s/%s", curdir, wp->file); + if (tmp == NULL) + err(2, NULL); + + if (!isfile(tmp)) { + warnx("file %s cannot be found", tmp); + wp->skip = TRUE; + } else + strlcpy(wp->file, tmp, FILENAME_MAX); + + free(tmp); + free(curdir); + } + } + + installed = matchinstalled(MATCH_ALL, NULL, &errcode); + if (installed == NULL) + return errcode; + + for (i = 0; installed[i] != NULL; i++) { + FILE *fp; + Package pkg; + PackingList itr; + char *cwd = NULL; + char tmp[FILENAME_MAX]; + + snprintf(tmp, FILENAME_MAX, "%s/%s/%s", db_dir, installed[i], + CONTENTS_FNAME); + fp = fopen(tmp, "r"); + if (fp == NULL) { + warn("%s", tmp); + return 1; + } + + pkg.head = pkg.tail = NULL; + read_plist(&pkg, fp); + fclose(fp); + for (itr = pkg.head; itr != pkg.tail; itr = itr->next) { + if (itr->type == PLIST_CWD) { + cwd = itr->name; + } else if (itr->type == PLIST_FILE) { + TAILQ_FOREACH(wp, which_list, next) { + if (wp->skip == TRUE) + continue; + if (!cmp_path(wp->file, itr->name, cwd)) + continue; + if (wp->package[0] != '\0') { + warnx("Both %s and %s claim to have installed %s\n", + wp->package, installed[i], wp->file); + } else { + strlcpy(wp->package, installed[i], FILENAME_MAX); + } + } + } + } + free_plist(&pkg); + } + + TAILQ_FOREACH(wp, which_list, next) { + if (wp->package[0] != '\0') { + if (Quiet) + fprintf(stdout, "%s\n", wp->package); + else + fprintf(stdout, "%s was installed by package %s\n", + wp->file, wp->package); + } + } + while (!TAILQ_EMPTY(which_list)) { + wp = TAILQ_FIRST(which_list); + TAILQ_REMOVE(which_list, wp, next); + free(wp); + } + + free(which_list); + return 0; +} Index: info/pkg_info.1 =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/info/pkg_info.1,v retrieving revision 1.37 diff -u -r1.37 pkg_info.1 --- info/pkg_info.1 2001/02/20 21:57:19 1.37 +++ info/pkg_info.1 2001/03/01 18:15:58 @@ -29,6 +29,7 @@ .Op Fl e Ar package .Op Fl l Ar prefix .Op Fl t Ar template +.Op Fl W Ar filename .Op Ar pkg-name ... .Nm .Fl a @@ -105,6 +106,14 @@ .Nm automatically expands shell glob patterns in the .Ar pkg-name ) . +.It Fl W +For the specified +.Ar filename +argument show which package it belongs to. If the file is not in the +current directory, and does not have an absolute path, then the +.Ev PATH +is searched using +.Xr which 1 . .It Fl x Treat the .Ar pkg-name Index: info/show.c =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/info/show.c,v retrieving revision 1.20 diff -u -r1.20 show.c --- info/show.c 2001/02/05 09:56:52 1.20 +++ info/show.c 2001/03/01 18:15:58 @@ -23,14 +23,15 @@ * */ -#include "lib.h" -#include "info.h" - #include #include #include #include +#include #include + +#include "lib.h" +#include "info.h" void show_file(char *title, char *fname) Index: lib/exec.c =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/lib/exec.c,v retrieving revision 1.7 diff -u -r1.7 exec.c --- lib/exec.c 1999/08/28 01:18:05 1.7 +++ lib/exec.c 2001/03/01 18:15:58 @@ -60,3 +60,47 @@ return ret; } +char * +vpipe(const char *fmt, ...) +{ + va_list args; + char *cmd, *rp; + int maxargs; + FILE *fp; + + rp = malloc(MAXPATHLEN); + if (!rp) { + warnx("vpipe can't alloc buffer space"); + return NULL; + } + maxargs = sysconf(_SC_ARG_MAX); + maxargs -= 32; /* some slop for the sh -c */ + cmd = malloc(maxargs); + if (!cmd) { + warnx("vpipe can't alloc arg space"); + return NULL; + } + + va_start(args, fmt); + if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) { + warnx("vsystem args are too long"); + return NULL; + } +#ifdef DEBUG + printf("Executing %s\n", cmd); +#endif + fflush(NULL); + fp = popen(cmd, "r"); + get_string(rp, MAXPATHLEN, fp); +#ifdef DEBUG + printf("Returned %s\n", rp); +#endif + va_end(args); + free(cmd); + if (pclose(fp) || (strlen(rp) == 0)) { + free(rp); + return NULL; + } + return rp; +} + Index: lib/lib.h =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/lib/lib.h,v retrieving revision 1.32 diff -u -r1.32 lib.h --- lib/lib.h 2001/02/27 09:00:18 1.32 +++ lib/lib.h 2001/03/01 18:15:58 @@ -112,6 +112,7 @@ /* Prototypes */ /* Misc */ int vsystem(const char *, ...); +char *vpipe(const char *, ...); void cleanup(int); char *make_playpen(char *, size_t); char *where_playpen(void); @@ -126,6 +127,7 @@ void str_lowercase(char *); char *basename_of(char *); char *strconcat(char *, char *); +char *get_string(char *, int, FILE *); /* File */ Boolean fexists(char *); Index: lib/str.c =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/lib/str.c,v retrieving revision 1.7 diff -u -r1.7 str.c --- lib/str.c 2000/10/22 09:53:27 1.7 +++ lib/str.c 2001/03/01 18:15:58 @@ -109,3 +109,22 @@ ++str; } } + +char * +get_string(char *str, int max, FILE *fp) +{ + int len; + + if (!str) + return NULL; + str[0] = '\0'; + while (fgets(str, max, fp)) { + len = strlen(str); + while (len && isspace(str[len - 1])) + str[--len] = '\0'; + if (len) + return str; + } + return NULL; +} + --zhXaljGHf11kAtnf-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-ports" in the body of the message