Fix formatting issues found with the last commit.
[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 n_deps;
174         pkg_t *p;
175         struct compound_depend *cdep;
176         abstract_pkg_t **dependents;
177
178         int count = pkg->pre_depends_count +
179                                 pkg->depends_count +
180                                 pkg->recommends_count +
181                                 pkg->suggests_count;
182
183         for (i=0; i<count; i++) {
184                 cdep = &pkg->depends[i];
185                 if (cdep->type != PREDEPEND
186                     && cdep->type != DEPEND
187                     && cdep->type != RECOMMEND)
188                         continue;
189                 for (j=0; j<cdep->possibility_count; j++) {
190                         p = pkg_hash_fetch_installed_by_name(
191                                         cdep->possibilities[j]->pkg->name);
192
193                         /* If the package is not installed, this could have
194                          * been a circular dependency and the package has
195                          * already been removed.
196                          */
197                         if (!p)
198                                 return -1;
199
200                         if (!p->auto_installed)
201                                 continue;
202
203                         n_deps = pkg_has_installed_dependents(p, &dependents);
204                         if (n_deps == 0) {
205                                  opkg_msg(NOTICE, "%s was autoinstalled and is "
206                                                "now orphaned, removing.\n",
207                                                p->name);
208                                  opkg_remove_pkg(p, 0);
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 0;
221 }
222
223 int
224 opkg_remove_pkg(pkg_t *pkg, int from_upgrade)
225 {
226      int err;
227      abstract_pkg_t *parent_pkg = NULL;
228
229 /*
230  * If called from an upgrade and not from a normal remove,
231  * ignore the essential flag.
232  */
233      if (pkg->essential && !from_upgrade) {
234           if (conf->force_removal_of_essential_packages) {
235                opkg_msg(NOTICE,
236                        "Removing essential package %s under your coercion.\n"
237                        "\tIf your system breaks, you get to keep both pieces\n",
238                        pkg->name);
239           } else {
240                opkg_msg(NOTICE, "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
257          && !(pkg->state_flag & SF_REPLACE)) {
258           abstract_pkg_t **dependents;
259           int has_installed_dependents =
260                pkg_has_installed_dependents(pkg, &dependents);
261
262           if (has_installed_dependents) {
263                /*
264                 * if this package is depended upon by others, then either we should
265                 * not remove it or we should remove it and all of its dependents
266                 */
267
268                if (!conf->force_removal_of_dependent_packages) {
269                     print_dependents_warning(pkg, dependents);
270                     free(dependents);
271                     return -1;
272                }
273
274                /* remove packages depending on this package - Karthik */
275                err = opkg_remove_dependent_pkgs(pkg, dependents);
276                if (err) {
277                  free(dependents);
278                  return err;
279                }
280           }
281           if (dependents)
282               free(dependents);
283      }
284
285      if (from_upgrade == 0) {
286          opkg_msg(NOTICE, "Removing package %s from %s...\n",
287                          pkg->name, pkg->dest->name);
288      }
289      pkg->state_flag |= SF_FILELIST_CHANGED;
290
291      pkg->state_want = SW_DEINSTALL;
292      opkg_state_changed++;
293
294      pkg_run_script(pkg, "prerm", "remove");
295
296      /* DPKG_INCOMPATIBILITY: dpkg is slightly different here. It
297         maintains an empty filelist rather than deleting it. That seems
298         like a big pain, and I don't see that that should make a big
299         difference, but for anyone who wants tighter compatibility,
300         feel free to fix this. */
301      remove_data_files_and_list(pkg);
302
303      pkg_run_script(pkg, "postrm", "remove");
304
305      remove_maintainer_scripts(pkg);
306      pkg->state_status = SS_NOT_INSTALLED;
307
308      if (parent_pkg)
309           parent_pkg->state_status = SS_NOT_INSTALLED;
310
311      /* remove autoinstalled packages that are orphaned by the removal of this one */
312      if (conf->autoremove)
313        remove_autoinstalled(pkg);
314
315      return 0;
316 }
317
318 void
319 remove_data_files_and_list(pkg_t *pkg)
320 {
321      str_list_t installed_dirs;
322      str_list_t *installed_files;
323      str_list_elt_t *iter;
324      char *file_name;
325      conffile_t *conffile;
326      int removed_a_dir;
327      pkg_t *owner;
328      int rootdirlen = 0;
329
330      installed_files = pkg_get_installed_files(pkg);
331      if (installed_files == NULL) {
332              opkg_msg(ERROR, "Failed to determine installed "
333                      "files for %s. None removed.\n", pkg->name);
334              return;
335      }
336
337      str_list_init(&installed_dirs);
338
339      /* don't include trailing slash */
340      if (conf->offline_root)
341           rootdirlen = strlen(conf->offline_root);
342
343      for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
344           file_name = (char *)iter->data;
345
346           owner = file_hash_get_file_owner(file_name);
347           if (owner != pkg)
348                   /* File may have been claimed by another package. */
349                   continue;
350
351           if (file_is_dir(file_name)) {
352                str_list_append(&installed_dirs, file_name);
353                continue;
354           }
355
356           conffile = pkg_get_conffile(pkg, file_name+rootdirlen);
357           if (conffile) {
358                if (conffile_has_been_modified(conffile)) {
359                     opkg_msg(NOTICE, "Not deleting modified conffile %s.\n",
360                                     file_name);
361                     continue;
362                }
363           }
364
365           if (!conf->noaction) {
366                 opkg_msg(INFO, "Deleting %s.\n", file_name);
367                unlink(file_name);
368           } else
369                 opkg_msg(INFO, "Not deleting %s. (noaction)\n",
370                                 file_name);
371
372           file_hash_remove(file_name);
373      }
374
375      /* Remove empty directories */
376      if (!conf->noaction) {
377           do {
378                removed_a_dir = 0;
379                for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) {
380                     file_name = (char *)iter->data;
381
382                     if (rmdir(file_name) == 0) {
383                          opkg_msg(INFO, "Deleting %s.\n", file_name);
384                          removed_a_dir = 1;
385                          str_list_remove(&installed_dirs, &iter);
386                     }
387                }
388           } while (removed_a_dir);
389      }
390
391      pkg_free_installed_files(pkg);
392      pkg_remove_installed_files_list(pkg);
393
394      /* Don't print warning for dirs that are provided by other packages */
395      for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) {
396           file_name = (char *)iter->data;
397
398           owner = file_hash_get_file_owner(file_name);
399           if (owner) {
400                free(iter->data);
401                iter->data = NULL;
402                str_list_remove(&installed_dirs, &iter);
403           }
404      }
405
406      /* cleanup */
407      while (!void_list_empty(&installed_dirs)) {
408         iter = str_list_pop(&installed_dirs);
409         free(iter->data);
410         free(iter);
411      }
412      str_list_deinit(&installed_dirs);
413 }
414
415 void
416 remove_maintainer_scripts(pkg_t *pkg)
417 {
418         int i, err;
419         char *globpattern;
420         glob_t globbuf;
421
422         if (conf->noaction)
423                 return;
424
425         sprintf_alloc(&globpattern, "%s/%s.*",
426                         pkg->dest->info_dir, pkg->name);
427
428         err = glob(globpattern, 0, NULL, &globbuf);
429         free(globpattern);
430         if (err)
431                 return;
432
433         for (i = 0; i < globbuf.gl_pathc; i++) {
434                 opkg_msg(INFO, "Deleting %s.\n", globbuf.gl_pathv[i]);
435                 unlink(globbuf.gl_pathv[i]);
436         }
437         globfree(&globbuf);
438 }