Remove str_util.{c,h}
[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      str_list_init(&installed_dirs);
333      installed_files = pkg_get_installed_files(conf, pkg);
334
335      /* don't include trailing slash */
336      if (conf->offline_root)
337           rootdirlen = strlen(conf->offline_root);
338
339      for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
340           file_name = (char *)iter->data;
341
342           if (file_is_dir(file_name)) {
343                str_list_append(&installed_dirs, file_name);
344                continue;
345           }
346
347           conffile = pkg_get_conffile(pkg, file_name+rootdirlen);
348           if (conffile) {
349                if (conffile_has_been_modified(conf, conffile)) {
350                     opkg_message (conf, OPKG_NOTICE,
351                                   "  not deleting modified conffile %s\n", file_name);
352                     continue;
353                }
354           }
355
356           opkg_message(conf, OPKG_INFO, "  deleting %s (noaction=%d)\n", file_name, conf->noaction);
357           if (!conf->noaction)
358                unlink(file_name);
359      }
360
361      /* Remove empty directories */
362      if (!conf->noaction) {
363           do {
364                removed_a_dir = 0;
365                for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) {
366                     file_name = (char *)iter->data;
367             
368                     if (rmdir(file_name) == 0) {
369                          opkg_message(conf, OPKG_INFO, "  deleting %s\n", file_name);
370                          removed_a_dir = 1;
371                          str_list_remove(&installed_dirs, &iter);
372                     }
373                }
374           } while (removed_a_dir);
375      }
376
377      pkg_free_installed_files(pkg);
378      pkg_remove_installed_files_list(conf, pkg);
379
380      /* Don't print warning for dirs that are provided by other packages */
381      for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) {
382           file_name = (char *)iter->data;
383
384           owner = file_hash_get_file_owner(conf, file_name);
385           if (owner) {
386                free(iter->data);
387                iter->data = NULL;
388                str_list_remove(&installed_dirs, &iter);
389           }
390      }
391
392      /* cleanup */
393      while (!void_list_empty(&installed_dirs)) {
394         iter = str_list_pop(&installed_dirs);
395         free(iter->data);
396         free(iter);
397      }
398      str_list_deinit(&installed_dirs);
399 }
400
401 void
402 remove_maintainer_scripts(opkg_conf_t *conf, pkg_t *pkg)
403 {
404         int i, err;
405         char *globpattern;
406         glob_t globbuf;
407
408         if (conf->noaction)
409                 return;
410
411         sprintf_alloc(&globpattern, "%s/%s.*",
412                         pkg->dest->info_dir, pkg->name);
413
414         err = glob(globpattern, 0, NULL, &globbuf);
415         free(globpattern);
416         if (err)
417                 return;
418
419         for (i = 0; i < globbuf.gl_pathc; i++) {
420                 opkg_message(conf, OPKG_INFO, "deleting %s\n",
421                                 globbuf.gl_pathv[i]);
422                 unlink(globbuf.gl_pathv[i]);
423         }
424         globfree(&globbuf);
425 }