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