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 (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,45 +1,45 @@ @@ -1,45 +1,45 @@
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:
40 $(INSTALL) -m 755 -d ${DESTDIR}$(sbindir) 40 $(INSTALL) -m 755 -d ${DESTDIR}$(sbindir)
41 $(INSTALL) -m 755 -d ${DESTDIR}$(man1dir) 41 $(INSTALL) -m 755 -d ${DESTDIR}$(man1dir)
42 $(INSTALL) -m 755 -d ${DESTDIR}$(cat1dir) 42 $(INSTALL) -m 755 -d ${DESTDIR}$(cat1dir)
43 $(INSTALL) $(PROG) ${DESTDIR}$(sbindir)/$(PROG) 43 $(INSTALL) $(PROG) ${DESTDIR}$(sbindir)/$(PROG)
44 $(INSTALL) -m 444 $(PROG).1 ${DESTDIR}$(man1dir)/$(PROG).1 44 $(INSTALL) -m 444 $(PROG).1 ${DESTDIR}$(man1dir)/$(PROG).1
45 $(INSTALL) -m 444 $(PROG).cat1 ${DESTDIR}$(cat1dir)/$(PROG).0 45 $(INSTALL) -m 444 $(PROG).cat1 ${DESTDIR}$(cat1dir)/$(PROG).0

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 (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,307 +1,316 @@ @@ -1,307 +1,316 @@
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
57package record directory 69package record directory
58.Pa ( /var/db/pkg/\*[Lt]pkg-name\*[Gt]/ ) . 70.Pa ( /var/db/pkg/\*[Lt]pkg-name\*[Gt]/ ) .
59Pay particular 71Pay particular
60attention to any 72attention to any
61.Pa +INSTALL 73.Pa +INSTALL
62or 74or
63.Pa +DEINSTALL 75.Pa +DEINSTALL
64files, and inspect the 76files, and inspect the
65.Pa +CONTENTS 77.Pa +CONTENTS
66file for 78file for
67.Cm @cwd , 79.Cm @cwd ,
68.Cm @mode 80.Cm @mode
69(check for setuid), 81(check for setuid),
70.Cm @dirrm , 82.Cm @dirrm ,
71.Cm @exec , 83.Cm @exec ,
72and 84and
73.Cm @unexec 85.Cm @unexec
74directives, and/or use the 86directives, and/or use the
75.Xr pkg_info 1 87.Xr pkg_info 1
76command to examine the installed package control files. 88command to examine the installed package control files.
77.Ef 89.Ef
78.Sh OPTIONS 90.Sh OPTIONS
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
105Any pkg-name given will be interpreted as pathname which is 123Any pkg-name given will be interpreted as pathname which is
106subsequently transformed in a (real) package name via the Package 124subsequently transformed in a (real) package name via the Package
107Database. 125Database.
108That way, packages can be deleted by giving a filename 126That way, packages can be deleted by giving a filename
109instead of the package-name. 127instead of the package-name.
110.It Fl f 128.It Fl f
111Force removal of the package, even if a dependency is recorded or the 129Force removal of the package, even if a dependency is recorded or the
112deinstall script fails. 130deinstall script fails.
113.It Fl ff 131.It Fl ff
114Force removal of the package, even if the package is marked as a 132Force removal of the package, even if the package is marked as a
115.Cm preserved 133.Cm preserved
116package. 134package.
117Note that this is a dangerous operation. 135Note that this is a dangerous operation.
118.It Fl K Ar pkg_dbdir 136.It Fl K Ar pkg_dbdir
119Set 137Set
120.Ar pkg_dbdir 138.Ar pkg_dbdir
121as the package database directory. 139as the package database directory.
122If this option isn't specified, then the package database directory is 140If this option isn't specified, then the package database directory is
123taken from the value of the environment variable 141taken from the value of the environment variable
124.Ev PKG_DBDIR 142.Ev PKG_DBDIR
125if it's set, otherwise it defaults to 143if it's set, otherwise it defaults to
126.Pa /var/db/pkg . 144.Pa /var/db/pkg .
127.It Fl N 145.It Fl N
128Remove the package's registration and its entries from the package database, 146Remove the package's registration and its entries from the package database,
129but leave the files installed. 147but leave the files installed.
130Don't run any deinstall scripts or @unexec lines either. 148Don't run any deinstall scripts or @unexec lines either.
131.It Fl n 149.It Fl n
132Don't actually deinstall a package, just report the steps that 150Don't actually deinstall a package, just report the steps that
133would be taken if it were. 151would be taken if it were.
134.It Fl O 152.It Fl O
135Only delete the package's entries from the package database, do not 153Only delete the package's entries from the package database, do not
136touch the package or its files itself. 154touch the package or its files itself.
137.It Fl p Ar destdir 155.It Fl p Ar destdir
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
182.Pa /var/db/pkg 189.Pa /var/db/pkg
183path shown above). 190path shown above).
184.Pp 191.Pp
185If a package is required by other installed packages, 192If a package is required by other installed packages,
186.Nm 193.Nm
187will list those dependent packages and refuse to delete the package 194will list those dependent packages and refuse to delete the package
188(unless the 195(unless the
189.Fl f 196.Fl f
190option is given). 197option is given).
191.Pp 198.Pp
192If a package has been marked as a 199If a package has been marked as a
193.Cm preserved 200.Cm preserved
194package, it will not be able to be deleted 201package, it will not be able to be deleted
195(unless more than one occurrence of the 202(unless more than one occurrence of the
196.Fl f 203.Fl f
197option is given). 204option is given).
198.Pp 205.Pp
199If a filename is given instead of a package name, the package of which 206If a filename is given instead of a package name, the package of which
200the given file belongs to can be deleted if the 207the given file belongs to can be deleted if the
201.Fl F 208.Fl F
202Flag is given. 209Flag is given.
203The filename needs to be absolute, see the output produced by the pkg_info 210The filename needs to be absolute, see the output produced by the pkg_info
204.Fl aF 211.Fl aF
205command. 212command.
206.Pp 213.Pp
207If a 214If a
208.Cm deinstall 215.Cm deinstall
209script exists for the package, it is executed before and after 216script exists for the package, it is executed before and after
210any files are removed. 217any files are removed.
211It is this script's responsibility to clean up any additional messy details 218It is this script's responsibility to clean up any additional messy details
212around the package's installation, since all 219around the package's installation, since all
213.Nm 220.Nm
214knows how to do is delete the files created in the original distribution. 221knows how to do is delete the files created in the original distribution.
215The 222The
216.Ic deinstall 223.Ic deinstall
217script is called as: 224script is called as:
218.Bd -filled -offset indent -compact 225.Bd -filled -offset indent -compact
219.Cm deinstall 226.Cm deinstall
220.Aq Ar pkg-name 227.Aq Ar pkg-name
221.Ar VIEW-DEINSTALL 228.Ar VIEW-DEINSTALL
222.Ed 229.Ed
223before removing the package from a view, and as: 230before removing the package from a view, and as:
224.Bd -filled -offset indent -compact 231.Bd -filled -offset indent -compact
225.Cm deinstall 232.Cm deinstall
226.Aq Ar pkg-name 233.Aq Ar pkg-name
227.Ar DEINSTALL 234.Ar DEINSTALL
228.Ed 235.Ed
229before deleting all files and as: 236before deleting all files and as:
230.Bd -filled -offset indent -compact 237.Bd -filled -offset indent -compact
231.Cm deinstall 238.Cm deinstall
232.Aq Ar pkg-name 239.Aq Ar pkg-name
233.Ar POST-DEINSTALL 240.Ar POST-DEINSTALL
234.Ed 241.Ed
235after deleting them. 242after deleting them.
236Passing the keywords 243Passing the keywords
237.Ar VIEW-DEINSTALL , 244.Ar VIEW-DEINSTALL ,
238.Ar DEINSTALL 245.Ar DEINSTALL
239and 246and
240.Ar POST-DEINSTALL 247.Ar POST-DEINSTALL
241lets you potentially write only one program/script that handles all 248lets you potentially write only one program/script that handles all
242aspects of installation and deletion. 249aspects of installation and deletion.
243.Pp 250.Pp
244All scripts are called with the environment variable 251All scripts are called with the environment variable
245.Ev PKG_PREFIX 252.Ev PKG_PREFIX
246set to the installation prefix (see the 253set to the installation prefix (see the
247.Fl p 254.Fl p
248option above). 255option above).
249This allows a package author to write a script 256This allows a package author to write a script
250that reliably performs some action on the directory where the package 257that reliably performs some action on the directory where the package
251is installed, even if the user might have changed it by specifying the 258is installed, even if the user might have changed it by specifying the
252.Fl p 259.Fl p
253option when running 260option when running
254.Nm 261.Nm
255or 262or
256.Xr pkg_add 1 . 263.Xr pkg_add 1 .
257The scripts are also called with the 264The scripts are also called with the
258.Ev PKG_METADATA_DIR 265.Ev PKG_METADATA_DIR
259environment variable set to the location of the 266environment variable set to the location of the
260.Pa +* 267.Pa +*
261meta-data files, and with the 268meta-data files, and with the
262.Ev PKG_REFCOUNT_DBDIR 269.Ev PKG_REFCOUNT_DBDIR
263environment variable set to the location of the package reference counts 270environment variable set to the location of the package reference counts
264database directory. 271database directory.
265If the 272If the
266.Fl P 273.Fl P
267flag was given to 274flag was given to
268.Nm , 275.Nm ,
269.Ev PKG_DESTDIR 276.Ev PKG_DESTDIR
270will be set to 277will be set to
271.Ar destdir . 278.Ar destdir .
272.Sh ENVIRONMENT 279.Sh ENVIRONMENT
273.Bl -tag -width PKG_DBDIR 280.Bl -tag -width PKG_DBDIR
274.It Ev PKG_DBDIR 281.It Ev PKG_DBDIR
275If the 282If the
276.Fl K 283.Fl K
277flag isn't given, then 284flag isn't given, then
278.Ev PKG_DBDIR 285.Ev PKG_DBDIR
279is the location of the package database directory. 286is the location of the package database directory.
280The default package database directory is 287The default package database directory is
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 (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,172 +1,177 @@ @@ -1,172 +1,177 @@
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
52 instead of the package-name. 60 instead of the package-name.
53 61
54 --ff Force removal of the package, even if a dependency is recorded or 62 --ff Force removal of the package, even if a dependency is recorded or
55 the deinstall script fails. 63 the deinstall script fails.
56 64
57 --ffff Force removal of the package, even if the package is marked as a 65 --ffff Force removal of the package, even if the package is marked as a
58 pprreesseerrvveedd package. Note that this is a dangerous operation. 66 pprreesseerrvveedd package. Note that this is a dangerous operation.
59 67
60 --KK _p_k_g___d_b_d_i_r 68 --KK _p_k_g___d_b_d_i_r
61 Set _p_k_g___d_b_d_i_r as the package database directory. If this option 69 Set _p_k_g___d_b_d_i_r as the package database directory. If this option
62 isn't specified, then the package database directory is taken 70 isn't specified, then the package database directory is taken
63 from the value of the environment variable PKG_DBDIR if it's set, 71 from the value of the environment variable PKG_DBDIR if it's set,
64 otherwise it defaults to _/_v_a_r_/_d_b_/_p_k_g. 72 otherwise it defaults to _/_v_a_r_/_d_b_/_p_k_g.
65 73
66 --NN Remove the package's registration and its entries from the pack- 74 --NN Remove the package's registration and its entries from the pack-
67 age database, but leave the files installed. Don't run any dein- 75 age database, but leave the files installed. Don't run any dein-
68 stall scripts or @unexec lines either. 76 stall scripts or @unexec lines either.
69 77
70 --nn Don't actually deinstall a package, just report the steps that 78 --nn Don't actually deinstall a package, just report the steps that
71 would be taken if it were. 79 would be taken if it were.
72 80
73 --OO Only delete the package's entries from the package database, do 81 --OO Only delete the package's entries from the package database, do
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
111 list those dependent packages and refuse to delete the package (unless 114 list those dependent packages and refuse to delete the package (unless
112 the --ff option is given). 115 the --ff option is given).
113 116
114 If a package has been marked as a pprreesseerrvveedd package, it will not be able 117 If a package has been marked as a pprreesseerrvveedd package, it will not be able
115 to be deleted (unless more than one occurrence of the --ff option is 118 to be deleted (unless more than one occurrence of the --ff option is
116 given). 119 given).
117 120
118 If a filename is given instead of a package name, the package of which 121 If a filename is given instead of a package name, the package of which
119 the given file belongs to can be deleted if the --FF Flag is given. The 122 the given file belongs to can be deleted if the --FF Flag is given. The
120 filename needs to be absolute, see the output produced by the pkg_info 123 filename needs to be absolute, see the output produced by the pkg_info
121 --aaFF command. 124 --aaFF command.
122 125
123 If a ddeeiinnssttaallll script exists for the package, it is executed before and 126 If a ddeeiinnssttaallll script exists for the package, it is executed before and
124 after any files are removed. It is this script's responsibility to clean 127 after any files are removed. It is this script's responsibility to clean
125 up any additional messy details around the package's installation, since 128 up any additional messy details around the package's installation, since
126 all ppkkgg__ddeelleettee knows how to do is delete the files created in the origi- 129 all ppkkgg__ddeelleettee knows how to do is delete the files created in the origi-
127 nal distribution. The ddeeiinnssttaallll script is called as: 130 nal distribution. The ddeeiinnssttaallll script is called as:
128 ddeeiinnssttaallll <_p_k_g_-_n_a_m_e> _V_I_E_W_-_D_E_I_N_S_T_A_L_L 131 ddeeiinnssttaallll <_p_k_g_-_n_a_m_e> _V_I_E_W_-_D_E_I_N_S_T_A_L_L
129 before removing the package from a view, and as: 132 before removing the package from a view, and as:
130 ddeeiinnssttaallll <_p_k_g_-_n_a_m_e> _D_E_I_N_S_T_A_L_L 133 ddeeiinnssttaallll <_p_k_g_-_n_a_m_e> _D_E_I_N_S_T_A_L_L
131 before deleting all files and as: 134 before deleting all files and as:
132 ddeeiinnssttaallll <_p_k_g_-_n_a_m_e> _P_O_S_T_-_D_E_I_N_S_T_A_L_L 135 ddeeiinnssttaallll <_p_k_g_-_n_a_m_e> _P_O_S_T_-_D_E_I_N_S_T_A_L_L
133 after deleting them. Passing the keywords _V_I_E_W_-_D_E_I_N_S_T_A_L_L, _D_E_I_N_S_T_A_L_L and 136 after deleting them. Passing the keywords _V_I_E_W_-_D_E_I_N_S_T_A_L_L, _D_E_I_N_S_T_A_L_L and
134 _P_O_S_T_-_D_E_I_N_S_T_A_L_L lets you potentially write only one program/script that 137 _P_O_S_T_-_D_E_I_N_S_T_A_L_L lets you potentially write only one program/script that
135 handles all aspects of installation and deletion. 138 handles all aspects of installation and deletion.
136 139
137 All scripts are called with the environment variable PKG_PREFIX set to 140 All scripts are called with the environment variable PKG_PREFIX set to
138 the installation prefix (see the --pp option above). This allows a package 141 the installation prefix (see the --pp option above). This allows a package
139 author to write a script that reliably performs some action on the direc- 142 author to write a script that reliably performs some action on the direc-
140 tory where the package is installed, even if the user might have changed 143 tory where the package is installed, even if the user might have changed
141 it by specifying the --pp option when running ppkkgg__ddeelleettee or pkg_add(1). 144 it by specifying the --pp option when running ppkkgg__ddeelleettee or pkg_add(1).
142 The scripts are also called with the PKG_METADATA_DIR environment vari- 145 The scripts are also called with the PKG_METADATA_DIR environment vari-
143 able set to the location of the _+_* meta-data files, and with the 146 able set to the location of the _+_* meta-data files, and with the
144 PKG_REFCOUNT_DBDIR environment variable set to the location of the pack- 147 PKG_REFCOUNT_DBDIR environment variable set to the location of the pack-
145 age reference counts database directory. If the --PP flag was given to 148 age reference counts database directory. If the --PP flag was given to
146 ppkkgg__ddeelleettee, PKG_DESTDIR will be set to _d_e_s_t_d_i_r. 149 ppkkgg__ddeelleettee, PKG_DESTDIR will be set to _d_e_s_t_d_i_r.
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 (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,32 +1,32 @@ @@ -1,32 +1,32 @@
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 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
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_ */