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