Date: Sun, 25 Feb 2001 00:16:24 -0500 From: Garrett Rooney <rooneg@electricjellyfish.net> To: ports@freebsd.org, jhk@freebsd.org, sobomax@freebsd.org, gad@freebsd.org Subject: [patch] which package functionality for pkg_info Message-ID: <20010225001624.A41801@electricjellyfish.net>
next in thread | raw e-mail | index | archive | help
--envbJBWh7q8WU6mo Content-Type: text/plain; charset=us-ascii Content-Disposition: inline a few days ago, i got frustrated with how much of a pain it was to determine what package a given file on my system came from. rather than simply using the old 'grep /var/db/pkg/*/+CONTENTS' method, i wrote a script to do some better searching, and then after a little inspection of the pkg_info code, i came up with a patch adding this functionality to pkg_info. the patch (attatched, and available a http://electricjellyfish.net/garrett/code/pkg_info.patch) adds a -w flag, which takes as its argument a path (either absolute or relative) to a file on the system. before anyone asks, -w was chosen because it isn't in use yet, and because the command tells you 'which package' the file came from. i would very much like this to be added to the base system in some manner, as i have often had people ask me how to get this information, but i've never actually had someone point out a good (one line) way to do it well. some ideas for future extension that i and others have come up with include better integration with the rest of the options of pkg_info (have the package that is found become the target of any other flags on the command line perhaps), making the code smarter about symbolic links (perhaps trying both the target file and the link), and an option to md5 checksum the file so as to determine if it has changed since it has been installed. while all of these are interesting extensions, the patch as it stands seems useful to me, and i felt it could be useful to others as it is. i would welcome any comments, both on the code itself, and on how a feature like this should operate. -- 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. --envbJBWh7q8WU6mo Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="pkg_info.patch" Index: info.h =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/info/info.h,v retrieving revision 1.17 diff -u -r1.17 info.h --- info.h 2001/02/08 17:43:59 1.17 +++ info.h 2001/02/23 22:29:41 @@ -1,4 +1,4 @@ -/* $FreeBSD$ */ +/* $FreeBSD: src/usr.sbin/pkg_install/info/info.h,v 1.17 2001/02/08 17:43:59 sobomax Exp $ */ /* * FreeBSD install - a package for the installation and maintainance @@ -58,6 +58,7 @@ extern char *InfoPrefix; extern char PlayPen[]; extern char *CheckPkg; +extern char *CheckFile; extern match_t MatchType; extern void show_file(char *, char *); Index: main.c =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/info/main.c,v retrieving revision 1.29 diff -u -r1.29 main.c --- main.c 2001/02/08 17:44:00 1.29 +++ main.c 2001/02/24 22:19:26 @@ -25,10 +25,10 @@ #ifndef lint static const char rcsid[] = - "$FreeBSD$"; + "$FreeBSD: src/usr.sbin/pkg_install/info/main.c,v 1.29 2001/02/08 17:44:00 sobomax Exp $"; #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 +36,7 @@ char *InfoPrefix = ""; char PlayPen[FILENAME_MAX]; char *CheckPkg = NULL; +char *CheckFile = NULL; static void usage __P((void)); @@ -148,6 +149,10 @@ CheckPkg = optarg; break; + case 'w': + CheckFile = optarg; + break; + case 'h': case '?': default: @@ -185,7 +190,7 @@ } /* If no packages, yelp */ - if (pkgs == start && MatchType != MATCH_ALL && !CheckPkg) + if (pkgs == start && MatchType != MATCH_ALL && !CheckPkg && !CheckFile) warnx("missing package name(s)"), usage(); *pkgs = NULL; return pkg_perform(start); @@ -196,7 +201,7 @@ { fprintf(stderr, "%s\n%s\n%s\n", "usage: pkg_info [-cdDfiIkLmopqrRsv] [-e package] [-l prefix]", - " [-t template] [pkg-name ...]", + " [-t template] [-w filename] [pkg-name ...]", " pkg_info -a [flags]"); exit(1); } Index: perform.c =================================================================== RCS file: /usr/local/cvs/src/usr.sbin/pkg_install/info/perform.c,v retrieving revision 1.34 diff -u -r1.34 perform.c --- perform.c 2001/02/08 17:44:00 1.34 +++ perform.c 2001/02/25 05:08:19 @@ -1,6 +1,6 @@ #ifndef lint static const char rcsid[] = - "$FreeBSD$"; + "$FreeBSD: src/usr.sbin/pkg_install/info/perform.c,v 1.34 2001/02/08 17:44:00 sobomax Exp $"; #endif /* @@ -27,15 +27,23 @@ #include "info.h" #include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <errno.h> #include <err.h> #include <glob.h> #include <fts.h> #include <regex.h> #include <signal.h> +char resolved_path[MAXPATHLEN]; + static int fname_cmp(const FTSENT **, const FTSENT **); static int pkg_do(char *); static int rexs_match(char **, char *); +static int find_pkg(char *, char *); +static int cmp_path(const char *, const char *, const char *); int pkg_perform(char **pkgs) @@ -55,6 +63,8 @@ snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg); return abs(access(buf, R_OK)); /* Not reached */ + } else if (CheckFile) { + return find_pkg(tmp, CheckFile); } switch (MatchType) { @@ -352,4 +362,116 @@ regfree(&rex); return retval; +} + +/* comparison to see if two paths we're on matches the one we're looking for. */ +static int +cmp_path(const char *target, const char *current, const char *cwd) { + + char *fixed_path; + char *temp; + char *itr1; + char *itr2; + + temp = malloc(strlen(cwd) + strlen(current) + 2); + fixed_path = malloc(strlen(cwd) + strlen(current) + 2); + if (temp == NULL || fixed_path == NULL) { + fprintf(stderr, "error, out of memory\n"); + exit(2); + } + + bzero(temp, strlen(cwd) + strlen(current) + 2); + bzero(fixed_path, strlen(cwd) + strlen(current) + 2); + strncpy(temp, cwd, strlen(cwd)); + strncat(temp, "/", 1); + strncat(temp, current, strlen(current)); + + /* 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++; + } + free(temp); + + if (!strncmp(target, fixed_path, strlen(target))) { + free(fixed_path); + return 1; + } else { + free(fixed_path); + return 0; + } +} + +/* look through package dbs in db_dir and find which package installed file */ +static int +find_pkg(char *db_dir, char *file) +{ + FTS *ftsp; + FTSENT *entp; + char *abs_file; + char *dir[2]; + struct stat st; + + abs_file = realpath(file, resolved_path); + if (abs_file == NULL) { + fprintf(stderr, "error: %s\n", strerror(errno)); + exit(2); + } + + if (stat(abs_file, &st) == -1) { + fprintf(stderr, "error: %s\n", strerror(errno)); + exit(2); + } + + 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 buf[FILENAME_MAX]; + char *cwd = NULL; + + bzero(buf, FILENAME_MAX); + strncpy(buf, entp->fts_path, strlen(entp->fts_path)); + strncat(buf, "/", 1); + strncat(buf, CONTENTS_FNAME, strlen(CONTENTS_FNAME)); + + fp = fopen(buf, "r"); + if (fp) { + 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) { + if (cmp_path(abs_file, itr->name, cwd)) { + fprintf(stdout, + "%s is from package %s\n", + CheckFile, + entp->fts_name); + free_plist(&pkg); + fclose(fp); + fts_close(ftsp); + return 1; + } + } + } + free_plist(&pkg); + fclose(fp); + } + } + } + } + fts_close(ftsp); + return 0; } --envbJBWh7q8WU6mo-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-ports" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010225001624.A41801>