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