Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 1 Mar 2001 13:30:20 -0500
From:      Garrett Rooney <rooneg@electricjellyfish.net>
To:        Maxim Sobolev <sobomax@FreeBSD.org>
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>
In-Reply-To: <3A9E8D0C.A24FD064@FreeBSD.org>; from sobomax@FreeBSD.org on Thu, Mar 01, 2001 at 07:55:24PM %2B0200
References:  <3A9E8D0C.A24FD064@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--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 <sys/queue.h>
 #include <err.h>
+
 #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 <sys/types.h>
 #include <err.h>
 #include <signal.h>
+#include <sys/queue.h>
 
+#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 <err.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/queue.h>
 #include <md5.h>
+
+#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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010301133020.A23453>