From owner-freebsd-ports Thu Mar 1 8:11:43 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 97FD837B718 for ; Thu, 1 Mar 2001 08:11:26 -0800 (PST) (envelope-from rooneg@isris.pair.com) Received: (qmail 4741 invoked by uid 3130); 1 Mar 2001 16:11:25 -0000 Date: Thu, 1 Mar 2001 11:11:25 -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: <20010301111125.A96679@electricjellyfish.net> References: <20010225161633.C94657@electricjellyfish.net> <200102252125.f1PLPH132145@vic.sabbo.net> <20010225192632.C37487@electricjellyfish.net> <20010225200351.A48200@electricjellyfish.net> <3A99FC4E.B825CB6B@FreeBSD.org> <20010227220553.A75036@electricjellyfish.net> <20010228192345.A11065@electricjellyfish.net> <3A9E500C.4709EB8@FreeBSD.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="OwLcNYc0lM97+oe1" Content-Disposition: inline User-Agent: Mutt/1.2.5i In-Reply-To: <3A9E500C.4709EB8@FreeBSD.org>; from sobomax@FreeBSD.org on Thu, Mar 01, 2001 at 03:35:08PM +0200 Sender: owner-freebsd-ports@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org --OwLcNYc0lM97+oe1 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Thu, Mar 01, 2001 at 03:35:08PM +0200, Maxim Sobolev wrote: > I have several additional comments regarding your patches: > > 1. There are several places in your patches when you use the following: > errx(2, strerror(errno)); > which is wrong from the two points of view: > - you should avoid supplying return value of a function as a format string for > printf()-like function. The following would be more correct: > foo("%s", bar()); > - in this particular case you can use err() function, which automatically expands > errno value into error message and prints it to the stderr, i.e. > err(2, NULL); oops, i see what you mean. fixed now. > 2. Use ordinary malloc(...) instead of calloc(1, ...); initially i was using calloc because it would zero the memory, but in that case it didn't really matter since i was initializing it anyway... fixed. in one place i have left it in however, as it just seems silly to have an extra function call to zero out the memory explicitly when calloc can do it for me. (this is in main.c, line 163) > 3. The following code is wrong, because it allocates 4 times more memory than > required (sizeof(char *) == 4, not 1). > fixed_path = calloc(strlen(cwd) + strlen(current) + 2, sizeof(char *)); oops, don't know how that got past me. fixed. > 4. I suspect that the horrible 10-level fts(3) loop could be greatly simplified by > using matchinstalled(MATCH_ALL, ...) function. Please try to look into that > direction. I just spent a while playing with that, and at first glance it does look like it might work, but MATCH_ALL will only return the names of the packages, where what I'm interested in is the files the package contains. I suppose it might be possible to add another match type to matchinstalled, (MATCH_FILES perhaps) which returns the files, instead of the package names, but it seems like we'd be pushing beyond what 'matchinstalled' is supposed to be doing. if you feel that it's worthwhile though, i can look at doing that. -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. --OwLcNYc0lM97+oe1 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/02/28 23:30:48 @@ -47,12 +47,21 @@ #define SHOW_ORIGIN 0x2000 #define SHOW_CKSUM 0x4000 +struct which_entry { + TAILQ_ENTRY(which_entry) next; + char file[MAXPATHLEN]; + char package[MAXPATHLEN]; + 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 16:09:30 @@ -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, MAXPATHLEN); + 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 16:09:44 @@ -23,14 +23,18 @@ * */ -#include "lib.h" -#include "info.h" - +#include #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,6 +46,9 @@ signal(SIGINT, cleanup); + tmp = getenv(PKG_DBDIR); + if (!tmp) + tmp = DEF_LOG_DIR; /* Overriding action? */ if (CheckPkg) { char buf[FILENAME_MAX]; @@ -52,6 +59,8 @@ 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 +248,165 @@ 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; +} + +static int +fname_cmp(const FTSENT **a, const FTSENT **b) +{ + return strcmp((*a)->fts_name, (*b)->fts_name); +} + +/* 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) +{ + FTS *ftsp; + FTSENT *entp; + char *dir[2]; + struct which_entry *wp; + + 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, MAXPATHLEN); + 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, MAXPATHLEN); + 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, MAXPATHLEN); + + free(tmp); + free(curdir); + } + } + + dir[0] = db_dir; + dir[1] = NULL; + + ftsp = fts_open(dir, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp); + + if (ftsp != NULL) { + while((entp = fts_read(ftsp)) != NULL) { + if (entp->fts_level == 1 && entp->fts_info == FTS_D) { + Package pkg; + PackingList itr; + FILE *fp; + char tmp[FILENAME_MAX]; + char *cwd = NULL; + + sprintf(tmp, "%s/%s", entp->fts_path, CONTENTS_FNAME); + + fp = fopen(tmp, "r"); + if (fp) { + pkg.head = pkg.tail = NULL; + read_plist(&pkg, 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) { + if (cmp_path(wp->file, itr->name, cwd)) { + if (wp->package[0] != '\0') { + warnx("Both %s and %s claim to " + "have installed %s\n", + wp->package, entp->fts_name, + wp->file); + } else { + snprintf(wp->package, + strlen(entp->fts_name), + entp->fts_name); + } + } + } + } + } + } + free_plist(&pkg); + fclose(fp); + } + } + } + } + + TAILQ_FOREACH(wp, which_list, next) { + if (wp->package[0] != '\0') { + 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); + } + fts_close(ftsp); + 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/02/28 23:45:17 @@ -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/02/28 23:45:49 @@ -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/02/28 23:47:19 @@ -60,3 +60,46 @@ 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 00:09: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/02/28 23:49:15 @@ -109,3 +109,21 @@ ++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; +} --OwLcNYc0lM97+oe1-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-ports" in the body of the message