Wed Feb 25 16:29:08 2009 UTC ()
pkg_install-20090225:
Rewrite pkg_delete to expand the list of packages to delete first and
reorder it if necessary. It will bail out if it knows in advance that it
can't remove a package. It will also fail for errors while removing one
package, unless forced. Add an option to remove automatically installed
packages that are no longer used.

The pkgviews support is kept, but untested. The error handling for
pkgviews most of all is as weak as before.

Basic review from hubertf@, man page changes by bad@.


(joerg)
diff -r1.12 -r1.13 pkgsrc/pkgtools/pkg_install/files/delete/Makefile.in
diff -r1.6 -r0 pkgsrc/pkgtools/pkg_install/files/delete/delete.h
diff -r1.22 -r0 pkgsrc/pkgtools/pkg_install/files/delete/main.c
diff -r1.26 -r0 pkgsrc/pkgtools/pkg_install/files/delete/perform.c
diff -r1.17 -r1.18 pkgsrc/pkgtools/pkg_install/files/delete/pkg_delete.1
diff -r0 -r1.1 pkgsrc/pkgtools/pkg_install/files/delete/pkg_delete.c
diff -r1.18 -r1.19 pkgsrc/pkgtools/pkg_install/files/delete/pkg_delete.cat1
diff -r1.112 -r1.113 pkgsrc/pkgtools/pkg_install/files/lib/version.h

cvs diff -r1.12 -r1.13 pkgsrc/pkgtools/pkg_install/files/delete/Makefile.in (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/delete/Makefile.in 2008/03/10 12:14:32 1.12
+++ pkgsrc/pkgtools/pkg_install/files/delete/Makefile.in 2009/02/25 16:29:08 1.13
@@ -1,39 +1,39 @@ @@ -1,39 +1,39 @@
1# $NetBSD: Makefile.in,v 1.12 2008/03/10 12:14:32 wiz Exp $ 1# $NetBSD: Makefile.in,v 1.13 2009/02/25 16:29:08 joerg Exp $
2 2
3srcdir= @srcdir@ 3srcdir= @srcdir@
4 4
5prefix= @prefix@ 5prefix= @prefix@
6exec_prefix= @exec_prefix@ 6exec_prefix= @exec_prefix@
7sbindir= @sbindir@ 7sbindir= @sbindir@
8mandir= @mandir@ 8mandir= @mandir@
9datarootdir= @datarootdir@ 9datarootdir= @datarootdir@
10 10
11man1dir= $(mandir)/man1 11man1dir= $(mandir)/man1
12cat1dir= $(mandir)/cat1 12cat1dir= $(mandir)/cat1
13 13
14CC= @CC@ 14CC= @CC@
15CCLD= $(CC) 15CCLD= $(CC)
16LIBS= -linstall @LIBS@ 16LIBS= -linstall @LIBS@
17CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib 17CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib -DBINDIR=\"$(sbindir)\"
18DEFS= @DEFS@ 18DEFS= @DEFS@
19CFLAGS= @CFLAGS@ 19CFLAGS= @CFLAGS@
20LDFLAGS= @LDFLAGS@ -L../lib 20LDFLAGS= @LDFLAGS@ -L../lib
21 21
22INSTALL= @INSTALL@ 22INSTALL= @INSTALL@
23 23
24PROG= pkg_delete 24PROG= pkg_delete
25 25
26OBJS= main.o perform.o 26OBJS= pkg_delete.o
27 27
28all: $(PROG) 28all: $(PROG)
29 29
30.c.o: 30.c.o:
31 $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $< 31 $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $<
32 32
33$(PROG): $(OBJS) 33$(PROG): $(OBJS)
34 $(CCLD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) 34 $(CCLD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
35 35
36clean: 36clean:
37 rm -f $(OBJS) $(PROG) 37 rm -f $(OBJS) $(PROG)
38 38
39install: 39install:

File Deleted: pkgsrc/pkgtools/pkg_install/files/delete/Attic/delete.h

File Deleted: pkgsrc/pkgtools/pkg_install/files/delete/Attic/main.c

File Deleted: pkgsrc/pkgtools/pkg_install/files/delete/Attic/perform.c

cvs diff -r1.17 -r1.18 pkgsrc/pkgtools/pkg_install/files/delete/pkg_delete.1 (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/delete/pkg_delete.1 2009/02/02 12:35:01 1.17
+++ pkgsrc/pkgtools/pkg_install/files/delete/pkg_delete.1 2009/02/25 16:29:08 1.18
@@ -1,56 +1,68 @@ @@ -1,56 +1,68 @@
1.\" $NetBSD: pkg_delete.1,v 1.17 2009/02/02 12:35:01 joerg Exp $ 1.\" $NetBSD: pkg_delete.1,v 1.18 2009/02/25 16:29:08 joerg Exp $
2.\" 2.\"
3.\" FreeBSD install - a package for the installation and maintenance 3.\" FreeBSD install - a package for the installation and maintenance
4.\" of non-core utilities. 4.\" of non-core utilities.
5.\" 5.\"
6.\" Redistribution and use in source and binary forms, with or without 6.\" Redistribution and use in source and binary forms, with or without
7.\" modification, are permitted provided that the following conditions 7.\" modification, are permitted provided that the following conditions
8.\" are met: 8.\" are met:
9.\" 1. Redistributions of source code must retain the above copyright 9.\" 1. Redistributions of source code must retain the above copyright
10.\" notice, this list of conditions and the following disclaimer. 10.\" notice, this list of conditions and the following disclaimer.
11.\" 2. Redistributions in binary form must reproduce the above copyright 11.\" 2. Redistributions in binary form must reproduce the above copyright
12.\" notice, this list of conditions and the following disclaimer in the 12.\" notice, this list of conditions and the following disclaimer in the
13.\" documentation and/or other materials provided with the distribution. 13.\" documentation and/or other materials provided with the distribution.
14.\" 14.\"
15.\" Jordan K. Hubbard 15.\" Jordan K. Hubbard
16.\" 16.\"
17.\" 17.\"
18.\" from FreeBSD: @(#)pkg_delete.1 18.\" from FreeBSD: @(#)pkg_delete.1
19.\" 19.\"
20.Dd July 30, 2008 20.Dd July 30, 2008
21.Dt PKG_DELETE 1 21.Dt PKG_DELETE 1
22.Os 22.Os
23.Sh NAME 23.Sh NAME
24.Nm pkg_delete 24.Nm pkg_delete
25.Nd a utility for deleting previously installed software package distributions 25.Nd a utility for deleting previously installed software package distributions
26.Sh SYNOPSIS 26.Sh SYNOPSIS
27.Nm 27.Nm
28.Op Fl DdFfNnORrVv 28.Op Fl ADdFfNnORrVv
29.Bk -words 29.Bk -words
30.Op Fl K Ar pkg_dbdir 30.Op Fl K Ar pkg_dbdir
31.Ek 31.Ek
32.Bk -words 32.Bk -words
33.Op Fl P Ar destdir 33.Op Fl P Ar destdir
34.Op Fl p Ar prefix 34.Op Fl p Ar prefix
35.Ek 35.Ek
36.Ar pkg-name ... 36.Ar pkg-name ...
37.Sh DESCRIPTION 37.Sh DESCRIPTION
38The 38The
39.Nm 39.Nm
40command is used to delete packages that have been previously installed 40command is used to delete packages that have been previously installed
41with the 41with the
42.Xr pkg_add 1 42.Xr pkg_add 1
43command. 43command.
 44The given packages are sorted, so that the dependencies of a package
 45are deleted after the package.
 46Before any action is executed,
 47.Nm
 48checks for packages that are marked as
 49.Cm preserved
 50or have depending packages left.
 51Unless the
 52.Fl f
 53flag is given,
 54.Nm
 55stops on the first error.
44.Sh WARNING 56.Sh WARNING
45.Bf -emphasis 57.Bf -emphasis
46Since the 58Since the
47.Nm 59.Nm
48command may execute scripts or programs provided by a package file, 60command may execute scripts or programs provided by a package file,
49your system may be susceptible to 61your system may be susceptible to
50.Dq Trojan horses 62.Dq Trojan horses
51or other subtle 63or other subtle
52attacks from miscreants who create dangerous package files. 64attacks from miscreants who create dangerous package files.
53.Pp 65.Pp
54You are advised to verify the competence and identity of those who 66You are advised to verify the competence and identity of those who
55provide installable package files. 67provide installable package files.
56For extra protection, examine all the package control files in the 68For extra protection, examine all the package control files in the
@@ -79,26 +91,32 @@ command to examine the installed package @@ -79,26 +91,32 @@ command to examine the installed package
79The following command line options are supported: 91The following command line options are supported:
80.Bl -tag -width indent 92.Bl -tag -width indent
81.It Ar pkg-name ... 93.It Ar pkg-name ...
82The named packages are deinstalled, wildcards can be used, see 94The named packages are deinstalled, wildcards can be used, see
83.Xr pkg_info 1 . 95.Xr pkg_info 1 .
84If no version is given, the one currently installed 96If no version is given, the one currently installed
85will be removed. 97will be removed.
86If the 98If the
87.Fl F 99.Fl F
88flag is given, one or more (absolute) filenames may be specified and 100flag is given, one or more (absolute) filenames may be specified and
89the Package Database will be consulted for the package to which the 101the Package Database will be consulted for the package to which the
90given file belongs. 102given file belongs.
91These packages are then deinstalled. 103These packages are then deinstalled.
 104.It Fl A
 105Recursively remove all automatically installed packages that were needed
 106by the given packages and are no longer required.
 107See also the
 108.Fl R
 109flag.
92.It Fl D 110.It Fl D
93If a deinstallation script exists for a given package, do not execute it. 111If a deinstallation script exists for a given package, do not execute it.
94.It Fl d 112.It Fl d
95Remove empty directories created by file cleanup. 113Remove empty directories created by file cleanup.
96By default, only files/directories explicitly listed in a package's 114By default, only files/directories explicitly listed in a package's
97contents (either as normal files/directories or with the 115contents (either as normal files/directories or with the
98.Cm @dirrm 116.Cm @dirrm
99directive) will be removed at deinstallation time. 117directive) will be removed at deinstallation time.
100This option tells 118This option tells
101.Nm 119.Nm
102to also remove any directories that were emptied as a result of removing 120to also remove any directories that were emptied as a result of removing
103the package. 121the package.
104.It Fl F 122.It Fl F
@@ -138,44 +156,33 @@ touch the package or its files itself. @@ -138,44 +156,33 @@ touch the package or its files itself.
138Prefix all file and directory names with 156Prefix all file and directory names with
139.Ar destdir . 157.Ar destdir .
140For packages without install scripts this has the same behavior as 158For packages without install scripts this has the same behavior as
141using chroot. 159using chroot.
142.It Fl p Ar prefix 160.It Fl p Ar prefix
143Set 161Set
144.Ar prefix 162.Ar prefix
145as the directory in which to delete files from any installed packages 163as the directory in which to delete files from any installed packages
146which do not explicitly set theirs. 164which do not explicitly set theirs.
147For most packages, the prefix will 165For most packages, the prefix will
148be set automatically to the installed location by 166be set automatically to the installed location by
149.Xr pkg_add 1 . 167.Xr pkg_add 1 .
150.It Fl R 168.It Fl R
151This option triggers a recursive delete of the given package and any 169Recursively remove all packages that were needed by the given packages
152packages it depends on, unless some other package still needs a 170and that have no other dependencies left.
153dependent package. 171This option overrides the
154This 172.Fl A
155.Fl R 173flag.
156option can be used to clean up by deleting a package and all its 
157then-unneeded dependent packages. 
158.It Fl r 174.It Fl r
159.Nm 175Recursively remove all packages that require one of the packages given.
160first builds a list of all packages that require (directly and indirectly) 
161the one being deleted. 
162It then deletes these packages using 
163.Nm 
164with the given options before deleting the user specified package. 
165This 
166.Fl r 
167option can be used to recursively delete a package and all of the 
168packages which depend on that package. 
169.It Fl V 176.It Fl V
170Print version number and exit. 177Print version number and exit.
171.It Fl v 178.It Fl v
172Turn on verbose output. 179Turn on verbose output.
173.El 180.El
174.Sh TECHNICAL DETAILS 181.Sh TECHNICAL DETAILS
175.Nm 182.Nm
176does pretty much what it says. 183does pretty much what it says.
177It examines installed package records in 184It examines installed package records in
178.Pa /var/db/pkg/\*[Lt]pkg-name\*[Gt] , 185.Pa /var/db/pkg/\*[Lt]pkg-name\*[Gt] ,
179deletes the package contents, and finally removes the package records 186deletes the package contents, and finally removes the package records
180(if an alternate package database directory is specified, then it 187(if an alternate package database directory is specified, then it
181overrides the 188overrides the
@@ -281,27 +288,29 @@ The default package database directory i @@ -281,27 +288,29 @@ The default package database directory i
281.Pa /var/db/pkg . 288.Pa /var/db/pkg .
282.It Ev PKG_REFCOUNT_DBDIR 289.It Ev PKG_REFCOUNT_DBDIR
283Location of the package reference counts database directory. 290Location of the package reference counts database directory.
284The default location is the path to the package database directory with 291The default location is the path to the package database directory with
285.Dq .refcount 292.Dq .refcount
286appended to the path, e.g. 293appended to the path, e.g.
287.Pa /var/db/pkg.refcount . 294.Pa /var/db/pkg.refcount .
288.El 295.El
289.Sh SEE ALSO 296.Sh SEE ALSO
290.Xr pkg_add 1 , 297.Xr pkg_add 1 ,
291.Xr pkg_admin 1 , 298.Xr pkg_admin 1 ,
292.Xr pkg_create 1 , 299.Xr pkg_create 1 ,
293.Xr pkg_info 1 , 300.Xr pkg_info 1 ,
294.Xr mktemp 3 , 
295.Xr pkgsrc 7 301.Xr pkgsrc 7
296.Sh AUTHORS 302.Sh AUTHORS
297.Bl -tag -width indent -compact 303.Bl -tag -width indent -compact
298.It "Jordan Hubbard" 304.It "Jordan Hubbard"
299most of the work 305most of the work
300.It "John Kohl" 306.It "John Kohl"
301refined it for 307refined it for
302.Nx 308.Nx
303.It "Hubert Feyrer" 309.It "Hubert Feyrer"
304.Nx 310.Nx
305wildcard dependency processing, pkgdb, recursive "down" 311wildcard dependency processing, pkgdb, recursive "down"
306delete, etc. 312delete, etc.
 313.It Joerg Sonnenberger
 314Rewrote most of the code to compute correct order of deinstallation
 315and to improve error handling.
307.El 316.El

File Added: pkgsrc/pkgtools/pkg_install/files/delete/pkg_delete.c
/*-
 * Copyright (c) 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
 * Copyright (c) 2003 Johnny Lam <jlam@NetBSD.org>.
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``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
 * COPYRIGHT HOLDERS OR CONTRIBUTORS 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.
 */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: pkg_delete.c,v 1.1 2009/02/25 16:29:08 joerg Exp $");

#if HAVE_ERR_H
#include <err.h>
#endif
#include <stdio.h>
#include <stdlib.h>

#include "lib.h"

#ifndef __UNCONST
#define __UNCONST(a)	((void *)(unsigned long)(const void *)(a))
#endif

static const char *pkgdb;
static const char *destdir;
static const char *prefix;

static int no_deinstall;
static int prune_empty;
static int find_by_filename;
static int unregister_only;
static int pkgdb_update_only;
static int delete_recursive;
static int delete_new_leaves;
static int delete_automatic_leaves;

static void
usage(void)
{
	fprintf(stderr, "usage: pkg_delete [-DdFfNnORrVv] [-K pkg_dbdir]"
	    " [-P destdir] [-p prefix] pkg-name ...\n");
	exit(1);
}

static int
add_by_filename(lpkg_head_t *pkgs, const char *filename)
{
	lpkg_t *lpp;
	char *s;

	if ((s = pkgdb_retrieve(filename)) == NULL) {
		warnx("No matching package for file `%s' in pkgdb", filename);
		return 1;
	}

	/* XXX Verify that pkgdb is consistent? Trust it for now... */

	lpp = alloc_lpkg(s);
	TAILQ_INSERT_TAIL(pkgs, lpp, lp_link);
	return 0;
}

static int
add_by_pattern(lpkg_head_t *pkgs, const char *pattern)
{
	switch (add_installed_pkgs_by_pattern(pattern, pkgs)) {
	case 0:
		warnx("No package matching `%s' found", pattern);
		return 1;
	case -1:
		warnx("Error while iterating package database for `%s'",
		    pattern);
		return 1;
	default:
		return 0;
	}
}

/*
 * The argument is either a fixed package name or an absolute path.
 * The latter is recognized for legacy compatibility and must point
 * into the package database.
 */
static int
add_by_pkgname(lpkg_head_t *pkgs, char *pkg)
{
	char *s;
	lpkg_t *lpp;
	size_t l;
	const char *orig_pkg = pkg;

	if (pkg[0] == '/') {
		l = strlen(pkgdb);
		if (strncmp(pkg, pkgdb, l) || pkg[l] != '/') {
			warnx("Absolute path is not relative to "
			    "package database, skipping: %s", pkg);
			return 1;
		}
		pkg += l + 1;
	}
	l = strcspn(pkg, "/");
	if (pkg[l + strspn(pkg + l, "/")] != '\0') {
		warnx("`%s' is not a package name, skipping", orig_pkg);
		return 1;
	}
	pkg[l] = '\0';

	s = pkgdb_pkg_file(pkg, CONTENTS_FNAME);
	if (fexists(s)) {
		free(s);
		lpp = alloc_lpkg(pkg);
		TAILQ_INSERT_TAIL(pkgs, lpp, lp_link);
		return 0;
	}
	free(s);

	switch (add_installed_pkgs_by_basename(pkg, pkgs)) {
	case 0:
		warnx("No matching package for basename `%s' of `%s'",
		    pkg, orig_pkg);
		return 1;
	case -1:
		warnx("Error expanding basename `%s' of `%s'",
		    pkg, orig_pkg);
		return 1;
	default:
		return 0;
	}
}

/*
 * Evaluate +REQUIRED_BY.  This function is used for four different
 * tasks:
 * 0: check if no depending packages remain
 * 1: like 0, but prepend the depending packages to pkgs if they exist
 * 2: print remaining packages to stderr
 * 3: check all and at least one depending packages have been removed
 */
static int
process_required_by(const char *pkg, lpkg_head_t *pkgs,
    lpkg_head_t *sorted_pkgs, int action)
{
	char line[MaxPathSize], *eol, *fname;
	FILE *fp;
	lpkg_t *lpp;
	int got_match, got_miss;

	fname = pkgdb_pkg_file(pkg, REQUIRED_BY_FNAME);
	if (!fexists(fname)) {
		free(fname);
		return 0;
	}

	if ((fp = fopen(fname, "r")) == NULL) {
		warn("Failed to open `%s'", fname);
		free(fname);
		return -1;
	}
	free(fname);

	got_match = 0;
	got_miss = 0;

	while (fgets(line, sizeof(line), fp)) {
		if ((eol = strrchr(line, '\n')) != NULL)
			*eol = '\0';
		TAILQ_FOREACH(lpp, sorted_pkgs, lp_link) {
			if (strcmp(lpp->lp_name, line) == 0)
				break;
		}
		if (lpp != NULL) {
			got_match = 1;
			continue;
		}
		got_miss = 1;
		if (pkgs) {
			TAILQ_FOREACH(lpp, pkgs, lp_link) {
				if (strcmp(lpp->lp_name, line) == 0)
					break;
			}
			if (lpp != NULL)
				continue;
		}
		switch (action) {
		case 0:
			fclose(fp);
			return 1;
		case 1:
			lpp = alloc_lpkg(line);
			TAILQ_INSERT_HEAD(pkgs, lpp, lp_link);
			break;
		case 2:
			fprintf(stderr, "\t%s\n", line);
			break;
		case 3:
			fclose(fp);
			return 0;
		}
	}

	fclose(fp);

	return (action == 3 ? got_match : got_miss);
}

/*
 * Main function to order the patterns from the command line and
 * add the subtrees for -r processing as needed.
 *
 * The first part ensures that all packages are listed at most once
 * in pkgs. Afterwards the list is scanned for packages without depending
 * packages. Each such package is moved to sorted_pkgs in order.
 * If -r is given, all dependencies are inserted at the head of pkgs.
 * The loop has to continue as long as progress is made. This can happen
 * either because another package has been added to pkgs due to recursion
 * (head of pkgs changed) or because a package has no more depending packages
 * (tail of sorted_pkgs changed).
 *
 * If no progress is made, the remaining packages are moved to sorted_pkgs
 * and an error is returned for the !Force case.
 */
static int
sort_and_recurse(lpkg_head_t *pkgs, lpkg_head_t *sorted_pkgs)
{
	lpkg_t *lpp, *lpp2, *lpp_next, *lpp_old_tail, *lpp_old_head;
	int rv;

	TAILQ_FOREACH_SAFE(lpp, pkgs, lp_link, lpp_next) {
		TAILQ_FOREACH(lpp2, pkgs, lp_link) {
			if (lpp != lpp2 &&
			    strcmp(lpp->lp_name, lpp2->lp_name) == 0)
				break;
		}
		if (lpp2 == NULL)
			continue;
		TAILQ_REMOVE(pkgs, lpp, lp_link);
		free_lpkg(lpp);
	}

	while (!TAILQ_EMPTY(pkgs)) {
		lpp_old_tail = TAILQ_LAST(sorted_pkgs, _lpkg_head_t);
		lpp_old_head = TAILQ_FIRST(pkgs);

		TAILQ_FOREACH_SAFE(lpp, pkgs, lp_link, lpp_next) {
			rv = process_required_by(lpp->lp_name, pkgs,
			    sorted_pkgs, delete_recursive ? 1 : 0);
			if (rv)
				continue;
			TAILQ_REMOVE(pkgs, lpp, lp_link);
			TAILQ_INSERT_TAIL(sorted_pkgs, lpp, lp_link);
		}

		if (lpp_old_tail == TAILQ_LAST(sorted_pkgs, _lpkg_head_t) &&
		    lpp_old_head == TAILQ_FIRST(pkgs))
			break;
	}

	if (TAILQ_EMPTY(pkgs))
		return 0;

	while (!TAILQ_EMPTY(pkgs)) {
		lpp = TAILQ_FIRST(pkgs);
		TAILQ_REMOVE(pkgs, lpp, lp_link);
		fprintf(stderr,
		    "Package `%s' is still required by other packages:\n",
		    lpp->lp_name);		
		process_required_by(lpp->lp_name, NULL, sorted_pkgs, 2);
		if (Force)
			TAILQ_INSERT_TAIL(sorted_pkgs, lpp, lp_link);
		else
			free_lpkg(lpp);
	}

	return !Force;
}

struct find_leaves_data {
	lpkg_head_t *pkgs;
	int progress;
};

/*
 * Iterator for finding leaf packages.
 * Packages that are marked as not for deletion are not considered as
 * leaves.  For all other packages it is checked if at least one package
 * that depended on them is to be removed AND no depending package remains.
 * If that is the case, the package is appened to the sorted list.
 * As this package can't have depending packages left, the topological order
 * remains consistent.
 */
static int
find_new_leaves_iter(const char *pkg, void *cookie)
{
	char *fname;
	struct find_leaves_data *data = cookie;
	lpkg_t *lpp;

	fname = pkgdb_pkg_file(pkg, PRESERVE_FNAME);
	if (fexists(fname)) {
		free(fname);
		return 0;
	}
	free(fname);

	if (delete_automatic_leaves && !delete_new_leaves &&
	    !is_automatic_installed(pkg))
		return 0;

	/* Check whether this package is already on the list first. */
	TAILQ_FOREACH(lpp, data->pkgs, lp_link) {
		if (strcmp(lpp->lp_name, pkg) == 0)
			return 0;
	}

	if (process_required_by(pkg, NULL, data->pkgs, 3) == 1) {
		lpp = alloc_lpkg(pkg);
		TAILQ_INSERT_TAIL(data->pkgs, lpp, lp_link);
		data->progress = 0;
	}

	return 0;
}

/*
 * Iterate over all installed packages and look for new leaf packages.
 * As long as the loop adds one new leaf package, processing continues.
 */
static void
find_new_leaves(lpkg_head_t *pkgs)
{
	struct find_leaves_data data;

	data.pkgs = pkgs;
	do {
		data.progress = 0;
		iterate_pkg_db(find_new_leaves_iter, &data);
	} while (data.progress);
}

/*
 * Check that no entry on the package list is marked as not for deletion.
 */
static int
find_preserve_pkgs(lpkg_head_t *pkgs)
{
	lpkg_t *lpp;
	char *fname;
	int found_preserve;

	found_preserve = 0;
	TAILQ_FOREACH(lpp, pkgs, lp_link) {
		fname = pkgdb_pkg_file(lpp->lp_name, PRESERVE_FNAME);
		if (!fexists(fname)) {
			free(fname);
			continue;
		}
		free(fname);
		if (!found_preserve)
			warnx("The following packages are marked as not "
			    "for deletion:");
		found_preserve = 1;
		fprintf(stderr, "\t%s\n", lpp->lp_name);
	}
	if (!found_preserve)
		return 0;
	if (Force == 0 || (!unregister_only && Force == 1))
		return 1;
	fprintf(stderr, "...but will delete them anyway\n");
	return 0;
}

/*
 * Remove package from view.  This is calling pkg_deinstall again.
 */
static int
remove_pkg_from_view(const char *pkg)
{
	char line[MaxPathSize], *fname, *eol;
	FILE *fp;

	fname = pkgdb_pkg_file(pkg, VIEWS_FNAME);
	if (isemptyfile(fname)) {
		free(fname);
		return 0;
	}
	if ((fp = fopen(fname, "r")) == NULL) {
		warn("Unable to open `%s', aborting", fname);
		free(fname);
		return 1;
	}
	free(fname);
	while (fgets(line, sizeof(line), fp) != NULL) {
		if ((eol = strrchr(line, '\n')) != NULL)
			*eol = '\0';
		if (Verbose || Fake)
			printf("Deleting package `%s' instance from `%s' view\n",
			    pkg, line);
		if (Fake)
			continue;
		if (fexec_skipempty(BINDIR "/pkg_delete", "-K", line,
				    Fake ? "-n" : "",
				    (Force > 1) ? "-f" : "",
				    (Force > 0) ? "-f" : "",
				    pkg, NULL) != 0) {
			warnx("Unable to delete package `%s' from view `%s'",
			    pkg, line);
			fclose(fp);
			return 1;
		}
	}
	fclose(fp);
	return 0;	
}

/*
 * Run the +DEINSTALL script. Depending on whether this is
 * a depoted package and whether this pre- or post-deinstall phase,
 * different arguments are passed down.
 */
static int
run_deinstall_script(const char *pkg, int do_postdeinstall)
{
	const char *target, *text;
	char *fname, *fname2, *pkgdir;
	int rv;

	fname = pkgdb_pkg_file(pkg, DEINSTALL_FNAME);
	if (!fexists(fname)) {
		free(fname);
		return 0;
	}

	fname2 = pkgdb_pkg_file(pkg, DEPOT_FNAME);
	if (fexists(fname2)) {
		if (do_postdeinstall) {
			free(fname);
			free(fname2);
			return 0;
		}
		target = "VIEW-DEINSTALL";
		text = "view deinstall";
	} else if (do_postdeinstall) {
		target = "POST-DEINSTALL";
		text = "post-deinstall";
	} else {
		target = "DEINSTALL";
		text = "deinstall";
	}
	free(fname2);

	if (Fake) {
		printf("Would execute %s script with argument %s now\n",
		    text, target);
		free(fname);
		return 0;
	}

	pkgdir = xasprintf("%s/%s", _pkgdb_getPKGDB_DIR(), pkg);
	if (chmod(fname, 0555))
		warn("chmod of `%s' failed", fname);
	rv = fcexec(pkgdir, fname, pkg, target, NULL);
	if (rv)
		warnx("%s script returned error status", text);
	free(pkgdir);
	free(fname);
	return rv;
}

/*
 * Copy lines from fname to fname_tmp, filtering out lines equal to text.
 * Afterwards rename fname_tmp to fname;
 */
static int
remove_line(const char *fname, const char *fname_tmp, const char *text)
{
	FILE *fp, *fp_out;
	char line[MaxPathSize], *eol;
	int rv;

	if ((fp = fopen(fname, "r")) == NULL) {
		warn("Unable to open `%s'", fname);
		return 1;
	}
	if ((fp_out = fopen(fname_tmp, "w")) == NULL) {
		warn("Unable to open `%s'", fname_tmp);
		fclose(fp);
		return 1;
	}

	while (fgets(line, sizeof(line), fp) != NULL) {
		if ((eol = strrchr(line, '\n')) != NULL)
			*eol = '\0';
		if (strcmp(line, text) == 0)
			continue;
		fprintf(fp_out, "%s\n", line);
	}
	fclose(fp);

	if (fclose(fp_out) == EOF) {
		remove(fname_tmp);
		warnx("Failure while closing `%s' temp file", fname_tmp);
		return 1;
	}

	if (rename(fname_tmp, fname) == -1) {
		warn("Unable to rename `%s' to `%s'", fname_tmp, fname);
		rv = 1;
	}
	remove(fname_tmp);

	return rv;
}

/*
 * Unregister the package from the depot it is registered in.
 */
static int
remove_pkg_from_depot(const char *pkg)
{
	FILE *fp;
	char line[MaxPathSize], *eol;
	char *fname, *fname2;
	int rv;

	fname = pkgdb_pkg_file(pkg, DEPOT_FNAME);
	if (isemptyfile(fname)) {
		free(fname);
		return 0;
	}

	if (Verbose)
		printf("Attempting to remove the `%s' registration "
		    "on package `%s'\n", fname, pkg);

	if (Fake) {
		free(fname);
		return 1;
	}

	if ((fp = fopen(fname, "r")) == NULL) {
		warn("Unable to open `%s' file", fname);
		free(fname);
		return 1;
	}
	if (fgets(line, sizeof(line), fp) == NULL) {
		fclose(fp);
		warnx("Empty depot file `%s'", fname);
		free(fname);
		return 1;
	}
	if ((eol = strrchr(line, '\n')) != NULL)
		*eol = '\0';
	fclose(fp);
	free(fname);

	fname = pkgdb_pkg_file(pkg, VIEWS_FNAME);
	fname2 = pkgdb_pkg_file(pkg, VIEWS_FNAME_TMP);
	rv = remove_line(fname, fname2, line);
	free(fname2);
	free(fname);

	return rv;
}

/*
 * remove_depend is used as iterator function below.
 * The passed-in package name should be removed from the
 * +REQUIRED_BY list of the dependency.  Such an entry
 * can miss in a fully correct package database, if the pattern
 * matches more than one package.
 */
static int
remove_depend(const char *cur_pkg, void *cookie)
{
	const char *pkg = cookie;
	char *fname, *fname2;
	int rv;

	fname = pkgdb_pkg_file(cur_pkg, REQUIRED_BY_FNAME);
	if (isemptyfile(fname)) {
		free(fname);
		return 0;
	}
	fname2 = pkgdb_pkg_file(cur_pkg, REQUIRED_BY_FNAME_TMP);

	rv = remove_line(fname, fname2, pkg);

	free(fname2);
	free(fname);

	return rv;
}

static int
remove_pkg(const char *pkg)
{
	FILE *fp;
	char *fname, *pkgdir;
	package_t plist;
	plist_t *p;
	int is_depoted_pkg, rv, late_error;

	if (pkgdb_update_only)
		return pkgdb_remove_pkg(pkg) ? 0 : 1;

	fname = pkgdb_pkg_file(pkg, CONTENTS_FNAME);
	if (!fexists(fname)) {
		warnx("package `%s' is not installed, `%s' missing", pkg, fname);
		free(fname);
		return 1;
	}
	free(fname);

	/* +REQUIRED_BY and +PRESERVE already checked */
	if (remove_pkg_from_view(pkg))
		return 1;

	/*
	 * The views related code has bad error handling, if e.g.
	 * the deinstall script fails, the package remains unregistered.
	 */

	fname = pkgdb_pkg_file(pkg, CONTENTS_FNAME);
	if ((fp = fopen(fname, "r")) == NULL) {
		warnx("Failed to open `%s'", fname);
		free(fname);
		return 1;
	}
	read_plist(&plist, fp);
	fclose(fp);

	/*
	 * If a prefix has been provided, remove the first @cwd and
	 * prepend that prefix.  This allows removing packages without
	 * @cwd if really necessary.  pkg_admin rebuild is likely needed
	 * afterwards though.
	 */
	if (prefix) {
		delete_plist(&plist, FALSE, PLIST_CWD, NULL);
		add_plist_top(&plist, PLIST_CWD, prefix);
	}
	if ((p = find_plist(&plist, PLIST_CWD)) == NULL) {
		warnx("Package `%s' doesn't have a prefix", pkg);
		return 1;
	}

	setenv(PKG_PREFIX_VNAME, p->name, 1);
	fname = xasprintf("%s/%s", _pkgdb_getPKGDB_DIR(), pkg);
	setenv(PKG_METADATA_DIR_VNAME, fname, 1);
	free(fname);

	if (!no_deinstall && !unregister_only) {
		if (run_deinstall_script(pkg, 0) && !Force)
			return 1;
	}

	late_error = 0;

	if (Fake)
		printf("Attempting to delete package `%s'\n", pkg);
	else if (delete_package(FALSE, prune_empty, &plist, unregister_only,
			        destdir) == FAIL) {
		warnx("couldn't entirely delete package `%s'\n", pkg);
		/*
		 * XXX It could be nice to error out here explicitly,
		 * XXX but this is problematic for missing or changed files.
		 * XXX At least the inability to remove files at all should
		 * XXX be handled though.
		 */
	}

	/*
	 * Past the point of no return. Files are gone, all that is left
	 * is cleaning up registered dependencies and removing the meta data.
	 * Errors in the remaining part are counted, but don't stop the
	 * processing.
	 */

	fname = pkgdb_pkg_file(pkg, DEPOT_FNAME);
	if (fexists(fname)) {
		late_error |= remove_pkg_from_depot(pkg);
		/* XXX error checking */
	} else {
		for (p = plist.head; p; p = p->next) {
			if (p->type != PLIST_PKGDEP)
				continue;
			if (Verbose)
				printf("Attempting to remove dependency "
				    "on package `%s'\n", p->name);
			if (Fake)
				continue;
			match_installed_pkgs(p->name, remove_depend,
			    __UNCONST(pkg));
		}
	}
	free(fname);

	free_plist(&plist);

	if (!no_deinstall && !unregister_only)
		late_error |= run_deinstall_script(pkg, 1);

	fname = pkgdb_pkg_file(pkg, VIEWS_FNAME);
	if (fexists(fname))
		is_depoted_pkg = TRUE;
	free(fname);

	if (Fake)
		return 0;

	/*
	 * Kill the pkgdb subdirectory. The files have been removed, so
	 * this is way beyond the point of no return.
	 */
	pkgdir = xasprintf("%s/%s", _pkgdb_getPKGDB_DIR(), pkg);
	(void) remove_files(pkgdir, "+*");
	rv = 1;
	if (isemptydir(pkgdir)&& rmdir(pkgdir) == 0)
		rv = 0;
	else if (is_depoted_pkg)
		warnx("Depot directory `%s' is not empty", pkgdir);
	else if (!Force)
		warnx("Couldn't remove package directory in `%s'", pkgdir);
	else if (recursive_remove(pkgdir, 1))
		warn("Couldn't remove package directory `%s'", pkgdir);
	else
		warnx("Package directory `%s' forcefully removed", pkgdir);
	free(pkgdir);

	return rv | late_error;
}

int
main(int argc, char *argv[])
{
	lpkg_head_t pkgs, sorted_pkgs;
	int ch, r, has_error;
	unsigned long bad_count;

	TAILQ_INIT(&pkgs);
	TAILQ_INIT(&sorted_pkgs);

	while ((ch = getopt(argc, argv, "ADdFfNnORrVvK:P:p:")) != -1) {
		switch (ch) {
		case 'A':
			delete_automatic_leaves = 1;
			break;
		case 'D':
			no_deinstall = 1;
			break;
		case 'd':
			prune_empty = 1;
			break;
		case 'F':
			find_by_filename = 1;
			break;
		case 'f':
			++Force;
			break;
		case 'K':
			pkgdb = optarg;
			break;
		case 'N':
			unregister_only = 1;
			break;
		case 'n':
			Fake = 1;
			break;
		case 'O':
			pkgdb_update_only = 1;
			break;
		case 'P':
			destdir = optarg;
			break;
		case 'p':
			prefix = optarg;
			break;
		case 'R':
			delete_new_leaves = 1;
			break;
		case 'r':
			delete_recursive = 1;
			break;
		case 'V':
			show_version();
			/* NOTREACHED */
		case 'v':
			++Verbose;
			break;
		default:
			usage();
			break;
		}
	}

	if (destdir != NULL) {
		char *pkgdbdir;

		if (pkgdb == NULL)
			pkgdb = _pkgdb_getPKGDB_DIR();

		pkgdbdir = xasprintf("%s/%s", destdir, pkgdb);
		_pkgdb_setPKGDB_DIR(pkgdbdir);
		free(pkgdbdir);
	} else if (pkgdb != NULL) {
		_pkgdb_setPKGDB_DIR(pkgdb);
	} else {
		pkgdb = _pkgdb_getPKGDB_DIR();
	}

	argc -= optind;
	argv += optind;

	if (argc == 0) {
		if (find_by_filename)
			warnx("Missing filename(s)");
		else
			warnx("Missing package name(s)");
		usage();
	}

	if (Fake)
		r = pkgdb_open(ReadOnly);
	else
		r = pkgdb_open(ReadWrite);

	if (!r)
		errx(EXIT_FAILURE, "Opening pkgdb failed");

	/* First, process all command line options. */

	has_error = 0;
	for (; argc != 0; --argc, ++argv) {
		if (find_by_filename)
			has_error |= add_by_filename(&pkgs, *argv);
		else if (ispkgpattern(*argv))
			has_error |= add_by_pattern(&pkgs, *argv);
		else
			has_error |= add_by_pkgname(&pkgs, *argv);
	}

	if (has_error && !Force) {
		pkgdb_close();
		return EXIT_FAILURE;
	}

	/* Second, reorder and recursive if necessary. */

	if (sort_and_recurse(&pkgs, &sorted_pkgs)) {
		pkgdb_close();
		return EXIT_FAILURE;
	}

	/* Third, add leaves if necessary. */

	if (delete_new_leaves || delete_automatic_leaves)
		find_new_leaves(&sorted_pkgs);

	/*
	 * Now that all packages to remove are known, check
	 * if all are removable.  After that, start the actual
	 * removal.
	 */

	if (find_preserve_pkgs(&sorted_pkgs)) {
		pkgdb_close();
		return EXIT_FAILURE;
	}

	setenv(PKG_REFCOUNT_DBDIR_VNAME, pkgdb_refcount_dir(), 1);

	bad_count = 0;
	while (!TAILQ_EMPTY(&sorted_pkgs)) {
		lpkg_t *lpp;
		
		lpp = TAILQ_FIRST(&sorted_pkgs);
		TAILQ_REMOVE(&sorted_pkgs, lpp, lp_link);
		if (remove_pkg(lpp->lp_name)) {
			++bad_count;
			if (!Force)
				break;
		}
		free_lpkg(lpp);
	}

	pkgdb_close();

	if (Force && bad_count && Verbose)
		warnx("Removal of %lu packages failed", bad_count);

	return bad_count > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

cvs diff -r1.18 -r1.19 pkgsrc/pkgtools/pkg_install/files/delete/Attic/pkg_delete.cat1 (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/delete/Attic/pkg_delete.cat1 2009/02/02 12:35:01 1.18
+++ pkgsrc/pkgtools/pkg_install/files/delete/Attic/pkg_delete.cat1 2009/02/25 16:29:08 1.19
@@ -1,51 +1,59 @@ @@ -1,51 +1,59 @@
1PKG_DELETE(1) NetBSD General Commands Manual PKG_DELETE(1) 1PKG_DELETE(1) NetBSD General Commands Manual PKG_DELETE(1)
2 2
3NNAAMMEE 3NNAAMMEE
4 ppkkgg__ddeelleettee -- a utility for deleting previously installed software pack- 4 ppkkgg__ddeelleettee -- a utility for deleting previously installed software pack-
5 age distributions 5 age distributions
6 6
7SSYYNNOOPPSSIISS 7SSYYNNOOPPSSIISS
8 ppkkgg__ddeelleettee [--DDddFFffNNnnOORRrrVVvv] [--KK _p_k_g___d_b_d_i_r] [--PP _d_e_s_t_d_i_r] [--pp _p_r_e_f_i_x] 8 ppkkgg__ddeelleettee [--AADDddFFffNNnnOORRrrVVvv] [--KK _p_k_g___d_b_d_i_r] [--PP _d_e_s_t_d_i_r] [--pp _p_r_e_f_i_x]
9 _p_k_g_-_n_a_m_e _._._. 9 _p_k_g_-_n_a_m_e _._._.
10 10
11DDEESSCCRRIIPPTTIIOONN 11DDEESSCCRRIIPPTTIIOONN
12 The ppkkgg__ddeelleettee command is used to delete packages that have been previ- 12 The ppkkgg__ddeelleettee command is used to delete packages that have been previ-
13 ously installed with the pkg_add(1) command. 13 ously installed with the pkg_add(1) command. The given packages are
 14 sorted, so that the dependencies of a package are deleted after the pack-
 15 age. Before any action is executed, ppkkgg__ddeelleettee checks for packages that
 16 are marked as pprreesseerrvveedd or have depending packages left. Unless the --ff
 17 flag is given, ppkkgg__ddeelleettee stops on the first error.
14 18
15WWAARRNNIINNGG 19WWAARRNNIINNGG
16 _S_i_n_c_e _t_h_e ppkkgg__ddeelleettee _c_o_m_m_a_n_d _m_a_y _e_x_e_c_u_t_e _s_c_r_i_p_t_s _o_r _p_r_o_g_r_a_m_s _p_r_o_v_i_d_e_d _b_y 20 _S_i_n_c_e _t_h_e ppkkgg__ddeelleettee _c_o_m_m_a_n_d _m_a_y _e_x_e_c_u_t_e _s_c_r_i_p_t_s _o_r _p_r_o_g_r_a_m_s _p_r_o_v_i_d_e_d _b_y
17 _a _p_a_c_k_a_g_e _f_i_l_e_, _y_o_u_r _s_y_s_t_e_m _m_a_y _b_e _s_u_s_c_e_p_t_i_b_l_e _t_o _`_`_T_r_o_j_a_n _h_o_r_s_e_s_'_' _o_r 21 _a _p_a_c_k_a_g_e _f_i_l_e_, _y_o_u_r _s_y_s_t_e_m _m_a_y _b_e _s_u_s_c_e_p_t_i_b_l_e _t_o _`_`_T_r_o_j_a_n _h_o_r_s_e_s_'_' _o_r
18 _o_t_h_e_r _s_u_b_t_l_e _a_t_t_a_c_k_s _f_r_o_m _m_i_s_c_r_e_a_n_t_s _w_h_o _c_r_e_a_t_e _d_a_n_g_e_r_o_u_s _p_a_c_k_a_g_e _f_i_l_e_s_. 22 _o_t_h_e_r _s_u_b_t_l_e _a_t_t_a_c_k_s _f_r_o_m _m_i_s_c_r_e_a_n_t_s _w_h_o _c_r_e_a_t_e _d_a_n_g_e_r_o_u_s _p_a_c_k_a_g_e _f_i_l_e_s_.
19 23
20 _Y_o_u _a_r_e _a_d_v_i_s_e_d _t_o _v_e_r_i_f_y _t_h_e _c_o_m_p_e_t_e_n_c_e _a_n_d _i_d_e_n_t_i_t_y _o_f _t_h_o_s_e _w_h_o _p_r_o_- 24 _Y_o_u _a_r_e _a_d_v_i_s_e_d _t_o _v_e_r_i_f_y _t_h_e _c_o_m_p_e_t_e_n_c_e _a_n_d _i_d_e_n_t_i_t_y _o_f _t_h_o_s_e _w_h_o _p_r_o_-
21 _v_i_d_e _i_n_s_t_a_l_l_a_b_l_e _p_a_c_k_a_g_e _f_i_l_e_s_. _F_o_r _e_x_t_r_a _p_r_o_t_e_c_t_i_o_n_, _e_x_a_m_i_n_e _a_l_l _t_h_e 25 _v_i_d_e _i_n_s_t_a_l_l_a_b_l_e _p_a_c_k_a_g_e _f_i_l_e_s_. _F_o_r _e_x_t_r_a _p_r_o_t_e_c_t_i_o_n_, _e_x_a_m_i_n_e _a_l_l _t_h_e
22 _p_a_c_k_a_g_e _c_o_n_t_r_o_l _f_i_l_e_s _i_n _t_h_e _p_a_c_k_a_g_e _r_e_c_o_r_d _d_i_r_e_c_t_o_r_y 26 _p_a_c_k_a_g_e _c_o_n_t_r_o_l _f_i_l_e_s _i_n _t_h_e _p_a_c_k_a_g_e _r_e_c_o_r_d _d_i_r_e_c_t_o_r_y
23 _(_/_v_a_r_/_d_b_/_p_k_g_/_<_p_k_g_-_n_a_m_e_>_/_)_. _P_a_y _p_a_r_t_i_c_u_l_a_r _a_t_t_e_n_t_i_o_n _t_o _a_n_y _+_I_N_S_T_A_L_L _o_r 27 _(_/_v_a_r_/_d_b_/_p_k_g_/_<_p_k_g_-_n_a_m_e_>_/_)_. _P_a_y _p_a_r_t_i_c_u_l_a_r _a_t_t_e_n_t_i_o_n _t_o _a_n_y _+_I_N_S_T_A_L_L _o_r
24 _+_D_E_I_N_S_T_A_L_L _f_i_l_e_s_, _a_n_d _i_n_s_p_e_c_t _t_h_e _+_C_O_N_T_E_N_T_S _f_i_l_e _f_o_r @@ccwwdd_, @@mmooddee _(_c_h_e_c_k 28 _+_D_E_I_N_S_T_A_L_L _f_i_l_e_s_, _a_n_d _i_n_s_p_e_c_t _t_h_e _+_C_O_N_T_E_N_T_S _f_i_l_e _f_o_r @@ccwwdd_, @@mmooddee _(_c_h_e_c_k
25 _f_o_r _s_e_t_u_i_d_)_, @@ddiirrrrmm_, @@eexxeecc_, _a_n_d @@uunneexxeecc _d_i_r_e_c_t_i_v_e_s_, _a_n_d_/_o_r _u_s_e _t_h_e 29 _f_o_r _s_e_t_u_i_d_)_, @@ddiirrrrmm_, @@eexxeecc_, _a_n_d @@uunneexxeecc _d_i_r_e_c_t_i_v_e_s_, _a_n_d_/_o_r _u_s_e _t_h_e
26 pkg_info(_1) _c_o_m_m_a_n_d _t_o _e_x_a_m_i_n_e _t_h_e _i_n_s_t_a_l_l_e_d _p_a_c_k_a_g_e _c_o_n_t_r_o_l _f_i_l_e_s_. 30 pkg_info(_1) _c_o_m_m_a_n_d _t_o _e_x_a_m_i_n_e _t_h_e _i_n_s_t_a_l_l_e_d _p_a_c_k_a_g_e _c_o_n_t_r_o_l _f_i_l_e_s_.
27 31
28OOPPTTIIOONNSS 32OOPPTTIIOONNSS
29 The following command line options are supported: 33 The following command line options are supported:
30 34
31 _p_k_g_-_n_a_m_e _._._. 35 _p_k_g_-_n_a_m_e _._._.
32 The named packages are deinstalled, wildcards can be used, see 36 The named packages are deinstalled, wildcards can be used, see
33 pkg_info(1). If no version is given, the one currently installed 37 pkg_info(1). If no version is given, the one currently installed
34 will be removed. If the --FF flag is given, one or more (absolute) 38 will be removed. If the --FF flag is given, one or more (absolute)
35 filenames may be specified and the Package Database will be con- 39 filenames may be specified and the Package Database will be con-
36 sulted for the package to which the given file belongs. These 40 sulted for the package to which the given file belongs. These
37 packages are then deinstalled. 41 packages are then deinstalled.
38 42
 43 --AA Recursively remove all automatically installed packages that were
 44 needed by the given packages and are no longer required. See
 45 also the --RR flag.
 46
39 --DD If a deinstallation script exists for a given package, do not 47 --DD If a deinstallation script exists for a given package, do not
40 execute it. 48 execute it.
41 49
42 --dd Remove empty directories created by file cleanup. By default, 50 --dd Remove empty directories created by file cleanup. By default,
43 only files/directories explicitly listed in a package's contents 51 only files/directories explicitly listed in a package's contents
44 (either as normal files/directories or with the @@ddiirrrrmm directive) 52 (either as normal files/directories or with the @@ddiirrrrmm directive)
45 will be removed at deinstallation time. This option tells 53 will be removed at deinstallation time. This option tells
46 ppkkgg__ddeelleettee to also remove any directories that were emptied as a 54 ppkkgg__ddeelleettee to also remove any directories that were emptied as a
47 result of removing the package. 55 result of removing the package.
48 56
49 --FF Any pkg-name given will be interpreted as pathname which is sub- 57 --FF Any pkg-name given will be interpreted as pathname which is sub-
50 sequently transformed in a (real) package name via the Package 58 sequently transformed in a (real) package name via the Package
51 Database. That way, packages can be deleted by giving a filename 59 Database. That way, packages can be deleted by giving a filename
@@ -74,37 +82,32 @@ OOPPTTIIOONNSS @@ -74,37 +82,32 @@ OOPPTTIIOONNSS
74 not touch the package or its files itself. 82 not touch the package or its files itself.
75 83
76 --pp _d_e_s_t_d_i_r 84 --pp _d_e_s_t_d_i_r
77 Prefix all file and directory names with _d_e_s_t_d_i_r. For packages 85 Prefix all file and directory names with _d_e_s_t_d_i_r. For packages
78 without install scripts this has the same behavior as using 86 without install scripts this has the same behavior as using
79 chroot. 87 chroot.
80 88
81 --pp _p_r_e_f_i_x 89 --pp _p_r_e_f_i_x
82 Set _p_r_e_f_i_x as the directory in which to delete files from any 90 Set _p_r_e_f_i_x as the directory in which to delete files from any
83 installed packages which do not explicitly set theirs. For most 91 installed packages which do not explicitly set theirs. For most
84 packages, the prefix will be set automatically to the installed 92 packages, the prefix will be set automatically to the installed
85 location by pkg_add(1). 93 location by pkg_add(1).
86 94
87 --RR This option triggers a recursive delete of the given package and 95 --RR Recursively remove all packages that were needed by the given
88 any packages it depends on, unless some other package still needs 96 packages and that have no other dependencies left. This option
89 a dependent package. This --RR option can be used to clean up by 97 overrides the --AA flag.
90 deleting a package and all its then-unneeded dependent packages. 98
91 99 --rr Recursively remove all packages that require one of the packages
92 --rr ppkkgg__ddeelleettee first builds a list of all packages that require 100 given.
93 (directly and indirectly) the one being deleted. It then deletes 
94 these packages using ppkkgg__ddeelleettee with the given options before 
95 deleting the user specified package. This --rr option can be used 
96 to recursively delete a package and all of the packages which 
97 depend on that package. 
98 101
99 --VV Print version number and exit. 102 --VV Print version number and exit.
100 103
101 --vv Turn on verbose output. 104 --vv Turn on verbose output.
102 105
103TTEECCHHNNIICCAALL DDEETTAAIILLSS 106TTEECCHHNNIICCAALL DDEETTAAIILLSS
104 ppkkgg__ddeelleettee does pretty much what it says. It examines installed package 107 ppkkgg__ddeelleettee does pretty much what it says. It examines installed package
105 records in _/_v_a_r_/_d_b_/_p_k_g_/_<_p_k_g_-_n_a_m_e_>, deletes the package contents, and 108 records in _/_v_a_r_/_d_b_/_p_k_g_/_<_p_k_g_-_n_a_m_e_>, deletes the package contents, and
106 finally removes the package records (if an alternate package database 109 finally removes the package records (if an alternate package database
107 directory is specified, then it overrides the _/_v_a_r_/_d_b_/_p_k_g path shown 110 directory is specified, then it overrides the _/_v_a_r_/_d_b_/_p_k_g path shown
108 above). 111 above).
109 112
110 If a package is required by other installed packages, ppkkgg__ddeelleettee will 113 If a package is required by other installed packages, ppkkgg__ddeelleettee will
@@ -147,26 +150,28 @@ TTEECCHHNNIICCAALL DDEETTAA @@ -147,26 +150,28 @@ TTEECCHHNNIICCAALL DDEETTAA
147 150
148EENNVVIIRROONNMMEENNTT 151EENNVVIIRROONNMMEENNTT
149 PKG_DBDIR If the --KK flag isn't given, then PKG_DBDIR is the location of 152 PKG_DBDIR If the --KK flag isn't given, then PKG_DBDIR is the location of
150 the package database directory. The default package database 153 the package database directory. The default package database
151 directory is _/_v_a_r_/_d_b_/_p_k_g. 154 directory is _/_v_a_r_/_d_b_/_p_k_g.
152 155
153 PKG_REFCOUNT_DBDIR 156 PKG_REFCOUNT_DBDIR
154 Location of the package reference counts database directory. 157 Location of the package reference counts database directory.
155 The default location is the path to the package database 158 The default location is the path to the package database
156 directory with ``.refcount'' appended to the path, e.g. 159 directory with ``.refcount'' appended to the path, e.g.
157 _/_v_a_r_/_d_b_/_p_k_g_._r_e_f_c_o_u_n_t. 160 _/_v_a_r_/_d_b_/_p_k_g_._r_e_f_c_o_u_n_t.
158 161
159SSEEEE AALLSSOO 162SSEEEE AALLSSOO
160 pkg_add(1), pkg_admin(1), pkg_create(1), pkg_info(1), mktemp(3), 163 pkg_add(1), pkg_admin(1), pkg_create(1), pkg_info(1), pkgsrc(7)
161 pkgsrc(7) 
162 164
163AAUUTTHHOORRSS 165AAUUTTHHOORRSS
164 Jordan Hubbard 166 Jordan Hubbard
165 most of the work 167 most of the work
166 John Kohl 168 John Kohl
167 refined it for NetBSD 169 refined it for NetBSD
168 Hubert Feyrer 170 Hubert Feyrer
169 NetBSD wildcard dependency processing, pkgdb, recursive "down" 171 NetBSD wildcard dependency processing, pkgdb, recursive "down"
170 delete, etc. 172 delete, etc.
 173 Joerg Sonnenberger
 174 Rewrote most of the code to compute correct order of deinstalla-
 175 tion and to improve error handling.
171 176
172NetBSD 4.0 July 30, 2008 NetBSD 4.0 177NetBSD 5.0 July 30, 2008 NetBSD 5.0

cvs diff -r1.112 -r1.113 pkgsrc/pkgtools/pkg_install/files/lib/version.h (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/lib/version.h 2009/02/14 17:08:05 1.112
+++ pkgsrc/pkgtools/pkg_install/files/lib/version.h 2009/02/25 16:29:08 1.113
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: version.h,v 1.112 2009/02/14 17:08:05 joerg Exp $ */ 1/* $NetBSD: version.h,v 1.113 2009/02/25 16:29:08 joerg Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001 Thomas Klausner. All rights reserved. 4 * Copyright (c) 2001 Thomas Klausner. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
@@ -17,16 +17,16 @@ @@ -17,16 +17,16 @@
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */ 25 */
26 26
27#ifndef _INST_LIB_VERSION_H_ 27#ifndef _INST_LIB_VERSION_H_
28#define _INST_LIB_VERSION_H_ 28#define _INST_LIB_VERSION_H_
29 29
30#define PKGTOOLS_VERSION "20090214" 30#define PKGTOOLS_VERSION "20090225"
31 31
32#endif /* _INST_LIB_VERSION_H_ */ 32#endif /* _INST_LIB_VERSION_H_ */