Skip site navigation (1)Skip section navigation (2)
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>