b5045ea9905263cdc5ce0bcd149c82e5043d759e
[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_cmd.h"
25
26 #include "file_util.h"
27 #include "sprintf_alloc.h"
28 #include "libbb/libbb.h"
29
30 /*
31  * Returns number of the number of packages depending on the packages provided by this package.
32  * Every package implicitly provides itself.
33  */
34 int
35 pkg_has_installed_dependents(pkg_t *pkg, abstract_pkg_t *** pdependents)
36 {
37      int nprovides = pkg->provides_count;
38      abstract_pkg_t **provides = pkg->provides;
39      unsigned int n_installed_dependents = 0;
40      int i;
41      for (i = 0; i < nprovides; i++) {
42           abstract_pkg_t *providee = provides[i];
43           abstract_pkg_t **dependers = providee->depended_upon_by;
44           abstract_pkg_t *dep_ab_pkg;
45           if (dependers == NULL)
46                continue;
47           while ((dep_ab_pkg = *dependers++) != NULL) {
48                if (dep_ab_pkg->state_status == SS_INSTALLED){
49                     n_installed_dependents++;
50                }
51           }
52
53      }
54      /* if caller requested the set of installed dependents */
55      if (pdependents) {
56           int p = 0;
57           abstract_pkg_t **dependents = xcalloc((n_installed_dependents+1), 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 && !(dep_ab_pkg->state_flag & SF_MARKED)) {
68                          dependents[p++] = dep_ab_pkg;
69                          dep_ab_pkg->state_flag |= SF_MARKED;
70                     }
71                }
72           }
73           dependents[p] = NULL;
74           /* now clear the marks */
75           for (i = 0; i < p; i++) {
76                abstract_pkg_t *dep_ab_pkg = dependents[i];
77                dep_ab_pkg->state_flag &= ~SF_MARKED;
78           }
79      }
80      return n_installed_dependents;
81 }
82
83 static int
84 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     
138     int err=0;
139     for (i = 0; i < dependent_pkgs->len; i++) {
140         err = opkg_remove_pkg(dependent_pkgs->pkgs[i],0);
141         if (err) {
142             pkg_vec_free(dependent_pkgs);
143             break;
144         }
145     }
146     pkg_vec_free(dependent_pkgs);
147     return err;
148 }
149
150 static void
151 print_dependents_warning(pkg_t *pkg, abstract_pkg_t **dependents)
152 {
153     abstract_pkg_t *dep_ab_pkg;
154     opkg_msg(ERROR, "Package %s is depended upon by packages:\n", pkg->name);
155     while ((dep_ab_pkg = *dependents++) != NULL) {
156          if (dep_ab_pkg->state_status == SS_INSTALLED)
157               opkg_msg(ERROR, "\t%s\n", dep_ab_pkg->name);
158     }
159     opkg_msg(ERROR, "These might cease to work if package %s is removed.\n\n",
160                     pkg->name);
161     opkg_msg(ERROR, "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
171 remove_autoinstalled(pkg_t *pkg)
172 {
173         int i, j;
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 != DEPEND)
187                         continue;
188                 for (j=0; j<cdep->possibility_count; j++) {
189                         p = pkg_hash_fetch_installed_by_name(
190                                         cdep->possibilities[j]->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",
206                                                p->name);
207                                  opkg_remove_pkg(p, 0);
208                         } else
209                                 opkg_msg(INFO, "%s was autoinstalled and is "
210                                                 "still required by %d "
211                                                 "installed packages.\n",
212                                                 p->name, n_deps);
213
214                         if (dependents)
215                                 free(dependents);
216                 }
217         }
218
219         return 0;
220 }
221
222 int
223 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, "Refusing to remove essential package %s.\n"
240                        "\tRemoving an essential package may lead to an unusable system, but if\n"
241                        "\tyou enjoy that kind of pain, you can force opkg to proceed against\n"
242                        "\tits will with the option: --force-removal-of-essential-packages\n",
243                        pkg->name);
244                return -1;
245           }
246      }
247
248      if ((parent_pkg = pkg->parent) == NULL)
249           return 0;
250
251      /* only attempt to remove dependent installed packages if
252       * force_depends is not specified or the package is being
253       * replaced.
254       */
255      if (!conf->force_depends
256          && !(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      pkg_run_script(pkg, "prerm", "remove");
294
295      /* DPKG_INCOMPATIBILITY: dpkg is slightly different here. It
296         maintains an empty filelist rather than deleting it. That seems
297         like a big pain, and I don't see that that should make a big
298         difference, but for anyone who wants tighter compatibility,
299         feel free to fix this. */
300      remove_data_files_and_list(pkg);
301
302      pkg_run_script(pkg, "postrm", "remove");
303
304      remove_maintainer_scripts(pkg);
305      pkg->state_status = SS_NOT_INSTALLED;
306
307      if (parent_pkg) 
308           parent_pkg->state_status = SS_NOT_INSTALLED;
309
310      /* remove autoinstalled packages that are orphaned by the removal of this one */
311      if (conf->autoremove)
312        remove_autoinstalled(pkg);
313
314      return 0;
315 }
316
317 void
318 remove_data_files_and_list(pkg_t *pkg)
319 {
320      str_list_t installed_dirs;
321      str_list_t *installed_files;
322      str_list_elt_t *iter;
323      char *file_name;
324      conffile_t *conffile;
325      int removed_a_dir;
326      pkg_t *owner;
327      int rootdirlen = 0;
328
329      installed_files = pkg_get_installed_files(pkg);
330      if (installed_files == NULL) {
331              opkg_msg(ERROR, "Failed to determine installed "
332                      "files for %s. None removed.\n", pkg->name);
333              return;
334      }
335
336      str_list_init(&installed_dirs);
337
338      /* don't include trailing slash */
339      if (conf->offline_root)
340           rootdirlen = strlen(conf->offline_root);
341
342      for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
343           file_name = (char *)iter->data;
344
345           if (file_is_dir(file_name)) {
346                str_list_append(&installed_dirs, file_name);
347                continue;
348           }
349
350           conffile = pkg_get_conffile(pkg, file_name+rootdirlen);
351           if (conffile) {
352                if (conffile_has_been_modified(conffile)) {
353                     opkg_msg(NOTICE, "Not deleting modified conffile %s.\n",
354                                     file_name);
355                     continue;
356                }
357           }
358
359           if (!conf->noaction) {
360                 opkg_msg(INFO, "Deleting %s.\n", file_name, conf->noaction);
361                unlink(file_name);
362           } else
363                 opkg_msg(INFO, "Not deleting %s. (noaction)\n",
364                                 file_name);
365
366      }
367
368      /* Remove empty directories */
369      if (!conf->noaction) {
370           do {
371                removed_a_dir = 0;
372                for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) {
373                     file_name = (char *)iter->data;
374             
375                     if (rmdir(file_name) == 0) {
376                          opkg_msg(INFO, "Deleting %s.\n", file_name);
377                          removed_a_dir = 1;
378                          str_list_remove(&installed_dirs, &iter);
379                     }
380                }
381           } while (removed_a_dir);
382      }
383
384      pkg_free_installed_files(pkg);
385      pkg_remove_installed_files_list(pkg);
386
387      /* Don't print warning for dirs that are provided by other packages */
388      for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) {
389           file_name = (char *)iter->data;
390
391           owner = file_hash_get_file_owner(file_name);
392           if (owner) {
393                free(iter->data);
394                iter->data = NULL;
395                str_list_remove(&installed_dirs, &iter);
396           }
397      }
398
399      /* cleanup */
400      while (!void_list_empty(&installed_dirs)) {
401         iter = str_list_pop(&installed_dirs);
402         free(iter->data);
403         free(iter);
404      }
405      str_list_deinit(&installed_dirs);
406 }
407
408 void
409 remove_maintainer_scripts(pkg_t *pkg)
410 {
411         int i, err;
412         char *globpattern;
413         glob_t globbuf;
414
415         if (conf->noaction)
416                 return;
417
418         sprintf_alloc(&globpattern, "%s/%s.*",
419                         pkg->dest->info_dir, pkg->name);
420
421         err = glob(globpattern, 0, NULL, &globbuf);
422         free(globpattern);
423         if (err)
424                 return;
425
426         for (i = 0; i < globbuf.gl_pathc; i++) {
427                 opkg_msg(INFO, "Deleting %s.\n", globbuf.gl_pathv[i]);
428                 unlink(globbuf.gl_pathv[i]);
429         }
430         globfree(&globbuf);
431 }