summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorsobomax <sobomax@FreeBSD.org>2001-09-19 08:06:48 +0000
committersobomax <sobomax@FreeBSD.org>2001-09-19 08:06:48 +0000
commit7942a4e1d2c7f9c821cae968af1b156019372d2a (patch)
tree983c446512bc26a2723c915739303dcac0da1570 /usr.sbin
parentde49b782662799d33adbe3450f5c4cbdb697a7f0 (diff)
downloadFreeBSD-src-7942a4e1d2c7f9c821cae968af1b156019372d2a.zip
FreeBSD-src-7942a4e1d2c7f9c821cae968af1b156019372d2a.tar.gz
Various fixes and improvements:
- fix harmless compiler's warnings (unused variables and missed prototype); - before refusing to delete package because "there are packages installed that require this package" check that packages in question is actually installed; - add new `-r' option to pkg_delete(8), which instructs it to delete not only packages specified at command line, but all packages that depend on specified packages as well. MFC after: 2 weeks
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/pkg_install/create/perform.c1
-rw-r--r--usr.sbin/pkg_install/delete/delete.h1
-rw-r--r--usr.sbin/pkg_install/delete/main.c9
-rw-r--r--usr.sbin/pkg_install/delete/perform.c152
-rw-r--r--usr.sbin/pkg_install/delete/pkg_delete.15
-rw-r--r--usr.sbin/pkg_install/info/perform.c2
-rw-r--r--usr.sbin/pkg_install/lib/deps.c89
-rw-r--r--usr.sbin/pkg_install/lib/lib.h8
8 files changed, 187 insertions, 80 deletions
diff --git a/usr.sbin/pkg_install/create/perform.c b/usr.sbin/pkg_install/create/perform.c
index 252a457..30678bb 100644
--- a/usr.sbin/pkg_install/create/perform.c
+++ b/usr.sbin/pkg_install/create/perform.c
@@ -27,6 +27,7 @@ static const char rcsid[] =
#include "create.h"
#include <err.h>
+#include <libgen.h>
#include <signal.h>
#include <sys/syslimits.h>
#include <sys/wait.h>
diff --git a/usr.sbin/pkg_install/delete/delete.h b/usr.sbin/pkg_install/delete/delete.h
index faa2e06..a973642 100644
--- a/usr.sbin/pkg_install/delete/delete.h
+++ b/usr.sbin/pkg_install/delete/delete.h
@@ -28,6 +28,7 @@ extern Boolean CleanDirs;
extern Boolean Interactive;
extern Boolean NoDeInstall;
extern Boolean Force;
+extern Boolean Recursive;
extern char *Directory;
extern char *PkgName;
extern match_t MatchType;
diff --git a/usr.sbin/pkg_install/delete/main.c b/usr.sbin/pkg_install/delete/main.c
index 2dba240..5538838e 100644
--- a/usr.sbin/pkg_install/delete/main.c
+++ b/usr.sbin/pkg_install/delete/main.c
@@ -30,12 +30,13 @@ static const char rcsid[] =
#include "lib.h"
#include "delete.h"
-static char Options[] = "adDfGhinp:vx";
+static char Options[] = "adDfGhinp:rvx";
char *Prefix = NULL;
Boolean CleanDirs = FALSE;
Boolean Interactive = FALSE;
Boolean NoDeInstall = FALSE;
+Boolean Recursive = FALSE;
match_t MatchType = MATCH_GLOB;
static void usage __P((void));
@@ -93,6 +94,10 @@ main(int argc, char **argv)
Interactive = TRUE;
break;
+ case 'r':
+ Recursive = TRUE;
+ break;
+
case 'h':
case '?':
default:
@@ -148,7 +153,7 @@ static void
usage()
{
fprintf(stderr, "%s\n%s\n",
- "usage: pkg_delete [-dDfGinvx] [-p prefix] pkg-name ...",
+ "usage: pkg_delete [-dDfGinrvx] [-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 21815f6..dfe7c91 100644
--- a/usr.sbin/pkg_install/delete/perform.c
+++ b/usr.sbin/pkg_install/delete/perform.c
@@ -36,10 +36,11 @@ static char LogDir[FILENAME_MAX];
int
pkg_perform(char **pkgs)
{
- char **matched;
- int i;
+ char **matched, **rb, **rbtmp;
+ int errcode, i, j;
int err_cnt = 0;
- int errcode;
+ struct reqr_by_entry *rb_entry;
+ struct reqr_by_head *rb_list;
if (MatchType != MATCH_EXACT) {
matched = matchinstalled(MatchType, pkgs, &errcode);
@@ -65,6 +66,40 @@ pkg_perform(char **pkgs)
err_cnt += sortdeps(pkgs);
for (i = 0; pkgs[i]; i++) {
+ if (Recursive == TRUE) {
+ errcode = requiredby(pkgs[i], &rb_list, FALSE, TRUE);
+ if (errcode < 0) {
+ err_cnt++;
+ } else if (errcode > 0) {
+ /*
+ * Copy values from the rb_list queue into argv-like NULL
+ * terminated list because requiredby() uses some static
+ * storage, while pkg_do() below will call this function,
+ * thus blowing our rb_list away.
+ */
+ rbtmp = rb = alloca((errcode + 1) * sizeof(*rb));
+ if (rb == NULL) {
+ warnx("%s(): alloca() failed", __FUNCTION__);
+ err_cnt++;
+ continue;
+ }
+ STAILQ_FOREACH(rb_entry, rb_list, link) {
+ *rbtmp = alloca(strlen(rb_entry->pkgname) + 1);
+ if (*rbtmp == NULL) {
+ warnx("%s(): alloca() failed", __FUNCTION__);
+ err_cnt++;
+ continue;
+ }
+ strcpy(*rbtmp, rb_entry->pkgname);
+ rbtmp++;
+ }
+ *rbtmp = NULL;
+
+ err_cnt += sortdeps(rb);
+ for (j = 0; rb[j]; j++)
+ err_cnt += pkg_do(rb[j]);
+ }
+ }
err_cnt += pkg_do(pkgs[i]);
}
@@ -80,13 +115,14 @@ pkg_do(char *pkg)
FILE *cfile;
char home[FILENAME_MAX];
PackingList p;
- char *tmp;
int len;
/* support for separate pre/post install scripts */
int new_m = 0;
char pre_script[FILENAME_MAX] = DEINSTALL_FNAME;
char post_script[FILENAME_MAX];
char pre_arg[FILENAME_MAX], post_arg[FILENAME_MAX];
+ struct reqr_by_entry *rb_entry;
+ struct reqr_by_head *rb_list;
if (!pkg || !(len = strlen(pkg)))
return 1;
@@ -127,18 +163,14 @@ pkg_do(char *pkg)
/* Not reached */
}
- if (!isemptyfile(REQUIRED_BY_FNAME)) {
- char buf[512];
+ if (requiredby(pkg, &rb_list, FALSE, TRUE) < 0)
+ return 1;
+ if (!STAILQ_EMPTY(rb_list)) {
warnx("package '%s' is required by these other packages\n"
- "and may not be deinstalled%s:",
- pkg, Force ? " (but I'll delete it anyway)" : "" );
- cfile = fopen(REQUIRED_BY_FNAME, "r");
- if (cfile) {
- while (fgets(buf, sizeof(buf), cfile))
- fprintf(stderr, "%s", buf);
- fclose(cfile);
- } else
- warnx("cannot open requirements file '%s'", REQUIRED_BY_FNAME);
+ "and may not be deinstalled%s:",
+ pkg, Force ? " (but I'll delete it anyway)" : "");
+ STAILQ_FOREACH(rb_entry, rb_list, link)
+ fprintf(stderr, "%s\n", rb_entry->pkgname);
if (!Force)
return 1;
}
@@ -283,54 +315,44 @@ cleanup(int sig)
static void
undepend(PackingList p, char *pkgname)
{
- char fname[FILENAME_MAX], ftmp[FILENAME_MAX];
- char fbuf[FILENAME_MAX];
- FILE *fp, *fpwr;
- char *tmp;
- int s;
-
- sprintf(fname, "%s/%s/%s", LOG_DIR, p->name, REQUIRED_BY_FNAME);
- fp = fopen(fname, "r");
- if (fp == NULL) {
- warnx("couldn't open dependency file '%s'", fname);
- return;
- }
- sprintf(ftmp, "%s.XXXXXX", fname);
- s = mkstemp(ftmp);
- if (s == -1) {
- fclose(fp);
- warnx("couldn't open temp file '%s'", ftmp);
- return;
- }
- fpwr = fdopen(s, "w");
- if (fpwr == NULL) {
- close(s);
- fclose(fp);
- warnx("couldn't fdopen temp file '%s'", ftmp);
- remove(ftmp);
- return;
- }
- while (fgets(fbuf, sizeof(fbuf), fp) != NULL) {
- if (fbuf[strlen(fbuf)-1] == '\n')
- fbuf[strlen(fbuf)-1] = '\0';
- if (strcmp(fbuf, pkgname)) /* no match */
- fputs(fbuf, fpwr), putc('\n', fpwr);
- }
- (void) fclose(fp);
- if (fchmod(s, 0644) == FAIL) {
- warnx("error changing permission of temp file '%s'", ftmp);
- fclose(fpwr);
- remove(ftmp);
- return;
- }
- if (fclose(fpwr) == EOF) {
- warnx("error closing temp file '%s'", ftmp);
- remove(ftmp);
- return;
- }
- if (rename(ftmp, fname) == -1)
- warnx("error renaming '%s' to '%s'", ftmp, fname);
- remove(ftmp); /* just in case */
- return;
+ char fname[FILENAME_MAX], ftmp[FILENAME_MAX];
+ FILE *fpwr;
+ int s;
+ struct reqr_by_entry *rb_entry;
+ struct reqr_by_head *rb_list;
+
+
+ if (requiredby(p->name, &rb_list, Verbose, FALSE) <= 0)
+ return;
+ snprintf(fname, sizeof(fname), "%s/%s/%s", LOG_DIR, p->name,
+ REQUIRED_BY_FNAME);
+ snprintf(ftmp, sizeof(ftmp), "%s.XXXXXX", fname);
+ s = mkstemp(ftmp);
+ if (s == -1) {
+ warnx("couldn't open temp file '%s'", ftmp);
+ return;
+ }
+ fpwr = fdopen(s, "w");
+ if (fpwr == NULL) {
+ close(s);
+ warnx("couldn't fdopen temp file '%s'", ftmp);
+ goto cleanexit;
+ }
+ STAILQ_FOREACH(rb_entry, rb_list, link)
+ if (strcmp(rb_entry->pkgname, pkgname)) /* no match */
+ fputs(rb_entry->pkgname, fpwr), putc('\n', fpwr);
+ if (fchmod(s, 0644) == FAIL) {
+ warnx("error changing permission of temp file '%s'", ftmp);
+ fclose(fpwr);
+ goto cleanexit;
+ }
+ if (fclose(fpwr) == EOF) {
+ warnx("error closing temp file '%s'", ftmp);
+ goto cleanexit;
+ }
+ if (rename(ftmp, fname) == -1)
+ warnx("error renaming '%s' to '%s'", ftmp, fname);
+cleanexit:
+ remove(ftmp);
+ return;
}
-
diff --git a/usr.sbin/pkg_install/delete/pkg_delete.1 b/usr.sbin/pkg_install/delete/pkg_delete.1
index c998bb3..947939b 100644
--- a/usr.sbin/pkg_install/delete/pkg_delete.1
+++ b/usr.sbin/pkg_install/delete/pkg_delete.1
@@ -25,7 +25,7 @@
.Nd a utility for deleting previously installed software package distributions
.Sh SYNOPSIS
.Nm
-.Op Fl dDfGinvx
+.Op Fl dDfGinrvx
.Op Fl p Ar prefix
.Ar pkg-name ...
.Nm
@@ -119,6 +119,9 @@ provided, in that case
.Nm
deletes all packages that match at least one
regular expression from the list.
+.It Fl r
+Recursive removal. In addition to specified packages, delete all
+packages that depend on those packages as well.
.El
.Sh TECHNICAL DETAILS
.Nm
diff --git a/usr.sbin/pkg_install/info/perform.c b/usr.sbin/pkg_install/info/perform.c
index a4aa829..5074b1b 100644
--- a/usr.sbin/pkg_install/info/perform.c
+++ b/usr.sbin/pkg_install/info/perform.c
@@ -143,8 +143,6 @@ pkg_do(char *pkg)
}
/* It's not an ininstalled package, try and find it among the installed */
else {
- char *tmp;
-
sprintf(log_dir, "%s/%s", LOG_DIR, pkg);
if (!fexists(log_dir)) {
warnx("can't find package '%s' installed or in a file!", pkg);
diff --git a/usr.sbin/pkg_install/lib/deps.c b/usr.sbin/pkg_install/lib/deps.c
index 802d6c8..cd52209 100644
--- a/usr.sbin/pkg_install/lib/deps.c
+++ b/usr.sbin/pkg_install/lib/deps.c
@@ -82,29 +82,98 @@ sortdeps(char **pkgs)
int
chkifdepends(char *pkgname1, char *pkgname2)
{
+ char pkgdir[FILENAME_MAX];
+ int errcode;
+ struct reqr_by_entry *rb_entry;
+ struct reqr_by_head *rb_list;
+
+ /* Check that pkgname2 is actually installed */
+ snprintf(pkgdir, sizeof(pkgdir), "%s/%s", LOG_DIR, pkgname2);
+ if (!isdir(pkgdir))
+ return 0;
+
+ errcode = requiredby(pkgname2, &rb_list, FALSE, TRUE);
+ if (errcode < 0)
+ return errcode;
+
+ STAILQ_FOREACH(rb_entry, rb_list, link)
+ if (strcmp(rb_entry->pkgname, pkgname1) == 0) /* match */
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Load +REQUIRED_BY file and return a list with names of
+ * packages that require package reffered to by `pkgname'.
+ *
+ * Optionally check that packages listed there are actually
+ * installed and filter out those that don't (filter == TRUE).
+ *
+ * strict argument controls whether the caller want warnings
+ * to be emitted when there are some non-fatal conditions,
+ * i.e. package doesn't have +REQUIRED_BY file or some packages
+ * listed in +REQUIRED_BY don't exist.
+ *
+ * Result returned in the **list, while return value is equal
+ * to the number of entries in the resulting list. Print error
+ * message and return -1 on error.
+ */
+int
+requiredby(const char *pkgname, struct reqr_by_head **list, Boolean strict, Boolean filter)
+{
FILE *fp;
- char fname[FILENAME_MAX];
- char fbuf[FILENAME_MAX];
- char *tmp;
+ char fbuf[FILENAME_MAX], fname[FILENAME_MAX], pkgdir[FILENAME_MAX];
int retval;
+ struct reqr_by_entry *rb_entry;
+ static struct reqr_by_head rb_list = STAILQ_HEAD_INITIALIZER(rb_list);
+
+ *list = &rb_list;
+ /* Deallocate any previously allocated space */
+ while (!STAILQ_EMPTY(&rb_list)) {
+ rb_entry = STAILQ_FIRST(&rb_list);
+ STAILQ_REMOVE_HEAD(&rb_list, link);
+ free(rb_entry);
+ }
- sprintf(fname, "%s/%s/%s", LOG_DIR, pkgname2, REQUIRED_BY_FNAME);
+ snprintf(fname, sizeof(fname), "%s/%s", LOG_DIR, pkgname);
+ if (!isdir(fname)) {
+ if (strict == TRUE)
+ warnx("no such package '%s' installed", pkgname);
+ return -1;
+ }
+
+ snprintf(fname, sizeof(fname), "%s/%s", fname, REQUIRED_BY_FNAME);
fp = fopen(fname, "r");
if (fp == NULL) {
- /* Probably pkgname2 doesn't have any packages that depend on it */
+ /* Probably pkgname doesn't have any packages that depend on it */
+ if (strict == TRUE)
+ warnx("couldn't open dependency file '%s'", fname);
return 0;
}
retval = 0;
while (fgets(fbuf, sizeof(fbuf), fp) != NULL) {
- if (fbuf[strlen(fbuf)-1] == '\n')
- fbuf[strlen(fbuf)-1] = '\0';
- if (strcmp(fbuf, pkgname1) == 0) { /* match */
- retval = 1;
+ if (fbuf[strlen(fbuf) - 1] == '\n')
+ fbuf[strlen(fbuf) - 1] = '\0';
+ snprintf(pkgdir, sizeof(pkgdir), "%s/%s", LOG_DIR, fbuf);
+ if (filter == TRUE && !isdir(pkgdir)) {
+ if (strict == TRUE)
+ warnx("package '%s' is recorded in the '%s' but isn't "
+ "actually installed", fbuf, fname);
+ continue;
+ }
+ retval++;
+ rb_entry = malloc(sizeof(*rb_entry));
+ if (rb_entry == NULL) {
+ warnx("%s(): malloc() failed", __FUNCTION__);
+ retval = -1;
break;
}
+ strlcpy(rb_entry->pkgname, fbuf, sizeof(rb_entry->pkgname));
+ STAILQ_INSERT_TAIL(&rb_list, rb_entry, link);
}
-
fclose(fp);
+
return retval;
}
diff --git a/usr.sbin/pkg_install/lib/lib.h b/usr.sbin/pkg_install/lib/lib.h
index fc41c66..ee709cd 100644
--- a/usr.sbin/pkg_install/lib/lib.h
+++ b/usr.sbin/pkg_install/lib/lib.h
@@ -27,6 +27,7 @@
#include <sys/param.h>
#include <sys/file.h>
#include <sys/stat.h>
+#include <sys/queue.h>
#include <ctype.h>
#include <dirent.h>
#include <stdarg.h>
@@ -111,6 +112,12 @@ struct _pack {
};
typedef struct _pack Package;
+struct reqr_by_entry {
+ STAILQ_ENTRY(reqr_by_entry) link;
+ char pkgname[PATH_MAX];
+};
+STAILQ_HEAD(reqr_by_head, reqr_by_entry);
+
/* Prototypes */
/* Misc */
int vsystem(const char *, ...);
@@ -183,6 +190,7 @@ char **matchinstalled(match_t, char **, int *);
/* Dependencies */
int sortdeps(char **);
int chkifdepends(char *, char *);
+int requiredby(const char *, struct reqr_by_head **, Boolean, Boolean);
/* Externs */
extern Boolean Verbose;
OpenPOWER on IntegriCloud