3886ccc6eeb40918c0d9d15a59de2a150fae5e97
[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_state.h"
26
27 #include "file_util.h"
28 #include "sprintf_alloc.h"
29 #include "str_util.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 pkg_has_installed_dependents(opkg_conf_t *conf, abstract_pkg_t *parent_apkg, pkg_t *pkg, abstract_pkg_t *** pdependents)
36 {
37      int nprovides = pkg->provides_count;
38      abstract_pkg_t **provides = pkg->provides;
39      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 = (abstract_pkg_t **)calloc((n_installed_dependents+1), sizeof(abstract_pkg_t *));
58
59           if ( dependents == NULL ){
60               fprintf(stderr,"%s Unable to allocate memory. REPORT THIS BUG IN BUGZILLA PLEASE\n", __FUNCTION__);
61               return -1;  
62           }
63
64           *pdependents = dependents;
65           for (i = 0; i <= nprovides; i++) {
66                abstract_pkg_t *providee = provides[i];
67                abstract_pkg_t **dependers = providee->depended_upon_by;
68                abstract_pkg_t *dep_ab_pkg;
69                if (dependers == NULL)
70                     continue;
71                while ((dep_ab_pkg = *dependers++) != NULL) {
72                     if (dep_ab_pkg->state_status == SS_INSTALLED && !(dep_ab_pkg->state_flag & SF_MARKED)) {
73                          dependents[p++] = dep_ab_pkg;
74                          dep_ab_pkg->state_flag |= SF_MARKED;
75                     }
76                }
77           }
78           dependents[p] = NULL;
79           /* now clear the marks */
80           for (i = 0; i < p; i++) {
81                abstract_pkg_t *dep_ab_pkg = dependents[i];
82                dep_ab_pkg->state_flag &= ~SF_MARKED;
83           }
84      }
85      return n_installed_dependents;
86 }
87
88 int opkg_remove_dependent_pkgs (opkg_conf_t *conf, pkg_t *pkg, abstract_pkg_t **dependents)
89 {
90     int i;
91     int a;
92     int count;
93     pkg_vec_t *dependent_pkgs;
94     abstract_pkg_t * ab_pkg;
95
96     if((ab_pkg = pkg->parent) == NULL){
97         fprintf(stderr, "%s: unable to get dependent pkgs. pkg %s isn't in hash table\n",
98                 __FUNCTION__, pkg->name);
99         return 0;
100     }
101     
102     if (dependents == NULL)
103             return 0;
104
105     // here i am using the dependencies_checked
106     if (ab_pkg->dependencies_checked == 2) // variable to make out whether this package
107         return 0;                          // has already been encountered in the process
108                                            // of marking packages for removal - Karthik
109     ab_pkg->dependencies_checked = 2;
110
111     i = 0;
112     count = 1;
113     dependent_pkgs = pkg_vec_alloc();
114
115     while (dependents [i] != NULL) {
116         abstract_pkg_t *dep_ab_pkg = dependents[i];
117         
118         if (dep_ab_pkg->dependencies_checked == 2){
119             i++;
120             continue;   
121         }
122         if (dep_ab_pkg->state_status == SS_INSTALLED) {
123             for (a = 0; a < dep_ab_pkg->pkgs->len; a++) {
124                 pkg_t *dep_pkg = dep_ab_pkg->pkgs->pkgs[a];
125                 if (dep_pkg->state_status == SS_INSTALLED) {
126                     pkg_vec_insert(dependent_pkgs, dep_pkg);
127                     count++;
128                 }
129             }
130         }
131         i++;
132         /* 1 - to keep track of visited ab_pkgs when checking for possiblility of a broken removal of pkgs.
133          * 2 - to keep track of pkgs whose deps have been checked alrdy  - Karthik */   
134     }
135     
136     if (count == 1) {
137         free(dependent_pkgs);  
138         return 0;
139     }
140     
141     
142     int err=0;
143     for (i = 0; i < dependent_pkgs->len; i++) {
144         err = opkg_remove_pkg(conf, dependent_pkgs->pkgs[i],0);
145         if (err)
146             break;
147     }
148     free(dependent_pkgs);
149     return err;
150 }
151
152 static int user_prefers_removing_dependents(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 or -recursive\n");
165     opkg_message(conf, OPKG_ERROR, "or by setting option force_removal_of_dependent_packages\n");
166     opkg_message(conf, OPKG_ERROR, "in opkg.conf.\n");
167     return 0;
168 }
169
170 static int remove_autoinstalled (opkg_conf_t *conf, pkg_t *pkg)
171 {
172   /*
173    * find and remove packages that were autoinstalled and are orphaned by the removal of pkg
174    */
175
176   char *buffer, *d_str;
177   int i;
178
179   for (i = 0; i < pkg->depends_count; ++i)
180   {
181     int x = 0;
182     pkg_t *p;
183     d_str = pkg->depends_str[i];
184     buffer = calloc (1, strlen (d_str) + 1);
185     if (!buffer)
186     {
187       fprintf(stderr,"%s Unable to allocate memory.\n", __FUNCTION__);
188       return -1;
189     }
190
191     while (d_str[x] != '\0' && d_str[x] != ' ')
192     {
193       buffer[x] = d_str[x];
194       ++x;
195     }
196     buffer[x] = '\0';
197     buffer = realloc (buffer, strlen (buffer) + 1);
198     p = pkg_hash_fetch_installed_by_name (&conf->pkg_hash, buffer);
199
200     /* if the package is not installed, this could have been a circular
201      * depenancy and the package has already been removed */
202     if (!p)
203       return -1;
204
205     if (p->auto_installed)
206     {
207       int deps;
208       abstract_pkg_t **dependents;
209
210       deps = pkg_has_installed_dependents(conf, NULL, p, &dependents);
211       if (deps == 0)
212       {
213          opkg_message (conf, OPKG_INFO,
214                        "%s was autoinstalled but is now orphaned\n", buffer);
215          opkg_remove_pkg(conf, p,0);
216       }
217         else
218            opkg_message (conf, OPKG_INFO, "%s was autoinstalled and is still required by "
219                          "%d installed packages\n", buffer, deps);
220     }
221     free (buffer);
222   }
223
224   return 0;
225 }
226
227 int opkg_remove_pkg(opkg_conf_t *conf, pkg_t *pkg,int message)
228 {
229 /* Actually, when "message == 1" I have been called from an upgrade, and not from a normal remove
230    thus I wan't check for essential, as I'm upgrading.
231    I hope it won't break anything :) 
232 */
233      int err;
234      abstract_pkg_t *parent_pkg = NULL;
235
236      if (pkg->essential && !message) {
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 up 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                    && !user_prefers_removing_dependents(conf, parent_pkg, pkg, dependents)) {
272                     return OPKG_PKG_HAS_DEPENDENTS;
273                }
274
275                /* remove packages depending on this package - Karthik */
276                err = opkg_remove_dependent_pkgs (conf, pkg, dependents);
277                if (err) {
278                  free(dependents);
279                  return err;
280                }
281           }
282           if (dependents)
283               free(dependents);
284      }
285
286      if ( message==0 ){
287          opkg_message (conf, OPKG_NOTICE,
288                        "Removing package %s from %s...\n", pkg->name, pkg->dest->name);
289          fflush(stdout);
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_except_postrm(conf, pkg);
308
309      /* Aman Gupta - Since opkg is made for handheld devices with limited
310       * space, it doesn't make sense to leave extra configurations, files, 
311       * and maintainer scripts left around. So, we make remove like purge, 
312       * and take out all the crap :) */
313
314      remove_postrm(conf, pkg);
315      pkg->state_status = SS_NOT_INSTALLED;
316
317      if (parent_pkg) 
318           parent_pkg->state_status = SS_NOT_INSTALLED;
319
320
321      /* remove autoinstalled packages that are orphaned by the removal of this one */
322      if (conf->autoremove)
323        remove_autoinstalled (conf, pkg);
324
325
326
327      return 0;
328 }
329
330 int opkg_purge_pkg(opkg_conf_t *conf, pkg_t *pkg)
331 {
332     opkg_remove_pkg(conf, pkg,0);
333     return 0;
334 }
335
336 int remove_data_files_and_list(opkg_conf_t *conf, pkg_t *pkg)
337 {
338      str_list_t installed_dirs;
339      str_list_t *installed_files;
340      str_list_elt_t *iter;
341      char *file_name;
342      conffile_t *conffile;
343      int removed_a_dir;
344      pkg_t *owner;
345
346      str_list_init(&installed_dirs);
347      installed_files = pkg_get_installed_files(pkg);
348
349      for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
350           file_name = (char *)iter->data;
351
352           if (file_is_dir(file_name)) {
353                str_list_append(&installed_dirs, file_name);
354                continue;
355           }
356
357           conffile = pkg_get_conffile(pkg, file_name);
358           if (conffile) {
359                /* XXX: QUESTION: Is this right? I figure we only need to
360                   save the conffile if it has been modified. Is that what
361                   dpkg does? Or does dpkg preserve all conffiles? If so,
362                   this seems like a better thing to do to conserve
363                   space. */
364                if (conffile_has_been_modified(conf, conffile)) {
365                     opkg_message (conf, OPKG_NOTICE,
366                                   "  not deleting modified conffile %s\n", file_name);
367                     fflush(stdout);
368                     continue;
369                }
370           }
371
372           opkg_message(conf, OPKG_INFO, "  deleting %s (noaction=%d)\n", file_name, conf->noaction);
373           if (!conf->noaction)
374                unlink(file_name);
375      }
376
377      if (!conf->noaction) {
378           do {
379                removed_a_dir = 0;
380                for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) {
381                     file_name = (char *)iter->data;
382             
383                     if (rmdir(file_name) == 0) {
384                          opkg_message(conf, OPKG_INFO, "  deleting %s\n", file_name);
385                          removed_a_dir = 1;
386                          str_list_remove(&installed_dirs, &iter);
387                     }
388                }
389           } while (removed_a_dir);
390      }
391
392      pkg_free_installed_files(pkg);
393      /* We have to remove the file list now, so that
394         find_pkg_owning_file does not always just report this package */
395      pkg_remove_installed_files_list(conf, pkg);
396
397      /* Don't print warning for dirs that are provided by other packages */
398      for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) {
399           file_name = (char *)iter->data;
400
401           owner = file_hash_get_file_owner(conf, file_name);
402           if (owner) {
403                free(iter->data);
404                iter->data = NULL;
405                str_list_remove(&installed_dirs, &iter);
406           }
407      }
408
409      /* cleanup */
410      while (!void_list_empty(&installed_dirs)) {
411         iter = str_list_pop(&installed_dirs);
412         free(iter->data);
413         free(iter);
414      }
415      str_list_deinit(&installed_dirs);
416
417      return 0;
418 }
419
420 int remove_maintainer_scripts_except_postrm(opkg_conf_t *conf, pkg_t *pkg)
421 {
422     int i, err;
423     char *globpattern;
424     glob_t globbuf;
425     
426     if (conf->noaction) return 0;
427
428     sprintf_alloc(&globpattern, "%s/%s.*",
429                   pkg->dest->info_dir, pkg->name);
430     err = glob(globpattern, 0, NULL, &globbuf);
431     free(globpattern);
432     if (err) {
433         return 0;
434     }
435
436     for (i = 0; i < globbuf.gl_pathc; i++) {
437         if (str_ends_with(globbuf.gl_pathv[i], ".postrm")) {
438             continue;
439         }
440         opkg_message(conf, OPKG_INFO, "  deleting %s\n", globbuf.gl_pathv[i]);
441         unlink(globbuf.gl_pathv[i]);
442     }
443     globfree(&globbuf);
444
445     return 0;
446 }
447
448 int remove_postrm(opkg_conf_t *conf, pkg_t *pkg)
449 {
450     char *postrm_file_name;
451
452     if (conf->noaction) return 0;
453
454     sprintf_alloc(&postrm_file_name, "%s/%s.postrm",
455                   pkg->dest->info_dir, pkg->name);
456     unlink(postrm_file_name);
457     free(postrm_file_name);
458
459     return 0;
460 }