add -r flag to delete all packages that require the user specified one
This commit is contained in:
parent
b3d5e1889f
commit
ad9eaac8ec
|
@ -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 */
|
||||
|
||||
|
@ -26,9 +26,11 @@
|
|||
#define _INST_DELETE_H_INCLUDE
|
||||
|
||||
extern char *Prefix;
|
||||
extern char *ProgramPath;
|
||||
extern Boolean NoDeInstall;
|
||||
extern Boolean CleanDirs;
|
||||
extern Boolean Force;
|
||||
extern Boolean Recurse;
|
||||
extern char *Directory;
|
||||
extern char *PkgName;
|
||||
|
||||
|
|
|
@ -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>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char *rcsid = "from FreeBSD Id: main.c,v 1.11 1997/10/08 07:46:48 charnier Exp";
|
||||
#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
|
||||
|
||||
|
@ -34,17 +34,19 @@ __RCSID("$NetBSD: main.c,v 1.7 1999/01/19 17:01:59 hubertf Exp $");
|
|||
#include "lib.h"
|
||||
#include "delete.h"
|
||||
|
||||
static char Options[] = "hvDdnfFp:";
|
||||
static char Options[] = "hvDdnfFrp:";
|
||||
|
||||
char *Prefix = NULL;
|
||||
char *ProgramPath = NULL;
|
||||
Boolean NoDeInstall = FALSE;
|
||||
Boolean CleanDirs = FALSE;
|
||||
Boolean File2Pkg = FALSE;
|
||||
Boolean Recurse = FALSE;
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
|
@ -54,6 +56,8 @@ main(int argc, char **argv)
|
|||
int ch, error;
|
||||
char **pkgs, **start;
|
||||
|
||||
ProgramPath = argv[0];
|
||||
|
||||
pkgs = start = argv;
|
||||
while ((ch = getopt(argc, argv, Options)) != -1)
|
||||
switch(ch) {
|
||||
|
@ -86,6 +90,10 @@ main(int argc, char **argv)
|
|||
Verbose = TRUE;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
Recurse = TRUE;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
|
|
|
@ -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>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.15 1997/10/13 15:03:52 jkh Exp";
|
||||
#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
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* 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 "lib.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);
|
||||
|
||||
static char LogDir[FILENAME_MAX];
|
||||
static char linebuf[FILENAME_MAX];
|
||||
static char pkgdir[FILENAME_MAX];
|
||||
|
||||
static package_t Plist;
|
||||
|
||||
rec_del_head_t rdfindq;
|
||||
rec_del_head_t rddelq;
|
||||
|
||||
static void
|
||||
sanity_check(char *pkg)
|
||||
{
|
||||
|
@ -56,6 +106,20 @@ cleanup(int sig)
|
|||
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
|
||||
* about to remove pkg2delname. This function is called from
|
||||
* findmatchingname(), deppkgname is expanded from a (possible) pattern.
|
||||
|
@ -70,8 +134,8 @@ undepend(const char *deppkgname, char *pkg2delname)
|
|||
int s;
|
||||
|
||||
(void) snprintf(fname, sizeof(fname), "%s/%s/%s",
|
||||
(tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR,
|
||||
deppkgname, REQUIRED_BY_FNAME);
|
||||
(tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR,
|
||||
deppkgname, REQUIRED_BY_FNAME);
|
||||
fp = fopen(fname, "r");
|
||||
if (fp == NULL) {
|
||||
warnx("couldn't open dependency file `%s'", fname);
|
||||
|
@ -117,6 +181,228 @@ undepend(const char *deppkgname, char *pkg2delname)
|
|||
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! */
|
||||
static int
|
||||
pkg_do(char *pkg)
|
||||
|
@ -145,19 +431,19 @@ pkg_do(char *pkg)
|
|||
return 1;
|
||||
}
|
||||
if (!isemptyfile(REQUIRED_BY_FNAME)) {
|
||||
char buf[512];
|
||||
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);
|
||||
if (!Force)
|
||||
return 1;
|
||||
if (!Recurse)
|
||||
warnx("package `%s' is required by other packages:", pkg);
|
||||
else if (Verbose)
|
||||
printf("building list of packages that require `%s'"
|
||||
" to deinstall\n", pkg);
|
||||
if (require_find(home, pkg)) {
|
||||
if (!Force || Recurse)
|
||||
return (1);
|
||||
}
|
||||
if (!Recurse)
|
||||
require_print(1);
|
||||
else
|
||||
require_delete(home);
|
||||
}
|
||||
sanity_check(LogDir);
|
||||
cfile = fopen(CONTENTS_FNAME, "r");
|
||||
|
|
|
@ -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
|
||||
.\" 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
|
||||
be set automatically to the installed location by
|
||||
.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
|
||||
Remove empty directories created by file cleanup. By default, only
|
||||
files/directories explicitly listed in a package's contents (either as
|
||||
|
|
Loading…
Reference in New Issue