XBPS Library API  0.19
The X Binary Package System
package_orphans.c
1 /*-
2  * Copyright (c) 2009-2012 Juan Romero Pardines.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <stdio.h>
27 #include <stdbool.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 
32 #include "xbps_api_impl.h"
33 
34 /**
35  * @file lib/package_orphans.c
36  * @brief Package orphans handling routines
37  * @defgroup pkg_orphans Package orphans handling functions
38  *
39  * Functions to find installed package orphans.
40  *
41  * Package orphans were installed automatically by another package,
42  * but currently no other packages are depending on.
43  *
44  * The following image shown below shows the registered packages database
45  * dictionary (the array returned by xbps_find_pkg_orphans() will
46  * contain a package dictionary per orphan found):
47  *
48  * @image html images/xbps_pkgdb_array.png
49  *
50  * Legend:
51  * - <b>Salmon filled box</b>: \a XBPS_REGPKGDB_PLIST file internalized.
52  * - <b>White filled box</b>: mandatory objects.
53  * - <b>Grey filled box</b>: optional objects.
54  * - <b>Green filled box</b>: possible value set in the object, only one
55  * of them is set.
56  *
57  * Text inside of white boxes are the key associated with the object, its
58  * data type is specified on its edge, i.e array, bool, integer, string,
59  * dictionary.
60  */
61 
62 struct orphan_data {
63  prop_array_t array;
64  prop_array_t orphans_user;
65 };
66 
67 static int
68 find_orphan_pkg(struct xbps_handle *xhp,
69  prop_object_t obj,
70  void *arg,
71  bool *loop_done)
72 {
73  struct orphan_data *od = arg;
74  prop_array_t reqby;
75  prop_object_t obj2;
76  prop_object_iterator_t iter;
77  const char *pkgdep, *curpkgname, *curpkgver;
78  char *pkgdepname;
79  unsigned int ndep = 0, cnt = 0;
80  bool automatic = false;
81  size_t i;
82 
83  (void)xhp;
84  (void)loop_done;
85  /*
86  * Skip packages that were not installed automatically.
87  */
88  prop_dictionary_get_bool(obj, "automatic-install", &automatic);
89  if (!automatic)
90  return 0;
91 
92  prop_dictionary_get_cstring_nocopy(obj, "pkgver", &curpkgver);
93  reqby = xbps_pkgdb_get_pkg_revdeps(xhp, curpkgver);
94  if (reqby == NULL || ((cnt = prop_array_count(reqby)) == 0)) {
95  /*
96  * Add packages with empty or missing "requiredby" arrays.
97  */
98  prop_array_add(od->array, obj);
99  return 0;
100  }
101  /*
102  * Add packages that only have 1 entry matching any pkgname
103  * object in the user supplied array of strings.
104  */
105  if (od->orphans_user != NULL && cnt == 1) {
106  for (i = 0; i < prop_array_count(od->orphans_user); i++) {
107  prop_array_get_cstring_nocopy(od->orphans_user,
108  i, &curpkgname);
109  if (xbps_match_pkgname_in_array(reqby, curpkgname)) {
110  prop_array_add(od->array, obj);
111  return 0;
112  }
113  }
114  }
115  iter = prop_array_iterator(reqby);
116  if (iter == NULL)
117  return ENOMEM;
118  /*
119  * Iterate over the requiredby array and add current pkg
120  * when all pkg dependencies are already in requiredby
121  * or any pkgname object in the user supplied array of
122  * strings match.
123  */
124  while ((obj2 = prop_object_iterator_next(iter)) != NULL) {
125  pkgdep = prop_string_cstring_nocopy(obj2);
126  if (pkgdep == NULL) {
127  prop_object_iterator_release(iter);
128  return EINVAL;
129  }
130  if (xbps_find_pkg_in_array(od->array, pkgdep))
131  ndep++;
132  if (od->orphans_user == NULL)
133  continue;
134 
135  pkgdepname = xbps_pkg_name(pkgdep);
136  if (pkgdepname == NULL) {
137  prop_object_iterator_release(iter);
138  return ENOMEM;
139  }
140  for (i = 0; i < prop_array_count(od->orphans_user); i++) {
141  prop_array_get_cstring_nocopy(od->orphans_user,
142  i, &curpkgname);
143  if (strcmp(curpkgname, pkgdepname) == 0) {
144  ndep++;
145  break;
146  }
147  }
148  free(pkgdepname);
149  }
150  prop_object_iterator_release(iter);
151 
152  if (ndep != cnt)
153  return 0;
154  if (!prop_array_add(od->array, obj))
155  return EINVAL;
156 
157  return 0;
158 }
159 
160 prop_array_t
161 xbps_find_pkg_orphans(struct xbps_handle *xhp, prop_array_t orphans_user)
162 {
163  prop_array_t array = NULL;
164  struct orphan_data od;
165  int rv = 0;
166 
167  /*
168  * Prepare an array with all packages previously found.
169  */
170  if ((od.array = prop_array_create()) == NULL)
171  return NULL;
172  /*
173  * Find out all orphans by looking at pkgdb and iterating in reverse
174  * order in which packages were installed.
175  */
176  od.orphans_user = orphans_user;
177  rv = xbps_pkgdb_foreach_reverse_cb(xhp, find_orphan_pkg, &od);
178  if (rv != 0) {
179  errno = rv;
180  prop_object_release(od.array);
181  return NULL;
182  }
183  array = prop_array_copy(od.array);
184  prop_array_make_immutable(array);
185  prop_object_release(od.array);
186  return array;
187 }