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
This commit is contained in:
sobomax 2001-09-19 08:06:48 +00:00
parent de49b78266
commit 7942a4e1d2
8 changed files with 188 additions and 81 deletions

View File

@ -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>

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
char fname[FILENAME_MAX], ftmp[FILENAME_MAX];
FILE *fpwr;
int s;
struct reqr_by_entry *rb_entry;
struct reqr_by_head *rb_list;
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;
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;
}

View File

@ -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

View File

@ -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);

View File

@ -82,29 +82,98 @@ sortdeps(char **pkgs)
int
chkifdepends(char *pkgname1, char *pkgname2)
{
FILE *fp;
char fname[FILENAME_MAX];
char fbuf[FILENAME_MAX];
char *tmp;
int retval;
char pkgdir[FILENAME_MAX];
int errcode;
struct reqr_by_entry *rb_entry;
struct reqr_by_head *rb_list;
sprintf(fname, "%s/%s/%s", LOG_DIR, pkgname2, REQUIRED_BY_FNAME);
/* 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 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);
}
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;
}

View File

@ -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;