2 * dpkg - main program for package management
3 * remove.c - functionality for removing packages
5 * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
7 * This is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
12 * This is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public
18 * License along with dpkg; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include <sys/types.h>
43 static void checkforremoval(struct pkginfo
*pkgtoremove
,
44 struct pkginfo
*pkgdepcheck
, /* may be virtual pkg */
45 int *rokp
, struct varbuf
*raemsgs
) {
46 struct deppossi
*possi
;
47 struct pkginfo
*depender
;
50 for (possi
= pkgdepcheck
->installed
.depended
; possi
; possi
= possi
->nextrev
) {
51 if (possi
->up
->type
!= dep_depends
&& possi
->up
->type
!= dep_predepends
) continue;
52 depender
= possi
->up
->up
;
53 debug(dbg_depcon
,"checking depending package `%s'",depender
->name
);
54 if (depender
->status
!= stat_installed
) continue;
55 if (ignore_depends(depender
)) {
56 debug(dbg_depcon
,"ignoring depending package `%s'\n",depender
->name
);
59 if (dependtry
> 1) { if (findbreakcycle(pkgdepcheck
,0)) sincenothing
= 0; }
60 before
= raemsgs
->used
;
61 ok
= dependencies_ok(depender
,pkgtoremove
,raemsgs
);
62 if (ok
== 0 && depender
->clientdata
->istobe
== itb_remove
) ok
= 1;
63 if (ok
== 1) raemsgs
->used
= before
; /* Don't burble about reasons for deferral */
64 if (ok
< *rokp
) *rokp
= ok
;
68 void deferred_remove(struct pkginfo
*pkg
) {
69 struct varbuf raemsgs
;
71 struct dependency
*dep
;
73 debug(dbg_general
,"deferred_remove package %s",pkg
->name
);
75 if (pkg
->status
== stat_notinstalled
) {
77 " - warning: ignoring request to remove %.250s which isn't installed.\n",
79 pkg
->clientdata
->istobe
= itb_normal
;
81 } else if (!f_pending
&&
82 pkg
->status
== stat_configfiles
&&
83 cipaction
->arg
!= act_purge
) {
85 " - warning: ignoring request to remove %.250s, only the config\n"
86 " files of which are on the system. Use --purge to remove them too.\n",
88 pkg
->clientdata
->istobe
= itb_normal
;
92 assert(pkg
->installed
.valid
);
93 if (pkg
->installed
.essential
&& pkg
->status
!= stat_configfiles
)
94 forcibleerr(fc_removeessential
, "This is an essential package -"
95 " it should not be removed.");
98 pkg
->want
= (cipaction
->arg
== act_purge
) ? want_purge
: want_deinstall
;
99 if (!f_noact
) modstatdb_note(pkg
);
101 debug(dbg_general
,"checking dependencies for remove `%s'",pkg
->name
);
102 varbufinit(&raemsgs
);
104 checkforremoval(pkg
,pkg
,&rok
,&raemsgs
);
105 for (dep
= pkg
->installed
.depends
; dep
; dep
= dep
->next
) {
106 if (dep
->type
!= dep_provides
) continue;
107 debug(dbg_depcon
,"checking virtual package `%s'",dep
->list
->ed
->name
);
108 checkforremoval(pkg
,dep
->list
->ed
,&rok
,&raemsgs
);
112 varbuffree(&raemsgs
);
113 pkg
->clientdata
->istobe
= itb_remove
;
116 } else if (rok
== 0) {
118 varbufaddc(&raemsgs
,0);
120 DPKG
": dependency problems prevent removal of %s:\n%s",
121 pkg
->name
, raemsgs
.buf
);
122 ohshit("dependency problems - not removing");
123 } else if (raemsgs
.used
) {
124 varbufaddc(&raemsgs
,0);
126 DPKG
": %s: dependency problems, but removing anyway as you request:\n%s",
127 pkg
->name
, raemsgs
.buf
);
129 varbuffree(&raemsgs
);
132 if (pkg
->eflag
& eflagf_reinstreq
)
133 forcibleerr(fc_removereinstreq
,
134 "Package is in a very bad inconsistent state - you should\n"
135 " reinstall it before attempting a removal.");
137 ensure_allinstfiles_available();
141 printf("Would remove or purge %s ...\n",pkg
->name
);
142 pkg
->status
= stat_notinstalled
;
143 pkg
->clientdata
->istobe
= itb_normal
;
147 oldconffsetflags(pkg
->installed
.conffiles
);
149 printf("Removing %s ...\n",pkg
->name
);
150 if (pkg
->status
== stat_halfconfigured
|| pkg
->status
== stat_installed
) {
152 if (pkg
->status
== stat_installed
|| pkg
->status
== stat_halfconfigured
) {
153 pkg
->status
= stat_halfconfigured
;
155 push_cleanup(cu_prermremove
,~ehflag_normaltidy
, 0,0, 1,(void*)pkg
);
156 maintainer_script_installed(pkg
, PRERMFILE
, "pre-removal",
160 pkg
->status
= stat_unpacked
; /* Will turn into halfinstalled soon ... */
166 static void push_leftover(struct fileinlist
**leftoverp
,
167 struct filenamenode
*namenode
) {
168 struct fileinlist
*newentry
;
169 newentry
= nfmalloc(sizeof(struct fileinlist
));
170 newentry
->next
= *leftoverp
;
171 newentry
->namenode
= namenode
;
172 *leftoverp
= newentry
;
175 void removal_bulk(struct pkginfo
*pkg
) {
176 /* This is used both by deferred_remove in this file, and at
177 * the end of process_archive in archives.c if it needs to finish
178 * removing a conflicting package.
180 static const char *const removeconffexts
[]= { REMOVECONFFEXTS
, 0 };
182 static struct varbuf fnvb
, removevb
;
184 int before
, r
, foundpostrm
, removevbbase
;
185 int infodirbaseused
, conffnameused
, conffbasenamelen
, pkgnameused
;
187 struct reversefilelistiter rlistit
;
188 struct conffile
*conff
, **lconffp
;
189 struct fileinlist
*searchfile
, *leftover
;
194 const char *const *ext
;
195 const char *postrmfilename
;
196 struct filenamenode
*namenode
;
198 debug(dbg_general
,"removal_bulk package %s",pkg
->name
);
200 if (pkg
->status
== stat_halfinstalled
|| pkg
->status
== stat_unpacked
) {
201 pkg
->status
= stat_halfinstalled
;
203 push_checkpoint(~ehflag_bombout
, ehflag_normaltidy
);
205 reversefilelist_init(&rlistit
,pkg
->clientdata
->files
);
207 while ((namenode
= reversefilelist_next(&rlistit
))) {
208 debug(dbg_eachfile
, "removal_bulk `%s' flags=%o",
209 namenode
->name
, namenode
->flags
);
210 if (namenode
->flags
& fnnf_old_conff
) {
211 push_leftover(&leftover
,namenode
);
215 varbufaddstr(&fnvb
,instdir
);
216 varbufaddstr(&fnvb
,namenodetouse(namenode
,pkg
)->name
);
219 varbufaddstr(&fnvb
,DPKGTEMPEXT
);
221 debug(dbg_eachfiledetail
, "removal_bulk cleaning temp `%s'", fnvb
.buf
);
223 ensure_pathname_nonexisting(fnvb
.buf
);
226 varbufaddstr(&fnvb
,DPKGNEWEXT
);
228 debug(dbg_eachfiledetail
, "removal_bulk cleaning new `%s'", fnvb
.buf
);
229 ensure_pathname_nonexisting(fnvb
.buf
);
233 if (!stat(fnvb
.buf
,&stab
) && S_ISDIR(stab
.st_mode
)) {
234 debug(dbg_eachfiledetail
, "removal_bulk is a directory");
235 /* Only delete a directory or a link to one if we're the only
236 * package which uses it. Other files should only be listed
237 * in this package (but we don't check).
239 if (isdirectoryinuse(namenode
,pkg
)) continue;
241 debug(dbg_eachfiledetail
, "removal_bulk removing `%s'", fnvb
.buf
);
242 if (!rmdir(fnvb
.buf
) || errno
== ENOENT
|| errno
== ELOOP
) continue;
243 if (errno
== ENOTEMPTY
) {
245 " - warning: while removing %.250s, directory `%.250s' not empty "
247 pkg
->name
, namenode
->name
);
248 push_leftover(&leftover
,namenode
);
250 } else if (errno
== EBUSY
|| errno
== EPERM
) {
251 fprintf(stderr
, DPKG
" - warning: while removing %.250s,"
252 " unable to remove directory `%.250s':"
253 " %s - directory may be a mount point ?\n",
254 pkg
->name
, namenode
->name
, strerror(errno
));
255 push_leftover(&leftover
,namenode
);
258 if (errno
!= ENOTDIR
) ohshite("cannot remove `%.250s'",fnvb
.buf
);
259 debug(dbg_eachfiledetail
, "removal_bulk unlinking `%s'", fnvb
.buf
);
260 if (unlink(fnvb
.buf
)) ohshite("cannot remove file `%.250s'",fnvb
.buf
);
262 write_filelist_except(pkg
,leftover
,0);
263 maintainer_script_installed(pkg
, POSTRMFILE
, "post-removal",
266 varbufaddstr(&fnvb
,admindir
);
267 varbufaddstr(&fnvb
,"/" INFODIR
);
268 infodirbaseused
= fnvb
.used
;
270 dsd
= opendir(fnvb
.buf
); if (!dsd
) ohshite("cannot read info directory");
271 push_cleanup(cu_closedir
,~0, 0,0, 1,(void*)dsd
);
274 debug(dbg_general
, "removal_bulk cleaning info directory");
276 while ((de
= readdir(dsd
)) != 0) {
277 debug(dbg_veryverbose
, "removal_bulk info file `%s'", de
->d_name
);
278 if (de
->d_name
[0] == '.') continue;
279 p
= strrchr(de
->d_name
,'.'); if (!p
) continue;
280 if (strlen(pkg
->name
) != p
-de
->d_name
||
281 strncmp(de
->d_name
,pkg
->name
,p
-de
->d_name
)) continue;
282 debug(dbg_stupidlyverbose
, "removal_bulk info this pkg");
283 /* We need the postrm and list files for --purge. */
284 if (!strcmp(p
+1,LISTFILE
)) continue;
285 if (!strcmp(p
+1,POSTRMFILE
)) { foundpostrm
=1; continue; }
286 debug(dbg_stupidlyverbose
, "removal_bulk info not postrm or list");
287 fnvb
.used
= infodirbaseused
;
288 varbufaddstr(&fnvb
,de
->d_name
);
290 if (unlink(fnvb
.buf
))
291 ohshite("unable to delete control info file `%.250s'",fnvb
.buf
);
292 debug(dbg_scripts
, "removal_bulk info unlinked %s",fnvb
.buf
);
294 pop_cleanup(ehflag_normaltidy
); /* closedir */
296 pkg
->status
= stat_configfiles
;
297 pkg
->installed
.essential
= 0;
299 push_checkpoint(~ehflag_bombout
, ehflag_normaltidy
);
303 postrmfilename
= pkgadminfile(pkg
,POSTRMFILE
);
304 if (!lstat(postrmfilename
,&stab
)) foundpostrm
= 1;
305 else if (errno
== ENOENT
) foundpostrm
= 0;
306 else ohshite("unable to check existence of `%.250s'",postrmfilename
);
310 debug(dbg_general
, "removal_bulk purging? foundpostrm=%d",foundpostrm
);
312 if (!foundpostrm
&& !pkg
->installed
.conffiles
) {
313 /* If there are no config files and no postrm script then we
314 * go straight into `purge'.
316 debug(dbg_general
, "removal_bulk no postrm, no conffiles, purging");
317 pkg
->want
= want_purge
;
319 } else if (pkg
->want
== want_purge
) {
321 printf("Purging configuration files for %s ...\n",pkg
->name
);
322 ensure_packagefiles_available(pkg
); /* We may have modified this above. */
324 /* We're about to remove the configuration, so remove the note
325 * about which version it was ...
327 blankversion(&pkg
->configversion
);
330 /* Remove from our list any conffiles that aren't ours any more or
331 * are involved in diversions, except if we are the package doing the
334 for (lconffp
= &pkg
->installed
.conffiles
;
335 (conff
= *lconffp
) != 0;
336 lconffp
= &conff
->next
) {
337 for (searchfile
= pkg
->clientdata
->files
;
338 searchfile
&& strcmp(searchfile
->namenode
->name
,conff
->name
);
339 searchfile
= searchfile
->next
);
341 debug(dbg_conff
,"removal_bulk conffile not ours any more `%s'",conff
->name
);
342 *lconffp
= conff
->next
;
343 } else if (searchfile
->namenode
->divert
&&
344 (searchfile
->namenode
->divert
->camefrom
||
345 (searchfile
->namenode
->divert
->useinstead
&&
346 searchfile
->namenode
->divert
->pkg
!= pkg
))) {
347 debug(dbg_conff
,"removal_bulk conffile `%s' ignored due to diversion\n",
349 *lconffp
= conff
->next
;
351 debug(dbg_conffdetail
,"removal_bulk set to new conffile `%s'",conff
->name
);
352 conff
->hash
= (char*)NEWCONFFILEFLAG
; /* yes, cast away const */
357 for (conff
= pkg
->installed
.conffiles
; conff
; conff
= conff
->next
) {
359 r
= conffderef(pkg
, &fnvb
, conff
->name
);
360 debug(dbg_conffdetail
, "removal_bulk conffile `%s' (= `%s')",
361 conff
->name
, r
== -1 ? "<r==-1>" : fnvb
.buf
);
362 if (r
== -1) continue;
363 conffnameused
= fnvb
.used
-1;
364 if (unlink(fnvb
.buf
) && errno
!= ENOENT
&& errno
!= ENOTDIR
)
365 ohshite("cannot remove old config file `%.250s' (= `%.250s')",
366 conff
->name
, fnvb
.buf
);
367 p
= strrchr(fnvb
.buf
,'/'); if (!p
) continue;
369 varbufreset(&removevb
);
370 varbufaddstr(&removevb
,fnvb
.buf
);
371 varbufaddc(&removevb
,'/');
372 removevbbase
= removevb
.used
;
373 varbufaddc(&removevb
,0);
374 dsd
= opendir(removevb
.buf
);
377 debug(dbg_conffdetail
, "removal_bulk conffile no dsd %s %s",
378 fnvb
.buf
, strerror(e
)); errno
= e
;
379 if (errno
== ENOENT
|| errno
== ENOTDIR
) continue;
380 ohshite("cannot read config file dir `%.250s' (from `%.250s')",
381 fnvb
.buf
, conff
->name
);
383 debug(dbg_conffdetail
, "removal_bulk conffile cleaning dsd %s", fnvb
.buf
);
384 push_cleanup(cu_closedir
,~0, 0,0, 1,(void*)dsd
);
386 conffbasenamelen
= strlen(++p
);
387 conffbasename
= fnvb
.buf
+conffnameused
-conffbasenamelen
;
388 while ((de
= readdir(dsd
)) != 0) {
389 debug(dbg_stupidlyverbose
, "removal_bulk conffile dsd entry=`%s'"
390 " conffbasename=`%s' conffnameused=%d conffbasenamelen=%d",
391 de
->d_name
, conffbasename
, conffnameused
, conffbasenamelen
);
392 if (!strncmp(de
->d_name
,conffbasename
,conffbasenamelen
)) {
393 debug(dbg_stupidlyverbose
, "removal_bulk conffile dsd entry starts right");
394 for (ext
= removeconffexts
; *ext
; ext
++)
395 if (!strcmp(*ext
,de
->d_name
+conffbasenamelen
)) goto yes_remove
;
396 p
= de
->d_name
+conffbasenamelen
;
398 while (*p
&& isdigit(*p
)) p
++;
399 if (*p
== '~' && !*++p
) goto yes_remove
;
402 debug(dbg_stupidlyverbose
, "removal_bulk conffile dsd entry starts wrong");
403 if (de
->d_name
[0] == '#' &&
404 !strncmp(de
->d_name
+1,conffbasename
,conffbasenamelen
) &&
405 !strcmp(de
->d_name
+1+conffbasenamelen
,"#"))
407 debug(dbg_stupidlyverbose
, "removal_bulk conffile dsd entry not it");
410 removevb
.used
= removevbbase
;
411 varbufaddstr(&removevb
,de
->d_name
); varbufaddc(&removevb
,0);
412 debug(dbg_conffdetail
, "removal_bulk conffile dsd entry removing `%s'",
414 if (unlink(removevb
.buf
) && errno
!= ENOENT
&& errno
!= ENOTDIR
)
415 ohshite("cannot remove old backup config file `%.250s' (of `%.250s')",
416 removevb
.buf
, conff
->name
);
418 pop_cleanup(ehflag_normaltidy
); /* closedir */
422 pkg
->installed
.conffiles
= 0;
425 maintainer_script_installed(pkg
, POSTRMFILE
, "post-removal",
428 /* fixme: retry empty directories */
432 if (pkg
->want
== want_purge
) {
434 /* ie, either of the two branches above. */
436 varbufaddstr(&fnvb
,admindir
);
437 varbufaddstr(&fnvb
,"/" INFODIR
);
438 varbufaddstr(&fnvb
,pkg
->name
);
439 pkgnameused
= fnvb
.used
;
441 varbufaddstr(&fnvb
,"." LISTFILE
);
443 debug(dbg_general
, "removal_bulk purge done, removing list `%s'",fnvb
.buf
);
444 if (unlink(fnvb
.buf
) && errno
!= ENOENT
) ohshite("cannot remove old files list");
446 fnvb
.used
= pkgnameused
;
447 varbufaddstr(&fnvb
,"." POSTRMFILE
);
449 debug(dbg_general
, "removal_bulk purge done, removing postrm `%s'",fnvb
.buf
);
450 if (unlink(fnvb
.buf
) && errno
!= ENOENT
) ohshite("can't remove old postrm script");
452 pkg
->status
= stat_notinstalled
;
454 /* This will mess up reverse links, but if we follow them
455 * we won't go back because pkg->status is stat_notinstalled.
457 pkg
->installed
.depends
= 0;
458 pkg
->installed
.essential
= 0;
459 pkg
->installed
.description
= pkg
->installed
.maintainer
= 0;
460 pkg
->installed
.source
= pkg
->installed
.installedsize
= 0;
461 blankversion(&pkg
->installed
.version
);
462 pkg
->installed
.arbs
= 0;
465 pkg
->eflag
= eflagv_ok
;
468 debug(dbg_general
, "removal done");