add -r flag to delete all packages that require the user specified one

This commit is contained in:
chopps 1999-02-26 10:49:30 +00:00
parent b3d5e1889f
commit ad9eaac8ec
4 changed files with 325 additions and 23 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: delete.h,v 1.2 1997/06/05 12:59:35 agc Exp $ */ /* $NetBSD: delete.h,v 1.3 1999/02/26 10:49:30 chopps Exp $ */
/* from FreeBSD Id: delete.h,v 1.4 1997/02/22 16:09:35 peter Exp */ /* from FreeBSD Id: delete.h,v 1.4 1997/02/22 16:09:35 peter Exp */
@ -26,9 +26,11 @@
#define _INST_DELETE_H_INCLUDE #define _INST_DELETE_H_INCLUDE
extern char *Prefix; extern char *Prefix;
extern char *ProgramPath;
extern Boolean NoDeInstall; extern Boolean NoDeInstall;
extern Boolean CleanDirs; extern Boolean CleanDirs;
extern Boolean Force; extern Boolean Force;
extern Boolean Recurse;
extern char *Directory; extern char *Directory;
extern char *PkgName; extern char *PkgName;

View File

@ -1,11 +1,11 @@
/* $NetBSD: main.c,v 1.7 1999/01/19 17:01:59 hubertf Exp $ */ /* $NetBSD: main.c,v 1.8 1999/02/26 10:49:30 chopps Exp $ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static char *rcsid = "from FreeBSD Id: main.c,v 1.11 1997/10/08 07:46:48 charnier Exp"; static char *rcsid = "from FreeBSD Id: main.c,v 1.11 1997/10/08 07:46:48 charnier Exp";
#else #else
__RCSID("$NetBSD: main.c,v 1.7 1999/01/19 17:01:59 hubertf Exp $"); __RCSID("$NetBSD: main.c,v 1.8 1999/02/26 10:49:30 chopps Exp $");
#endif #endif
#endif #endif
@ -34,17 +34,19 @@ __RCSID("$NetBSD: main.c,v 1.7 1999/01/19 17:01:59 hubertf Exp $");
#include "lib.h" #include "lib.h"
#include "delete.h" #include "delete.h"
static char Options[] = "hvDdnfFp:"; static char Options[] = "hvDdnfFrp:";
char *Prefix = NULL; char *Prefix = NULL;
char *ProgramPath = NULL;
Boolean NoDeInstall = FALSE; Boolean NoDeInstall = FALSE;
Boolean CleanDirs = FALSE; Boolean CleanDirs = FALSE;
Boolean File2Pkg = FALSE; Boolean File2Pkg = FALSE;
Boolean Recurse = FALSE;
static void static void
usage(void) usage(void)
{ {
fprintf(stderr, "usage: pkg_delete [-vDdnFf] [-p prefix] pkg-name ...\n"); fprintf(stderr, "usage: pkg_delete [-vDdnFfr] [-p prefix] pkg-name ...\n");
exit(1); exit(1);
} }
@ -54,6 +56,8 @@ main(int argc, char **argv)
int ch, error; int ch, error;
char **pkgs, **start; char **pkgs, **start;
ProgramPath = argv[0];
pkgs = start = argv; pkgs = start = argv;
while ((ch = getopt(argc, argv, Options)) != -1) while ((ch = getopt(argc, argv, Options)) != -1)
switch(ch) { switch(ch) {
@ -86,6 +90,10 @@ main(int argc, char **argv)
Verbose = TRUE; Verbose = TRUE;
break; break;
case 'r':
Recurse = TRUE;
break;
case 'h': case 'h':
case '?': case '?':
default: default:

View File

@ -1,11 +1,11 @@
/* $NetBSD: perform.c,v 1.11 1998/10/12 12:03:26 agc Exp $ */ /* $NetBSD: perform.c,v 1.12 1999/02/26 10:49:30 chopps Exp $ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
#if 0 #if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.15 1997/10/13 15:03:52 jkh Exp"; static const char *rcsid = "from FreeBSD Id: perform.c,v 1.15 1997/10/13 15:03:52 jkh Exp";
#else #else
__RCSID("$NetBSD: perform.c,v 1.11 1998/10/12 12:03:26 agc Exp $"); __RCSID("$NetBSD: perform.c,v 1.12 1999/02/26 10:49:30 chopps Exp $");
#endif #endif
#endif #endif
@ -28,17 +28,67 @@ __RCSID("$NetBSD: perform.c,v 1.11 1998/10/12 12:03:26 agc Exp $");
* This is the main body of the delete module. * This is the main body of the delete module.
* *
*/ */
/*
* Copyright (c) 1999 Christian E. Hopps
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Added the require find and require delete code
*/
#include <sys/queue.h>
#include <err.h> #include <err.h>
#include "lib.h" #include "lib.h"
#include "delete.h" #include "delete.h"
typedef struct _rec_del_t {
TAILQ_ENTRY(_rec_del_t) rd_link;
char *rd_name;
} rec_del_t;
TAILQ_HEAD(_rec_del_head_t, _rec_del_t);
typedef struct _rec_del_head_t rec_del_head_t;
rec_del_t *alloc_rec_del(char *);
rec_del_t *find_on_queue(rec_del_head_t *, char *);
void free_rec_del(rec_del_t *);
int recurse_require_find(rec_del_t *);
int require_find(char *, char *);
int require_delete(char *);
void require_print(int);
int strequal(const char *, const char *);
int undepend(const char *deppkgname, char *pkg2delname); int undepend(const char *deppkgname, char *pkg2delname);
static char LogDir[FILENAME_MAX]; static char LogDir[FILENAME_MAX];
static char linebuf[FILENAME_MAX];
static char pkgdir[FILENAME_MAX];
static package_t Plist; static package_t Plist;
rec_del_head_t rdfindq;
rec_del_head_t rddelq;
static void static void
sanity_check(char *pkg) sanity_check(char *pkg)
{ {
@ -56,6 +106,20 @@ cleanup(int sig)
exit(1); exit(1);
} }
int
strequal(const char *a, const char *b)
{
int al, bl;
al = strlen(a);
bl = strlen(b);
if (al != bl || strcmp(a, b))
return (0);
return (1);
}
/* deppkgname is the pkg from which's +REQUIRED_BY file we are /* deppkgname is the pkg from which's +REQUIRED_BY file we are
* about to remove pkg2delname. This function is called from * about to remove pkg2delname. This function is called from
* findmatchingname(), deppkgname is expanded from a (possible) pattern. * findmatchingname(), deppkgname is expanded from a (possible) pattern.
@ -70,8 +134,8 @@ undepend(const char *deppkgname, char *pkg2delname)
int s; int s;
(void) snprintf(fname, sizeof(fname), "%s/%s/%s", (void) snprintf(fname, sizeof(fname), "%s/%s/%s",
(tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR,
deppkgname, REQUIRED_BY_FNAME); deppkgname, REQUIRED_BY_FNAME);
fp = fopen(fname, "r"); fp = fopen(fname, "r");
if (fp == NULL) { if (fp == NULL) {
warnx("couldn't open dependency file `%s'", fname); warnx("couldn't open dependency file `%s'", fname);
@ -117,6 +181,228 @@ undepend(const char *deppkgname, char *pkg2delname)
return 0; return 0;
} }
/* add a package to the recursive delete list */
rec_del_t *
alloc_rec_del(char *pkgname)
{
rec_del_t *rdp;
if ((rdp = malloc(sizeof(*rdp))) == 0)
err(1, "cannot allocate recursion data");
if ((rdp->rd_name = strdup(pkgname)) == 0)
err(1, "cannot allocate recursion data");
return (rdp);
}
void
free_rec_del(rec_del_t *rdp)
{
free(rdp->rd_name);
free(rdp);
}
rec_del_t *
find_on_queue(rec_del_head_t *qp, char *name)
{
rec_del_t *rdp;
for (rdp = TAILQ_FIRST(qp); rdp; rdp = TAILQ_NEXT(rdp, rd_link))
if (strequal(name, rdp->rd_name))
return (rdp);
return (0);
}
/* delete from 'home' all packages on rec_del_list */
int
require_delete(char *home)
{
rec_del_t *rdp;
int rv, fail;
char *tmp;
(void)snprintf(pkgdir, sizeof(pkgdir), "%s",
(tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR);
/* walk list of things to delete */
fail = 0;
rdp = TAILQ_FIRST(&rddelq);
for (; rdp; rdp = TAILQ_NEXT(rdp, rd_link)) {
/* go to the db dir */
if (chdir(pkgdir) == FAIL) {
warnx("unable to change directory to %s! deinstall failed",
pkgdir);
fail = 1;
break;
}
/* look to see if package was already deleted */
if (!fexists(rdp->rd_name)) {
warnx("%s appears to have been deleted", rdp->rd_name);
continue;
}
/* return home for execution of command */
if (chdir(home) == FAIL) {
warnx("unable to change directory to %s! deinstall failed", home);
fail = 1;
break;
}
if (Verbose)
printf("deinstalling %s\n", rdp->rd_name);
/* delete the package */
if (Fake)
rv = 0;
else
rv = vsystem("%s %s %s %s %s %s %s %s %s", ProgramPath,
Prefix ? "-p" : "",
Prefix ? Prefix : "",
Verbose ? "-v" : "",
Force ? "-f" : "",
NoDeInstall ? "-D" : "",
CleanDirs ? "-d" : "",
Fake ? "-n" : "",
rdp->rd_name);
/* check for delete failure */
if (rv) {
fail = 1;
warnx("had problem removing %s%s", rdp->rd_name,
Force ? ", continuing" : "");
if (!Force)
break;
}
}
/* cleanup list */
while ((rdp = TAILQ_FIRST(&rddelq))) {
TAILQ_REMOVE(&rddelq, rdp, rd_link);
free_rec_del(rdp);
}
/* return to the log dir */
if (chdir(LogDir) == FAIL) {
warnx("unable to change directory to %s! deinstall failed", LogDir);
fail = 1;
}
return (fail);
}
/* recursively find all packages */
int
recurse_require_find(rec_del_t *thisrdp)
{
rec_del_head_t reqq;
rec_del_t *rdp;
FILE *cfile;
char *nl, *tmp;
/* see if we are on the find queue -- ciruclar dependency */
if ((rdp = find_on_queue(&rdfindq, rdp->rd_name))) {
warnx("circular dependency found for pkg %s", rdp->rd_name);
return (1);
}
TAILQ_INIT(&reqq);
(void)snprintf(pkgdir, sizeof(pkgdir), "%s/%s",
(tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, thisrdp->rd_name);
/* change to package's dir */
if (chdir(pkgdir) == FAIL) {
warnx("unable to change directory to %s! deinstall failed", pkgdir);
return (1);
}
/* terminate recursion if no required by's */
if (isemptyfile(REQUIRED_BY_FNAME))
return (0);
/* get packages that ditectly require us */
cfile = fopen(REQUIRED_BY_FNAME, "r");
if (!cfile) {
warnx("cannot open requirements file `%s'", REQUIRED_BY_FNAME);
return (1);
}
while (fgets(linebuf, sizeof(linebuf), cfile)) {
if ((nl = strrchr(linebuf, '\n')))
*nl = 0;
rdp = alloc_rec_del(linebuf);
TAILQ_INSERT_TAIL(&reqq, rdp, rd_link);
}
fclose(cfile);
/* put ourselves on the top of the find queue */
TAILQ_INSERT_HEAD(&rdfindq, thisrdp, rd_link);
while ((rdp = TAILQ_FIRST(&reqq))) {
/* remove a direct req from our queue */
TAILQ_REMOVE(&reqq, rdp, rd_link);
/* find direct required requires */
if (recurse_require_find(rdp))
goto fail;
/*
* all requires taken care of, add to tail of delete queue
* if not already there
*/
if (find_on_queue(&rddelq, rdp->rd_name))
free_rec_del(rdp);
else
TAILQ_INSERT_TAIL(&rddelq, rdp, rd_link);
}
/* take ourselves off the find queue */
TAILQ_REMOVE(&rdfindq, thisrdp, rd_link);
return (0);
fail:
while ((rdp = TAILQ_FIRST(&reqq))) {
TAILQ_REMOVE(&reqq, rdp, rd_link);
free_rec_del(rdp);
}
return (1);
}
int
require_find(char *home, char *pkg)
{
rec_del_t *rdp;
int rv;
TAILQ_INIT(&rdfindq);
TAILQ_INIT(&rddelq);
rdp = alloc_rec_del(pkg);
rv = recurse_require_find(rdp);
free_rec_del(rdp);
return (rv);
}
void
require_print(int del)
{
rec_del_t *rdp;
/* print all but last -- deleting if requested */
if (del) {
while ((rdp = TAILQ_FIRST(&rddelq))) {
TAILQ_REMOVE(&rddelq, rdp, rd_link);
fprintf(stderr, "\t%s\n", rdp->rd_name);
free_rec_del(rdp);
}
} else {
for (rdp = TAILQ_FIRST(&rddelq); rdp; rdp = TAILQ_NEXT(rdp, rd_link))
fprintf(stderr, "\t%s\n", rdp->rd_name);
}
}
/* This is seriously ugly code following. Written very fast! */ /* This is seriously ugly code following. Written very fast! */
static int static int
pkg_do(char *pkg) pkg_do(char *pkg)
@ -145,19 +431,19 @@ pkg_do(char *pkg)
return 1; return 1;
} }
if (!isemptyfile(REQUIRED_BY_FNAME)) { if (!isemptyfile(REQUIRED_BY_FNAME)) {
char buf[512]; if (!Recurse)
warnx("package `%s' is required by these other packages\n" warnx("package `%s' is required by other packages:", pkg);
"and may not be deinstalled%s:", else if (Verbose)
pkg, Force ? " (but I'll delete it anyway)" : "" ); printf("building list of packages that require `%s'"
cfile = fopen(REQUIRED_BY_FNAME, "r"); " to deinstall\n", pkg);
if (cfile) { if (require_find(home, pkg)) {
while (fgets(buf, sizeof(buf), cfile)) if (!Force || Recurse)
fprintf(stderr, "%s", buf); return (1);
fclose(cfile); }
} else if (!Recurse)
warnx("cannot open requirements file `%s'", REQUIRED_BY_FNAME); require_print(1);
if (!Force) else
return 1; require_delete(home);
} }
sanity_check(LogDir); sanity_check(LogDir);
cfile = fopen(CONTENTS_FNAME, "r"); cfile = fopen(CONTENTS_FNAME, "r");

View File

@ -1,4 +1,4 @@
.\" $NetBSD: pkg_delete.1,v 1.6 1999/01/19 17:02:00 hubertf Exp $ .\" $NetBSD: pkg_delete.1,v 1.7 1999/02/26 10:49:30 chopps Exp $
.\" .\"
.\" FreeBSD install - a package for the installation and maintainance .\" FreeBSD install - a package for the installation and maintainance
.\" of non-core utilities. .\" of non-core utilities.
@ -86,6 +86,12 @@ as the directory in which to delete files from any installed packages
which do not explicitly set theirs. For most packages, the prefix will which do not explicitly set theirs. For most packages, the prefix will
be set automatically to the installed location by be set automatically to the installed location by
.Xr pkg_add 1 . .Xr pkg_add 1 .
.It Fl r
.Nm Pkg_delete
first builds a list of all packages that require (directly and indirectly)
the one being deleted. It then deletes these packages using
.Nm pkg_delete
with the given options before deleting the user specified package.
.It Fl d .It Fl d
Remove empty directories created by file cleanup. By default, only Remove empty directories created by file cleanup. By default, only
files/directories explicitly listed in a package's contents (either as files/directories explicitly listed in a package's contents (either as