summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorsobomax <sobomax@FreeBSD.org>2001-02-27 09:00:18 +0000
committersobomax <sobomax@FreeBSD.org>2001-02-27 09:00:18 +0000
commit9ef21beb7a0f2e40841eaec959a3353bb1a0fab1 (patch)
treee3f9b793ac5867f8c854408a2545d3e05f9e0df5 /usr.sbin
parent3dba1d1543776a0f641cde330672fdb902764a4b (diff)
downloadFreeBSD-src-9ef21beb7a0f2e40841eaec959a3353bb1a0fab1.zip
FreeBSD-src-9ef21beb7a0f2e40841eaec959a3353bb1a0fab1.tar.gz
- Merge recently added into pkg_info(1) regex/glob matching functionality into
pkg_delete(1) as well; - add a new `-a' option for pkg_delete(1) to delete all installed packages; - add a new `-i' option for pkg_delete(1) to request simple rm(1)-like interactive confirmation before attempting to delete each package. Silently approved by: jkh, -ports
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/pkg_install/delete/delete.h4
-rw-r--r--usr.sbin/pkg_install/delete/main.c53
-rw-r--r--usr.sbin/pkg_install/delete/perform.c38
-rw-r--r--usr.sbin/pkg_install/delete/pkg_delete.127
-rw-r--r--usr.sbin/pkg_install/info/info.h6
-rw-r--r--usr.sbin/pkg_install/info/perform.c169
-rw-r--r--usr.sbin/pkg_install/lib/Makefile4
-rw-r--r--usr.sbin/pkg_install/lib/lib.h8
-rw-r--r--usr.sbin/pkg_install/lib/match.c197
9 files changed, 338 insertions, 168 deletions
diff --git a/usr.sbin/pkg_install/delete/delete.h b/usr.sbin/pkg_install/delete/delete.h
index cc7a70e..faa2e06 100644
--- a/usr.sbin/pkg_install/delete/delete.h
+++ b/usr.sbin/pkg_install/delete/delete.h
@@ -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 */
diff --git a/usr.sbin/pkg_install/delete/main.c b/usr.sbin/pkg_install/delete/main.c
index fc35c4e..f87af3d 100644
--- a/usr.sbin/pkg_install/delete/main.c
+++ b/usr.sbin/pkg_install/delete/main.c
@@ -30,11 +30,13 @@ static const char rcsid[] =
#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 @@ main(int argc, char **argv)
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 @@ main(int argc, char **argv)
/* 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 @@ main(int argc, char **argv)
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);
}
diff --git a/usr.sbin/pkg_install/delete/perform.c b/usr.sbin/pkg_install/delete/perform.c
index 072b6d5..3453cf8 100644
--- a/usr.sbin/pkg_install/delete/perform.c
+++ b/usr.sbin/pkg_install/delete/perform.c
@@ -37,10 +37,33 @@ static char LogDir[FILENAME_MAX];
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++) {
/*
@@ -122,6 +145,19 @@ pkg_do(char *pkg)
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)) {
char buf[512];
warnx("package `%s' is required by these other packages\n"
diff --git a/usr.sbin/pkg_install/delete/pkg_delete.1 b/usr.sbin/pkg_install/delete/pkg_delete.1
index 7ec63a6..55350bf 100644
--- a/usr.sbin/pkg_install/delete/pkg_delete.1
+++ b/usr.sbin/pkg_install/delete/pkg_delete.1
@@ -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 @@ The following command line options are supported:
.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 @@ the package.
.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
diff --git a/usr.sbin/pkg_install/info/info.h b/usr.sbin/pkg_install/info/info.h
index ba56efb..2356a7e 100644
--- a/usr.sbin/pkg_install/info/info.h
+++ b/usr.sbin/pkg_install/info/info.h
@@ -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;
diff --git a/usr.sbin/pkg_install/info/perform.c b/usr.sbin/pkg_install/info/perform.c
index 80de910..b350be1 100644
--- a/usr.sbin/pkg_install/info/perform.c
+++ b/usr.sbin/pkg_install/info/perform.c
@@ -28,26 +28,20 @@ static const char rcsid[] =
#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 @@ pkg_perform(char **pkgs)
/* Not reached */
}
- switch (MatchType) {
- case MATCH_ALL:
- case MATCH_REGEX:
- {
- FTS *ftsp;
- FTSENT *f;
- char *paths[2];
- int errcode;
-
- if (!isdir(tmp))
+ 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;
+ /* 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 @@ cleanup(int sig)
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;
-}
diff --git a/usr.sbin/pkg_install/lib/Makefile b/usr.sbin/pkg_install/lib/Makefile
index 3876b10..990bfe3 100644
--- a/usr.sbin/pkg_install/lib/Makefile
+++ b/usr.sbin/pkg_install/lib/Makefile
@@ -1,5 +1,7 @@
+# $FreeBSD$
+
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
diff --git a/usr.sbin/pkg_install/lib/lib.h b/usr.sbin/pkg_install/lib/lib.h
index 2584655..fae802d 100644
--- a/usr.sbin/pkg_install/lib/lib.h
+++ b/usr.sbin/pkg_install/lib/lib.h
@@ -88,6 +88,11 @@ enum _plist_t {
};
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;
@@ -169,6 +174,9 @@ Boolean make_preserve_name(char *, int, char *, char *);
/* For all */
int pkg_perform(char **);
+/* Query installed packages */
+char **matchinstalled(match_t, char **, int *);
+
/* Externs */
extern Boolean Verbose;
extern Boolean Fake;
diff --git a/usr.sbin/pkg_install/lib/match.c b/usr.sbin/pkg_install/lib/match.c
new file mode 100644
index 0000000..21495f6
--- /dev/null
+++ b/usr.sbin/pkg_install/lib/match.c
@@ -0,0 +1,197 @@
+#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 **);
+
+/*
+ * Function to query names of installed packages.
+ * MatchType - one of MATCH_ALL, MATCH_REGEX, MATCH_GLOB;
+ * patterns - NULL-terminated list of glob or regex patterns
+ * (could be NULL for MATCH_ALL);
+ * retval - return value (could be NULL if you don't want/need
+ * return value).
+ * Returns NULL-terminated list with matching names.
+ * Names in list returned are dynamically allocated and should
+ * not be altered by the caller.
+ */
+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);
+}
OpenPOWER on IntegriCloud