XBPS Library API 20240111
The X Binary Package System
package_orphans.c
1/*-
2 * Copyright (c) 2009-2020 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_dictionary.png
49 *
50 * Legend:
51 * - <b>Salmon filled box</b>: \a pkgdb plist 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
62xbps_array_t
63xbps_find_pkg_orphans(struct xbps_handle *xhp, xbps_array_t orphans_user)
64{
65 xbps_array_t array = NULL;
66 xbps_object_t obj;
67 xbps_object_iterator_t iter;
68
69 if (xbps_pkgdb_init(xhp) != 0)
70 return NULL;
71
72 if ((array = xbps_array_create()) == NULL)
73 return NULL;
74
75 if (!orphans_user) {
76 /* automatic mode (xbps-query -O, xbps-remove -o) */
77 iter = xbps_dictionary_iterator(xhp->pkgdb);
78 assert(iter);
79 /*
80 * Iterate on pkgdb until no more orphans are found.
81 */
82 for (;;) {
83 bool added = false;
84 while ((obj = xbps_object_iterator_next(iter))) {
85 xbps_array_t revdeps;
86 xbps_dictionary_t pkgd;
87 unsigned int cnt = 0, revdepscnt = 0;
88 const char *pkgver = NULL;
89 bool automatic = false;
90
91 pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj);
92 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
93 /* _XBPS_ALTERNATIVES_ */
94 continue;
95 }
96 xbps_dbg_printf(" %s checking %s\n", __func__, pkgver);
97 xbps_dictionary_get_bool(pkgd, "automatic-install", &automatic);
98 if (!automatic) {
99 xbps_dbg_printf(" %s skipped (!automatic)\n", pkgver);
100 continue;
101 }
102 if (xbps_find_pkg_in_array(array, pkgver, 0)) {
103 xbps_dbg_printf(" %s orphan (queued)\n", pkgver);
104 continue;
105 }
106 revdeps = xbps_pkgdb_get_pkg_revdeps(xhp, pkgver);
107 revdepscnt = xbps_array_count(revdeps);
108
109 if (revdepscnt == 0) {
110 added = true;
111 xbps_array_add(array, pkgd);
112 xbps_dbg_printf(" %s orphan (automatic and !revdeps)\n", pkgver);
113 continue;
114 }
115 /* verify all revdeps are seen */
116 for (unsigned int i = 0; i < revdepscnt; i++) {
117 const char *revdepver = NULL;
118
119 xbps_array_get_cstring_nocopy(revdeps, i, &revdepver);
120 if (xbps_find_pkg_in_array(array, revdepver, 0))
121 cnt++;
122 }
123 if (cnt == revdepscnt) {
124 added = true;
125 xbps_array_add(array, pkgd);
126 xbps_dbg_printf(" %s orphan (automatic and all revdeps)\n", pkgver);
127 }
128
129 }
130 xbps_dbg_printf("orphans pkgdb iter: added %s\n", added ? "true" : "false");
131 xbps_object_iterator_reset(iter);
132 if (!added)
133 break;
134 }
135 xbps_object_iterator_release(iter);
136
137 return array;
138 }
139
140 /*
141 * Recursive removal mode (xbps-remove -R).
142 */
143 for (unsigned int i = 0; i < xbps_array_count(orphans_user); i++) {
144 xbps_dictionary_t pkgd;
145 const char *pkgver = NULL;
146
147 xbps_array_get_cstring_nocopy(orphans_user, i, &pkgver);
148 pkgd = xbps_pkgdb_get_pkg(xhp, pkgver);
149 if (pkgd == NULL)
150 continue;
151 xbps_array_add(array, pkgd);
152 }
153
154 for (unsigned int i = 0; i < xbps_array_count(array); i++) {
155 xbps_array_t rdeps;
156 xbps_dictionary_t pkgd;
157 const char *pkgver = NULL;
158 unsigned int cnt = 0, reqbycnt = 0;
159
160 pkgd = xbps_array_get(array, i);
161 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
162 rdeps = xbps_pkgdb_get_pkg_fulldeptree(xhp, pkgver);
163 if (xbps_array_count(rdeps) == 0) {
164 continue;
165 }
166
167 xbps_dbg_printf(" processing rdeps for %s\n", pkgver);
168 for (unsigned int x = 0; x < xbps_array_count(rdeps); x++) {
169 xbps_array_t reqby;
170 xbps_dictionary_t deppkgd;
171 const char *deppkgver = NULL;
172 bool automatic = false;
173
174 cnt = 0;
175 xbps_array_get_cstring_nocopy(rdeps, x, &deppkgver);
176 if (xbps_find_pkg_in_array(array, deppkgver, 0)) {
177 xbps_dbg_printf(" rdep %s already queued\n", deppkgver);
178 continue;
179 }
180 deppkgd = xbps_pkgdb_get_pkg(xhp, deppkgver);
181 xbps_dictionary_get_bool(deppkgd, "automatic-install", &automatic);
182 if (!automatic) {
183 xbps_dbg_printf(" rdep %s skipped (!automatic)\n", deppkgver);
184 continue;
185 }
186
187 reqby = xbps_pkgdb_get_pkg_revdeps(xhp, deppkgver);
188 reqbycnt = xbps_array_count(reqby);
189 for (unsigned int j = 0; j < reqbycnt; j++) {
190 const char *reqbydep = NULL;
191
192 xbps_array_get_cstring_nocopy(reqby, j, &reqbydep);
193 xbps_dbg_printf(" %s processing revdep %s\n", pkgver, reqbydep);
194 if (xbps_find_pkg_in_array(array, reqbydep, 0))
195 cnt++;
196 }
197 if (cnt == reqbycnt) {
198 xbps_array_add(array, deppkgd);
199 xbps_dbg_printf(" added %s orphan\n", deppkgver);
200 }
201 }
202 }
203
204 return array;
205}
xbps_dictionary_t pkgdb
Definition xbps.h:576
Generic XBPS structure handler for initialization.
Definition xbps.h:550
xbps_array_t xbps_find_pkg_orphans(struct xbps_handle *xhp, xbps_array_t orphans_user)
xbps_array_t xbps_pkgdb_get_pkg_fulldeptree(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:476
xbps_array_t xbps_pkgdb_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:458
xbps_dictionary_t xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:379