Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 25 Feb 2001 22:34:15 +0200 (EET)
From:      Maxim Sobolev <sobomax@freebsd.org>
To:        ports@freebsd.org
Cc:        jkh@freebsd.org
Subject:   Re: pkg_delete and wildcards/regexs (and some other improvements) [patch]
Message-ID:  <200102252034.f1PKYFV31535@vic.sabbo.net>

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

--%--multipart-mixed-boundary-1.31492.983133255--%
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

> Hi folks,
> 
> With this message I'm attaching patch that brings recent addition of
> wildcards/regexs match in pkg_info(1) into pkg_delete(1) as well. The code is
> almost ready for commit, though I'm planning to add some more error checking
> and evaluating possibility to move matchinstalled() call one level up, into
> main(). Nevrtheless, I would like to hear your comments and suggestions
> regarding proposed change.

(ARGH! Forgot to attach patchset)

With this message I'm attaching ready-to-commit patch, complete with manual
updates, usage() updates etc. Also as a bonus with this patch comes simple
rm(1)-like functionality for pkg_delete(1), which allows one to manually select
packages to be deleted.

Please all interested parties review and comment on attached patches, as I'm
going to commit it tomorrow.
 
Thanks!

-Maxim



--%--multipart-mixed-boundary-1.31492.983133255--%
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Description: ASCII C program text
Content-Disposition: attachment; filename="pkg_delete-regex.patch"

Index: delete/delete.h
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/delete/delete.h,v
retrieving revision 1.5
diff -d -u -r1.5 delete.h
--- delete/delete.h	1999/08/28 01:18:00	1.5
+++ delete/delete.h	2001/02/25 20:20:59
@@ -24,10 +24,12 @@
 #define _INST_DELETE_H_INCLUDE
 
 extern char	*Prefix;
-extern Boolean	NoDeInstall;
 extern Boolean	CleanDirs;
+extern Boolean	Interactive;
+extern Boolean	NoDeInstall;
 extern Boolean	Force;
 extern char	*Directory;
 extern char	*PkgName;
+extern match_t	MatchType;
 
 #endif	/* _INST_DELETE_H_INCLUDE */
Index: delete/main.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/delete/main.c,v
retrieving revision 1.20
diff -d -u -r1.20 main.c
--- delete/main.c	2000/10/22 09:53:25	1.20
+++ delete/main.c	2001/02/25 20:21:01
@@ -30,11 +30,13 @@
 #include "lib.h"
 #include "delete.h"
 
-static char Options[] = "hvDdnfp:";
+static char Options[] = "adDfGhinp:vx";
 
 char	*Prefix		= NULL;
-Boolean	NoDeInstall	= FALSE;
 Boolean	CleanDirs	= FALSE;
+Boolean	Interactive	= FALSE;
+Boolean	NoDeInstall	= FALSE;
+match_t	MatchType	= MATCH_GLOB;
 
 static void usage __P((void));
 
@@ -75,6 +77,22 @@
 	    Verbose = TRUE;
 	    break;
 
+	case 'a':
+	    MatchType = MATCH_ALL;
+	    break;
+
+	case 'G':
+	    MatchType = MATCH_EXACT;
+	    break;
+
+	case 'x':
+	    MatchType = MATCH_REGEX;
+	    break;
+
+	case 'i':
+	    Interactive = TRUE;
+	    break;
+
 	case 'h':
 	case '?':
 	default:
@@ -87,23 +105,26 @@
 
     /* Get all the remaining package names, if any */
     while (*argv) {
-	while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) {
-	    *pkgs_split++ = '\0';
-	    /*
-	     * If character after the '/' is alphanumeric, then we've found the
-	     * package name.  Otherwise we've come across a trailing '/' and
-	     * need to continue our quest.
-	     */
-	    if (isalpha(*pkgs_split)) {
-		*argv = pkgs_split;
-		break;
+	/* Don't try to apply heuristics if arguments are regexs */
+	if (MatchType != MATCH_REGEX)
+	    while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) {
+		*pkgs_split++ = '\0';
+		/*
+		 * If character after the '/' is alphanumeric, then we've found the
+		 * package name.  Otherwise we've come across a trailing '/' and
+		 * need to continue our quest.
+		 */
+		if (isalpha(*pkgs_split) || ((MatchType == MATCH_GLOB) && \
+		    strpbrk(pkgs_split, "*?[]") != NULL)) {
+		    *argv = pkgs_split;
+		    break;
+		}
 	    }
-	}
 	*pkgs++ = *argv++;
     }
 
     /* If no packages, yelp */
-    if (pkgs == start)
+    if (pkgs == start && MatchType != MATCH_ALL)
 	warnx("missing package name(s)"), usage();
     *pkgs = NULL;
     tmp = getenv(PKG_DBDIR) ? getenv(PKG_DBDIR) : DEF_LOG_DIR;
@@ -126,6 +147,8 @@
 static void
 usage()
 {
-    fprintf(stderr, "usage: pkg_delete [-vDdnf] [-p prefix] pkg-name ...\n");
+    fprintf(stderr, "%s\n%s\n",
+	"usage: pkg_delete [-dDfGinvx] [-p prefix] pkg-name ...",
+	"       pkg_delete -a [flags]");
     exit(1);
 }
Index: delete/perform.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/delete/perform.c,v
retrieving revision 1.26
diff -d -u -r1.26 perform.c
--- delete/perform.c	2001/02/21 02:01:10	1.26
+++ delete/perform.c	2001/02/25 20:21:01
@@ -37,10 +37,33 @@
 int
 pkg_perform(char **pkgs)
 {
+    char **matched;
     char *tmp;
     int i, j;
     int err_cnt = 0;
-    int loop_cnt;
+    int loop_cnt, errcode;
+
+    if (MatchType != MATCH_EXACT) {
+	matched = matchinstalled(MatchType, pkgs, &errcode);
+	if (errcode != 0)
+	    return 1;
+	    /* Not reached */
+
+	if (matched != NULL)
+	    pkgs = matched;
+	else switch (MatchType) {
+	    case MATCH_GLOB:
+		break;
+	    case MATCH_ALL:
+		warnx("no packages installed");
+		return 0;
+	    case MATCH_REGEX:
+		warnx("no packages match pattern(s)");
+		return 1;
+	    default:
+		break;
+	}
+    }
 
     for (i = 0; pkgs[i]; i++) {
 	/*
@@ -120,6 +143,19 @@
     if (chdir(LogDir) == FAIL) {
 	warnx("unable to change directory to %s! deinstall failed", LogDir);
 	return 1;
+    }
+
+    if (Interactive == TRUE) {
+	int first, ch;
+
+	(void)fprintf(stderr, "delete %s? ", pkg);
+	(void)fflush(stderr);
+	first = ch = getchar();
+	while (ch != '\n' && ch != EOF)
+	    ch = getchar();
+	if (first != 'y' && first != 'Y')
+	    return 0;
+	    /* Not reached */
     }
 
     if (!isemptyfile(REQUIRED_BY_FNAME)) {
Index: delete/pkg_delete.1
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/delete/pkg_delete.1,v
retrieving revision 1.23
diff -d -u -r1.23 pkg_delete.1
--- delete/pkg_delete.1	2001/02/20 21:57:17	1.23
+++ delete/pkg_delete.1	2001/02/25 20:21:01
@@ -25,9 +25,12 @@
 .Nd a utility for deleting previously installed software package distributions
 .Sh SYNOPSIS
 .Nm
-.Op Fl vDdnf
+.Op Fl dDfGinvx
 .Op Fl p Ar prefix
 .Ar pkg-name ...
+.Nm
+.Fl a
+.Op Ar flags
 .Sh DESCRIPTION
 The
 .Nm
@@ -68,6 +71,12 @@
 .Bl -tag -width indent
 .It Ar pkg-name ...
 The named packages are deinstalled.
+.It Fl a
+Unconditionally delete all currently installed packages.
+.It Fl i
+Request confirmation before attempting to delete each package,
+regardless whether or not the standard input device is a
+terminal.
 .It Fl v
 Turn on verbose output.
 .It Fl D
@@ -94,6 +103,22 @@
 .It Fl f
 Force removal of the package, even if a dependency is recorded or the
 deinstall or require script fails.
+.It Fl G
+Do not try to expand shell glob patterns in the
+.Ar pkg-name
+when selecting packages to be deleted (by default
+.Nm
+automatically expands shell glob patterns in the
+.Ar pkg-name ) .
+.It Fl x
+Treat the
+.Ar pkg-name
+as a regular expression and delete all packages whose names match
+that regular expression.  Multiple regular expressions could be
+provided, in that case
+.Nm
+deletes all packages that match at least one
+regular expression from the list.
 .El
 .Sh TECHNICAL DETAILS
 .Nm
Index: info/info.h
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/info/info.h,v
retrieving revision 1.17
diff -d -u -r1.17 info.h
--- info/info.h	2001/02/08 17:43:59	1.17
+++ info/info.h	2001/02/25 20:21:01
@@ -47,12 +47,6 @@
 #define SHOW_ORIGIN	0x2000
 #define SHOW_CKSUM	0x4000
 
-enum _match_t {
-    MATCH_ALL, MATCH_EXACT, MATCH_GLOB, MATCH_REGEX
-};
-
-typedef enum _match_t match_t;
-
 extern int Flags;
 extern Boolean Quiet;
 extern char *InfoPrefix;
Index: info/perform.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/info/perform.c,v
retrieving revision 1.34
diff -d -u -r1.34 perform.c
--- info/perform.c	2001/02/08 17:44:00	1.34
+++ info/perform.c	2001/02/25 20:21:01
@@ -28,26 +28,20 @@
 
 #include <sys/types.h>
 #include <err.h>
-#include <glob.h>
-#include <fts.h>
-#include <regex.h>
 #include <signal.h>
 
-static int fname_cmp(const FTSENT **, const FTSENT **);
 static int pkg_do(char *);
-static int rexs_match(char **, char *);
 
 int
 pkg_perform(char **pkgs)
 {
-    int i, err_cnt = 0;
+    char **matched;
     char *tmp;
+    int err_cnt = 0;
+    int i, errcode;
 
     signal(SIGINT, cleanup);
 
-    tmp = getenv(PKG_DBDIR);
-    if (!tmp)
-	tmp = DEF_LOG_DIR;
     /* Overriding action? */
     if (CheckPkg) {
 	char buf[FILENAME_MAX];
@@ -57,90 +51,33 @@
 	/* Not reached */
     }
 
-    switch (MatchType) {
-    case MATCH_ALL:
-    case MATCH_REGEX:
-	{
-	    FTS *ftsp;
-	    FTSENT *f;
-	    char *paths[2];
-	    int errcode;
+    if (MatchType != MATCH_EXACT) {
+	matched = matchinstalled(MatchType, pkgs, &errcode);
+	if (errcode != 0)
+	    return 1;
+	    /* Not reached */
 
-	    if (!isdir(tmp))
+	if (matched != NULL)
+	    pkgs = matched;
+	else switch (MatchType) {
+	    case MATCH_GLOB:
+		break;
+	    case MATCH_ALL:
+		warnx("no packages installed");
+		return 0;
+		/* Not reached */
+	    case MATCH_REGEX:
+		warnx("no packages match pattern(s)");
 		return 1;
-	    paths[0] = tmp;
-	    paths[1] = NULL;
-	    ftsp = fts_open(paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT,
-	      fname_cmp);
-	    if (ftsp != NULL) {
-		while ((f = fts_read(ftsp)) != NULL) {
-		    if (f->fts_info == FTS_D && f->fts_level == 1) {
-			fts_set(ftsp, f, FTS_SKIP);
-			if (MatchType == MATCH_REGEX) {
-			    errcode = rexs_match(pkgs, f->fts_name);
-			    if (errcode == -1) {
-				err_cnt += 1;
-				break;
-			    }
-			    else if (errcode == 0)
-				continue;
-			}
-			err_cnt += pkg_do(f->fts_name);
-		    }
-		}
-		fts_close(ftsp);
-	    }
-	}
-	break;
-    case MATCH_GLOB:
-	{
-	    glob_t g;
-	    char *gexpr;
-	    char *cp;
-	    int gflags;
-	    int prev_matchc;
-
-	    gflags = GLOB_ERR;
-	    prev_matchc = 0;
-	    for (i = 0; pkgs[i]; i++) {
-		asprintf(&gexpr, "%s/%s", tmp, pkgs[i]);
-
-		if (glob(gexpr, gflags, NULL, &g) != 0) {
-		    warn("%s: error encountered when matching glob", pkgs[i]);
-		    return 1;
-		}
-
-		/*
-		 * If glob doesn't match try to use pkgs[i] directly - it
-		 * could be name of the tarball.
-		 */
-		if (g.gl_matchc == prev_matchc)
-		    err_cnt += pkg_do(pkgs[i]);
-
-		prev_matchc = g.gl_matchc;
-		gflags |= GLOB_APPEND;
-		free(gexpr);
-	    }
-
-	    for (i = 0; i < g.gl_matchc; i++) {
-		cp = strrchr(g.gl_pathv[i], '/');
-		if (cp == NULL)
-		    cp = g.gl_pathv[i];
-		else
-		    cp++;
-
-		err_cnt += pkg_do(cp);
-	    }
-
-	    globfree(&g);
+		/* Not reached */
+	    default:
+		break;
 	}
-	break;
-    default:
-	for (i = 0; pkgs[i]; i++)
-	    err_cnt += pkg_do(pkgs[i]);
-	break;
     }
 
+    for (i = 0; pkgs[i]; i++)
+	err_cnt += pkg_do(pkgs[i]);
+
     return err_cnt;
 }
 
@@ -299,57 +236,3 @@
 	exit(1);
 }
 
-static int
-fname_cmp(const FTSENT **a, const FTSENT **b)
-{
-    return strcmp((*a)->fts_name, (*b)->fts_name);
-}
-
-/*
- * Returns 1 if specified pkgname matches at least one
- * of the RE from patterns. Otherwise return 0 if no
- * matches were found or -1 if RE engine reported an
- * error (usually invalid syntax).
- */
-static int
-rexs_match(char **patterns, char *pkgname)
-{
-    Boolean matched;
-    char errbuf[128];
-    int i;
-    int errcode;
-    int retval;
-    regex_t rex;
-
-    errcode = 0;
-    retval = 0;
-    matched = FALSE;
-    for (i = 0; patterns[i]; i++) {
-	errcode = regcomp(&rex, patterns[i], REG_BASIC | REG_NOSUB);
-	if (errcode != 0)
-	    break;
-
-	errcode = regexec(&rex, pkgname, 0, NULL, 0);
-	if (errcode == 0) {
-	    matched = TRUE;
-	    retval = 1;
-	    break;
-	}
-	else if (errcode != REG_NOMATCH)
-	    break;
-
-	regfree(&rex);
-	errcode = 0;
-    }
-
-    if (errcode != 0) {
-	regerror(errcode, &rex, errbuf, sizeof(errbuf));
-	warnx("%s: %s", patterns[i], errbuf);
-	retval = -1;
-    }
-
-    if ((errcode != 0) || (matched == TRUE))
-	regfree(&rex);
-
-    return retval;
-}
Index: lib/Makefile
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/lib/Makefile,v
retrieving revision 1.6
diff -d -u -r1.6 Makefile
--- lib/Makefile	1996/06/20 18:33:49	1.6
+++ lib/Makefile	2001/02/25 20:21:02
@@ -1,5 +1,5 @@
 LIB=	install
-SRCS=	file.c msg.c plist.c str.c exec.c global.c pen.c
+SRCS=	file.c msg.c plist.c str.c exec.c global.c pen.c match.c
 CFLAGS+= ${DEBUG}
 NOPROFILE= yes
 NOPIC=	yes
Index: lib/lib.h
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/lib/lib.h,v
retrieving revision 1.31
diff -d -u -r1.31 lib.h
--- lib/lib.h	2000/09/18 07:41:48	1.31
+++ lib/lib.h	2001/02/25 20:21:02
@@ -88,6 +88,11 @@
 };
 typedef enum _plist_t plist_t;
 
+enum _match_t {
+    MATCH_ALL, MATCH_EXACT, MATCH_GLOB, MATCH_REGEX
+};
+typedef enum _match_t match_t;
+
 /* Types */
 typedef unsigned int Boolean;
 
@@ -168,6 +173,9 @@
 
 /* For all */
 int		pkg_perform(char **);
+
+/* Query installed packages */
+char		**matchinstalled(match_t, char **, int *);
 
 /* Externs */
 extern Boolean	Verbose;
Index: lib/match.c
===================================================================
RCS file: match.c
diff -N match.c
--- /dev/null	Sun Feb 25 12:20:25 2001
+++ match.c	Sun Feb 25 12:21:03 2001
@@ -0,0 +1,186 @@
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * Maxim Sobolev
+ * 24 February 2001
+ *
+ * Routines used to query installed packages.
+ *
+ */
+
+#include "lib.h"
+
+#include <err.h>
+#include <fnmatch.h>
+#include <fts.h>
+#include <regex.h>
+
+/*
+ * Simple structure representing argv-like
+ * NULL-terminated list.
+ */
+struct store {
+    int currlen;
+    int used;
+    char **store;
+};
+
+static int rex_match(char *, char *);
+static void storeappend(struct store *, const char *);
+static int fname_cmp(const FTSENT **, const FTSENT **);
+
+char **
+matchinstalled(match_t MatchType, char **patterns, int *retval)
+{
+    int i, matched, errcode;
+    char *tmp;
+    char *paths[2];
+    static struct store *store = NULL;
+    FTS *ftsp;
+    FTSENT *f;
+
+    if (store == NULL) {
+	store = malloc(sizeof *store);
+	store->currlen = 0;
+	store->store = NULL;
+    } else {
+	if (store->store != NULL) {
+	    /* Free previously allocated memory */
+	    for (i = 0; store->store[i] != NULL; i++)
+		free(store->store[i]);
+	}
+    }
+    store->used = 0;
+
+    if (retval != NULL)
+	*retval = 0;
+
+    tmp = getenv(PKG_DBDIR);
+    if (!tmp)
+	tmp = DEF_LOG_DIR;
+    if (!isdir(tmp)) {
+	if (retval != NULL)
+	    *retval = 1;
+	return NULL;
+	/* Not reached */
+    }
+
+    paths[0] = tmp;
+    paths[1] = NULL;
+    ftsp = fts_open(paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp);
+    if (ftsp != NULL) {
+	while ((f = fts_read(ftsp)) != NULL) {
+	    if (f->fts_info == FTS_D && f->fts_level == 1) {
+		fts_set(ftsp, f, FTS_SKIP);
+		if (MatchType == MATCH_ALL) {
+		    storeappend(store, f->fts_name);
+		    continue;
+		}
+		for (i = 0; patterns[i]; i++) {
+		    matched = 0;
+		    switch (MatchType) {
+		    case MATCH_REGEX:
+			errcode = rex_match(patterns[i], f->fts_name);
+			if (errcode == 1) {
+			    storeappend(store, f->fts_name);
+			    matched = 1;
+			} else if (errcode == -1) {
+			    if (retval != NULL)
+				*retval = 1;
+			    return NULL;
+			    /* Not reached */
+			}
+			break;
+		    case MATCH_GLOB:
+			if (fnmatch(patterns[i], f->fts_name, 0) == 0) {
+			    storeappend(store, f->fts_name);
+			    matched = 1;
+			}
+			break;
+		    default:
+			break;
+		    }
+		    if (matched == 1)
+			break;
+		}
+	    }
+	}
+	fts_close(ftsp);
+    }
+
+    if (store->used == 0)
+	return NULL;
+    else
+	return store->store;
+}
+
+/*
+ * Returns 1 if specified pkgname matches RE pattern.
+ * Otherwise returns 0 if doesn't match or -1 if RE
+ * engine reported an error (usually invalid syntax).
+ */
+static int
+rex_match(char *pattern, char *pkgname)
+{
+    char errbuf[128];
+    int errcode;
+    int retval;
+    regex_t rex;
+
+    retval = 0;
+
+    errcode = regcomp(&rex, pattern, REG_BASIC | REG_NOSUB);
+    if (errcode == 0)
+	errcode = regexec(&rex, pkgname, 0, NULL, 0);
+
+    if (errcode == 0) {
+	retval = 1;
+    } else if (errcode != REG_NOMATCH) {
+	regerror(errcode, &rex, errbuf, sizeof(errbuf));
+	warnx("%s: %s", pattern, errbuf);
+	retval = -1;
+    }
+
+    regfree(&rex);
+
+    return retval;
+}
+
+static void
+storeappend(struct store *store, const char *item)
+{
+    char **tmp;
+
+    if (store->used + 2 > store->currlen) {
+	tmp = store->store;
+	store->currlen += 16;
+	store->store = malloc(store->currlen * sizeof(*(store->store)));
+	memcpy(store->store, tmp, store->used * sizeof(*(store->store)));
+	free(tmp);
+    }
+
+    asprintf(&(store->store[store->used]), "%s", item);
+    store->used++;
+    store->store[store->used] = NULL;
+}
+
+static int
+fname_cmp(const FTSENT **a, const FTSENT **b)
+{
+    return strcmp((*a)->fts_name, (*b)->fts_name);
+}

--%--multipart-mixed-boundary-1.31492.983133255--%--

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?200102252034.f1PKYFV31535>