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