694c3f3edc23689ce283e23834856cfd83c2495a
[project/opkg-lede.git] / libopkg / opkg_remove.c
1 /* opkg_remove.c - the opkg package management system
2
3 Carl D. Worth
4
5 Copyright (C) 2001 University of Southern California
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 This program 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 GNU
15 General Public License for more details.
16 */
17
18 #include <stdio.h>
19 #include <glob.h>
20 #include <unistd.h>
21
22 #include "opkg_message.h"
23 #include "opkg_remove.h"
24 #include "opkg_cmd.h"
25 #include "file_util.h"
26 #include "sprintf_alloc.h"
27 #include "libbb/libbb.h"
28
29 /*
30 * Returns number of the number of packages depending on the packages provided by this package.
31 * Every package implicitly provides itself.
32 */
33 int pkg_has_installed_dependents(pkg_t * pkg, abstract_pkg_t *** pdependents)
34 {
35 abstract_pkg_t **provider, **provides = pkg_get_ptr(pkg, PKG_PROVIDES);
36 unsigned int i, n_installed_dependents = 0;
37
38 provider = provides;
39
40 while (provider && *provider) {
41 abstract_pkg_t *providee = *provider++;
42 abstract_pkg_t **dependers = providee->depended_upon_by;
43 abstract_pkg_t *dep_ab_pkg;
44 if (dependers == NULL)
45 continue;
46 while ((dep_ab_pkg = *dependers++) != NULL) {
47 if (dep_ab_pkg->state_status == SS_INSTALLED) {
48 n_installed_dependents++;
49 }
50 }
51 }
52
53 /* if caller requested the set of installed dependents */
54 if (pdependents) {
55 int p = 0;
56 abstract_pkg_t **dependents =
57 xcalloc((n_installed_dependents + 1),
58 sizeof(abstract_pkg_t *));
59
60 provider = provides;
61 *pdependents = dependents;
62
63 while (provider && *provider) {
64 abstract_pkg_t *providee = *provider++;
65 abstract_pkg_t **dependers = providee->depended_upon_by;
66 abstract_pkg_t *dep_ab_pkg;
67 if (dependers == NULL)
68 continue;
69 while ((dep_ab_pkg = *dependers++) != NULL) {
70 if (dep_ab_pkg->state_status == SS_INSTALLED
71 && !(dep_ab_pkg->state_flag & SF_MARKED)) {
72 dependents[p++] = dep_ab_pkg;
73 dep_ab_pkg->state_flag |= SF_MARKED;
74 }
75 }
76 }
77 dependents[p] = NULL;
78 /* now clear the marks */
79 for (i = 0; i < p; i++) {
80 abstract_pkg_t *dep_ab_pkg = dependents[i];
81 dep_ab_pkg->state_flag &= ~SF_MARKED;
82 }
83 }
84 return n_installed_dependents;
85 }
86
87 static int opkg_remove_dependent_pkgs(pkg_t * pkg, abstract_pkg_t ** dependents)
88 {
89 int i;
90 int a;
91 int count;
92 pkg_vec_t *dependent_pkgs;
93 abstract_pkg_t *ab_pkg;
94
95 if ((ab_pkg = pkg->parent) == NULL) {
96 opkg_msg(ERROR, "Internal error: pkg %s isn't in hash table\n",
97 pkg->name);
98 return 0;
99 }
100
101 if (dependents == NULL)
102 return 0;
103
104 // here i am using the dependencies_checked
105 if (ab_pkg->dependencies_checked == 2) // variable to make out whether this package
106 return 0; // has already been encountered in the process
107 // of marking packages for removal - Karthik
108 ab_pkg->dependencies_checked = 2;
109
110 i = 0;
111 count = 1;
112 dependent_pkgs = pkg_vec_alloc();
113
114 while (dependents[i] != NULL) {
115 abstract_pkg_t *dep_ab_pkg = dependents[i];
116
117 if (dep_ab_pkg->dependencies_checked == 2) {
118 i++;
119 continue;
120 }
121 if (dep_ab_pkg->state_status == SS_INSTALLED) {
122 for (a = 0; a < dep_ab_pkg->pkgs->len; a++) {
123 pkg_t *dep_pkg = dep_ab_pkg->pkgs->pkgs[a];
124 if (dep_pkg->state_status == SS_INSTALLED) {
125 pkg_vec_insert(dependent_pkgs, dep_pkg);
126 count++;
127 }
128 }
129 }
130 i++;
131 /* 1 - to keep track of visited ab_pkgs when checking for possiblility of a broken removal of pkgs.
132 * 2 - to keep track of pkgs whose deps have been checked alrdy - Karthik */
133 }
134
135 if (count == 1) {
136 pkg_vec_free(dependent_pkgs);
137 return 0;
138 }
139
140 int err = 0;
141 for (i = 0; i < dependent_pkgs->len; i++) {
142 err = opkg_remove_pkg(dependent_pkgs->pkgs[i], 0);
143 if (err) {
144 break;
145 }
146 }
147 pkg_vec_free(dependent_pkgs);
148 return err;
149 }
150
151 static void print_dependents_warning(pkg_t * pkg, abstract_pkg_t ** dependents)
152 {
153 abstract_pkg_t *dep_ab_pkg;
154 opkg_msg(ERROR, "Package %s is depended upon by packages:\n",
155 pkg->name);
156 while ((dep_ab_pkg = *dependents++) != NULL) {
157 if (dep_ab_pkg->state_status == SS_INSTALLED)
158 opkg_msg(ERROR, "\t%s\n", dep_ab_pkg->name);
159 }
160 opkg_msg(ERROR,
161 "These might cease to work if package %s is removed.\n\n",
162 pkg->name);
163 opkg_msg(ERROR,
164 "Force removal of this package with --force-depends.\n");
165 opkg_msg(ERROR, "Force removal of this package and its dependents\n");
166 opkg_msg(ERROR, "with --force-removal-of-dependent-packages.\n");
167 }
168
169 /*
170 * Find and remove packages that were autoinstalled and are orphaned
171 * by the removal of pkg.
172 */
173 static int remove_autoinstalled(pkg_t * pkg)
174 {
175 int j;
176 int err = 0;
177 int n_deps;
178 pkg_t *p;
179 struct compound_depend *cdep;
180 abstract_pkg_t **dependents;
181
182 for (cdep = pkg_get_ptr(pkg, PKG_DEPENDS); cdep && cdep->type; cdep++) {
183 if (cdep->type != PREDEPEND
184 && cdep->type != DEPEND && cdep->type != RECOMMEND)
185 continue;
186 for (j = 0; j < cdep->possibility_count; j++) {
187 p = pkg_hash_fetch_installed_by_name(cdep->
188 possibilities[j]->
189 pkg->name);
190
191 /* If the package is not installed, this could have
192 * been a circular dependency and the package has
193 * already been removed.
194 */
195 if (!p)
196 return -1;
197
198 if (!p->auto_installed)
199 continue;
200
201 n_deps = pkg_has_installed_dependents(p, &dependents);
202 if (n_deps == 0) {
203 opkg_msg(NOTICE, "%s was autoinstalled and is "
204 "now orphaned, removing.\n", p->name);
205 if (opkg_remove_pkg(p, 0) != 0) {
206 err = -1;
207 }
208 } else
209 opkg_msg(INFO, "%s was autoinstalled and is "
210 "still required by %d "
211 "installed packages.\n",
212 p->name, n_deps);
213
214 if (dependents)
215 free(dependents);
216 }
217 }
218
219 return err;
220 }
221
222 int opkg_remove_pkg(pkg_t * pkg, int from_upgrade)
223 {
224 int err;
225 abstract_pkg_t *parent_pkg = NULL;
226
227 /*
228 * If called from an upgrade and not from a normal remove,
229 * ignore the essential flag.
230 */
231 if (pkg->essential && !from_upgrade) {
232 if (conf->force_removal_of_essential_packages) {
233 opkg_msg(NOTICE,
234 "Removing essential package %s under your coercion.\n"
235 "\tIf your system breaks, you get to keep both pieces\n",
236 pkg->name);
237 } else {
238 opkg_msg(NOTICE,
239 "Refusing to remove essential package %s.\n"
240 "\tRemoving an essential package may lead to an unusable system, but if\n"
241 "\tyou enjoy that kind of pain, you can force opkg to proceed against\n"
242 "\tits will with the option: --force-removal-of-essential-packages\n",
243 pkg->name);
244 return -1;
245 }
246 }
247
248 if ((parent_pkg = pkg->parent) == NULL)
249 return 0;
250
251 /* only attempt to remove dependent installed packages if
252 * force_depends is not specified or the package is being
253 * replaced.
254 */
255 if (!conf->force_depends && !(pkg->state_flag & SF_REPLACE)) {
256 abstract_pkg_t **dependents;
257 int has_installed_dependents =
258 pkg_has_installed_dependents(pkg, &dependents);
259
260 if (has_installed_dependents) {
261 /*
262 * if this package is depended upon by others, then either we should
263 * not remove it or we should remove it and all of its dependents
264 */
265
266 if (!conf->force_removal_of_dependent_packages) {
267 print_dependents_warning(pkg, dependents);
268 free(dependents);
269 return -1;
270 }
271
272 /* remove packages depending on this package - Karthik */
273 err = opkg_remove_dependent_pkgs(pkg, dependents);
274 if (err) {
275 free(dependents);
276 return err;
277 }
278 }
279 if (dependents)
280 free(dependents);
281 }
282
283 if (from_upgrade == 0) {
284 opkg_msg(NOTICE, "Removing package %s from %s...\n",
285 pkg->name, pkg->dest->name);
286 }
287 pkg->state_flag |= SF_FILELIST_CHANGED;
288
289 pkg->state_want = SW_DEINSTALL;
290 opkg_state_changed++;
291
292 if (pkg_run_script(pkg, "prerm", "remove") != 0) {
293 if (!conf->force_remove) {
294 opkg_msg(ERROR, "not removing package \"%s\", "
295 "prerm script failed\n", pkg->name);
296 opkg_msg(NOTICE,
297 "You can force removal of packages with failed "
298 "prerm scripts with the option: \n"
299 "\t--force-remove\n");
300 return -1;
301 }
302 }
303
304 /* DPKG_INCOMPATIBILITY: dpkg is slightly different here. It
305 maintains an empty filelist rather than deleting it. That seems
306 like a big pain, and I don't see that that should make a big
307 difference, but for anyone who wants tighter compatibility,
308 feel free to fix this. */
309 remove_data_files_and_list(pkg);
310
311 err = pkg_run_script(pkg, "postrm", "remove");
312
313 remove_maintainer_scripts(pkg);
314 pkg->state_status = SS_NOT_INSTALLED;
315
316 if (parent_pkg)
317 parent_pkg->state_status = SS_NOT_INSTALLED;
318
319 /* remove autoinstalled packages that are orphaned by the removal of this one */
320 if (conf->autoremove) {
321 if (remove_autoinstalled(pkg) != 0) {
322 err = -1;
323 }
324 }
325 return err;
326 }
327
328 void remove_data_files_and_list(pkg_t * pkg)
329 {
330 str_list_t installed_dirs;
331 str_list_t *installed_files;
332 str_list_elt_t *iter;
333 char *file_name;
334 conffile_t *conffile;
335 int removed_a_dir;
336 pkg_t *owner;
337 int rootdirlen = 0;
338
339 installed_files = pkg_get_installed_files(pkg);
340 if (installed_files == NULL) {
341 opkg_msg(ERROR, "Failed to determine installed "
342 "files for %s. None removed.\n", pkg->name);
343 return;
344 }
345
346 str_list_init(&installed_dirs);
347
348 /* don't include trailing slash */
349 if (conf->offline_root)
350 rootdirlen = strlen(conf->offline_root);
351
352 for (iter = str_list_first(installed_files); iter;
353 iter = str_list_next(installed_files, iter)) {
354 file_name = (char *)iter->data;
355
356 owner = file_hash_get_file_owner(file_name);
357 if (owner != pkg)
358 /* File may have been claimed by another package. */
359 continue;
360
361 if (file_is_dir(file_name)) {
362 str_list_append(&installed_dirs, file_name);
363 continue;
364 }
365
366 conffile = pkg_get_conffile(pkg, file_name + rootdirlen);
367 if (conffile) {
368 if (conffile_has_been_modified(conffile)) {
369 opkg_msg(NOTICE,
370 "Not deleting modified conffile %s.\n",
371 file_name);
372 continue;
373 }
374 }
375
376 if (!conf->noaction) {
377 opkg_msg(INFO, "Deleting %s.\n", file_name);
378 unlink(file_name);
379 } else
380 opkg_msg(INFO, "Not deleting %s. (noaction)\n",
381 file_name);
382
383 file_hash_remove(file_name);
384 }
385
386 /* Remove empty directories */
387 if (!conf->noaction) {
388 do {
389 removed_a_dir = 0;
390 for (iter = str_list_first(&installed_dirs); iter;
391 iter = str_list_next(&installed_dirs, iter)) {
392 file_name = (char *)iter->data;
393
394 if (rmdir(file_name) == 0) {
395 opkg_msg(INFO, "Deleting %s.\n",
396 file_name);
397 removed_a_dir = 1;
398 str_list_remove(&installed_dirs, &iter);
399 }
400 }
401 } while (removed_a_dir);
402 }
403
404 pkg_free_installed_files(pkg);
405 pkg_remove_installed_files_list(pkg);
406
407 /* Don't print warning for dirs that are provided by other packages */
408 for (iter = str_list_first(&installed_dirs); iter;
409 iter = str_list_next(&installed_dirs, iter)) {
410 file_name = (char *)iter->data;
411
412 owner = file_hash_get_file_owner(file_name);
413 if (owner) {
414 free(iter->data);
415 iter->data = NULL;
416 str_list_remove(&installed_dirs, &iter);
417 }
418 }
419
420 /* cleanup */
421 while (!void_list_empty(&installed_dirs)) {
422 iter = str_list_pop(&installed_dirs);
423 free(iter->data);
424 free(iter);
425 }
426 str_list_deinit(&installed_dirs);
427 }
428
429 void remove_maintainer_scripts(pkg_t * pkg)
430 {
431 int i, err;
432 char *globpattern;
433 glob_t globbuf;
434
435 if (conf->noaction)
436 return;
437
438 sprintf_alloc(&globpattern, "%s/%s.*", pkg->dest->info_dir, pkg->name);
439
440 err = glob(globpattern, 0, NULL, &globbuf);
441 free(globpattern);
442 if (err)
443 return;
444
445 for (i = 0; i < globbuf.gl_pathc; i++) {
446 opkg_msg(INFO, "Deleting %s.\n", globbuf.gl_pathv[i]);
447 unlink(globbuf.gl_pathv[i]);
448 }
449 globfree(&globbuf);
450 }