|
28 | 28 | #include <stdbool.h> |
29 | 29 | #include <errno.h> |
30 | 30 |
|
| 31 | +#include "uthash.h" |
| 32 | + |
| 33 | +#include "xbps.h" |
| 34 | +#include "xbps/xbps_array.h" |
| 35 | +#include "xbps/xbps_dictionary.h" |
31 | 36 | #include "xbps_api_impl.h" |
32 | 37 |
|
33 | 38 | /* |
|
43 | 48 | * Abort transaction if such case is found. |
44 | 49 | */ |
45 | 50 |
|
46 | | -static void |
47 | | -shlib_register(xbps_dictionary_t d, const char *shlib, const char *pkgver) |
| 51 | +struct shlib_entry { |
| 52 | + const char *name; |
| 53 | + UT_hash_handle hh; |
| 54 | +}; |
| 55 | + |
| 56 | +struct shlib_ctx { |
| 57 | + struct xbps_handle *xhp; |
| 58 | + struct shlib_entry *entries; |
| 59 | + xbps_dictionary_t seen; |
| 60 | + xbps_array_t missing; |
| 61 | +}; |
| 62 | + |
| 63 | +static struct shlib_entry * |
| 64 | +shlib_entry_find(struct shlib_entry *head, const char *name) |
48 | 65 | { |
49 | | - xbps_array_t array; |
50 | | - bool alloc = false; |
| 66 | + struct shlib_entry *res = NULL; |
| 67 | + HASH_FIND_STR(head, name, res); |
| 68 | + return res; |
| 69 | +} |
51 | 70 |
|
52 | | - if ((array = xbps_dictionary_get(d, shlib)) == NULL) { |
53 | | - alloc = true; |
54 | | - array = xbps_array_create(); |
55 | | - xbps_dictionary_set(d, shlib, array); |
| 71 | +static struct shlib_entry * |
| 72 | +shlib_entry_get(struct shlib_ctx *ctx, const char *name) |
| 73 | +{ |
| 74 | + struct shlib_entry *res = shlib_entry_find(ctx->entries, name); |
| 75 | + if (res) |
| 76 | + return res; |
| 77 | + res = calloc(1, sizeof(*res)); |
| 78 | + if (!res) { |
| 79 | + xbps_error_printf("out of memory\n"); |
| 80 | + errno = ENOMEM; |
| 81 | + return NULL; |
56 | 82 | } |
57 | | - if (!xbps_match_string_in_array(array, pkgver)) |
58 | | - xbps_array_add_cstring_nocopy(array, pkgver); |
59 | | - if (alloc) |
60 | | - xbps_object_release(array); |
| 83 | + res->name = name; |
| 84 | + HASH_ADD_STR(ctx->entries, name, res); |
| 85 | + return res; |
61 | 86 | } |
62 | 87 |
|
63 | | -static xbps_dictionary_t |
64 | | -collect_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs, bool req) |
| 88 | +static int |
| 89 | +collect_shlib_array(struct shlib_ctx *ctx, xbps_array_t array) |
| 90 | +{ |
| 91 | + for (unsigned int i = 0; i < xbps_array_count(array); i++) { |
| 92 | + struct shlib_entry *entry; |
| 93 | + const char *shlib = NULL; |
| 94 | + if (!xbps_array_get_cstring_nocopy(array, i, &shlib)) |
| 95 | + return -EINVAL; |
| 96 | + entry = shlib_entry_get(ctx, shlib); |
| 97 | + if (!entry) |
| 98 | + return -errno; |
| 99 | + } |
| 100 | + return 0; |
| 101 | +} |
| 102 | + |
| 103 | +static int |
| 104 | +collect_shlibs(struct shlib_ctx *ctx, xbps_array_t pkgs) |
65 | 105 | { |
66 | 106 | xbps_object_t obj; |
67 | 107 | xbps_object_iterator_t iter; |
68 | | - xbps_dictionary_t d, pd; |
69 | | - const char *pkgname, *pkgver; |
70 | | - |
71 | | - d = xbps_dictionary_create(); |
72 | | - assert(d); |
73 | | - |
74 | | - /* copy pkgdb to out temporary dictionary */ |
75 | | - pd = xbps_dictionary_copy(xhp->pkgdb); |
76 | | - assert(pd); |
77 | | - |
78 | | - /* |
79 | | - * copy pkgs from transaction to our dictionary, overriding them |
80 | | - * if they were there from pkgdb. |
81 | | - */ |
82 | | - iter = xbps_array_iterator(pkgs); |
83 | | - assert(iter); |
84 | | - while ((obj = xbps_object_iterator_next(iter))) { |
85 | | - if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname)) |
86 | | - continue; |
| 108 | + xbps_bool_t placeholder; |
| 109 | + |
| 110 | + // can't set null values to xbps_dictionary so just use one boolean |
| 111 | + placeholder = xbps_bool_create(true); |
| 112 | + if (!placeholder) { |
| 113 | + xbps_error_printf("out of memory\n"); |
| 114 | + return -ENOMEM; |
| 115 | + } |
| 116 | + |
| 117 | + ctx->seen = xbps_dictionary_create(); |
| 118 | + if (!ctx->seen) { |
| 119 | + xbps_error_printf("out of memory\n"); |
| 120 | + return -ENOMEM; |
| 121 | + } |
87 | 122 |
|
88 | | - /* ignore shlibs if pkg is on hold mode */ |
89 | | - if (xbps_transaction_pkg_type(obj) == XBPS_TRANS_HOLD) { |
| 123 | + for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) { |
| 124 | + const char *pkgname; |
| 125 | + xbps_dictionary_t pkgd = xbps_array_get(pkgs, i); |
| 126 | + xbps_array_t array; |
| 127 | + |
| 128 | + if (xbps_transaction_pkg_type(pkgd) == XBPS_TRANS_HOLD) |
90 | 129 | continue; |
| 130 | + if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname)) { |
| 131 | + xbps_error_printf("invalid package: missing `pkgname` property\n"); |
| 132 | + return -EINVAL; |
| 133 | + } |
| 134 | + if (!xbps_dictionary_set(ctx->seen, pkgname, placeholder)) { |
| 135 | + xbps_error_printf("out of memory\n"); |
| 136 | + return -ENOMEM; |
91 | 137 | } |
92 | 138 |
|
93 | | - xbps_dictionary_set(pd, pkgname, obj); |
| 139 | + if (xbps_transaction_pkg_type(pkgd) == XBPS_TRANS_REMOVE) |
| 140 | + continue; |
| 141 | + |
| 142 | + array = xbps_dictionary_get(pkgd, "shlib-provides"); |
| 143 | + if (array) { |
| 144 | + int r = collect_shlib_array(ctx, array); |
| 145 | + if (r < 0) |
| 146 | + return r; |
| 147 | + } |
94 | 148 | } |
95 | | - xbps_object_iterator_release(iter); |
96 | 149 |
|
97 | | - /* |
98 | | - * iterate over our dictionary to collect shlib-{requires,provides}. |
99 | | - */ |
100 | | - iter = xbps_dictionary_iterator(pd); |
101 | | - assert(iter); |
| 150 | + iter = xbps_dictionary_iterator(ctx->xhp->pkgdb); |
| 151 | + if (!iter) { |
| 152 | + xbps_error_printf("out of memory\n"); |
| 153 | + return -ENOMEM; |
| 154 | + } |
102 | 155 |
|
103 | 156 | while ((obj = xbps_object_iterator_next(iter))) { |
104 | | - xbps_array_t shobjs; |
| 157 | + xbps_array_t array; |
105 | 158 | xbps_dictionary_t pkgd; |
| 159 | + const char *pkgname = NULL; |
106 | 160 |
|
107 | | - pkgd = xbps_dictionary_get_keysym(pd, obj); |
108 | | - if (xbps_transaction_pkg_type(pkgd) == XBPS_TRANS_REMOVE) { |
109 | | - continue; |
110 | | - } |
111 | | - /* |
112 | | - * If pkg does not have the required obj, pass to next one. |
113 | | - */ |
114 | | - xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); |
115 | | - shobjs = xbps_dictionary_get(pkgd, |
116 | | - req ? "shlib-requires" : "shlib-provides"); |
117 | | - if (shobjs == NULL) |
| 161 | + pkgname = xbps_dictionary_keysym_cstring_nocopy(obj); |
| 162 | + /* ignore internal objs */ |
| 163 | + if (strncmp(pkgname, "_XBPS_", 6) == 0) |
118 | 164 | continue; |
119 | 165 |
|
120 | | - for (unsigned int i = 0; i < xbps_array_count(shobjs); i++) { |
121 | | - const char *shlib = NULL; |
| 166 | + pkgd = xbps_dictionary_get_keysym(ctx->xhp->pkgdb, obj); |
| 167 | + |
| 168 | + if (xbps_dictionary_get(ctx->seen, pkgname)) |
| 169 | + continue; |
122 | 170 |
|
123 | | - xbps_array_get_cstring_nocopy(shobjs, i, &shlib); |
124 | | - xbps_dbg_printf("%s: registering %s for %s\n", |
125 | | - pkgver, shlib, req ? "shlib-requires" : "shlib-provides"); |
126 | | - if (req) |
127 | | - shlib_register(d, shlib, pkgver); |
128 | | - else |
129 | | - xbps_dictionary_set_cstring_nocopy(d, shlib, pkgver); |
| 171 | + array = xbps_dictionary_get(pkgd, "shlib-provides"); |
| 172 | + if (array) { |
| 173 | + int r = collect_shlib_array(ctx, array); |
| 174 | + if (r < 0) |
| 175 | + return r; |
130 | 176 | } |
131 | 177 | } |
| 178 | + |
132 | 179 | xbps_object_iterator_release(iter); |
133 | | - xbps_object_release(pd); |
134 | | - return d; |
| 180 | + return 0; |
135 | 181 | } |
136 | 182 |
|
137 | | -bool HIDDEN |
138 | | -xbps_transaction_check_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs) |
| 183 | +static int |
| 184 | +check_shlibs(struct shlib_ctx *ctx, xbps_array_t pkgs) |
139 | 185 | { |
140 | | - xbps_array_t array, mshlibs; |
141 | | - xbps_object_t obj, obj2; |
142 | 186 | xbps_object_iterator_t iter; |
143 | | - xbps_dictionary_t shrequires, shprovides; |
144 | | - const char *pkgver = NULL, *shlib = NULL; |
145 | | - char *buf; |
146 | | - bool broken = false; |
| 187 | + xbps_object_t obj; |
147 | 188 |
|
148 | | - shrequires = collect_shlibs(xhp, pkgs, true); |
149 | | - shprovides = collect_shlibs(xhp, pkgs, false); |
| 189 | + for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) { |
| 190 | + xbps_array_t array; |
| 191 | + xbps_dictionary_t pkgd = xbps_array_get(pkgs, i); |
| 192 | + xbps_trans_type_t ttype = xbps_transaction_pkg_type(pkgd); |
150 | 193 |
|
151 | | - mshlibs = xbps_dictionary_get(xhp->transd, "missing_shlibs"); |
152 | | - /* iterate over shlib-requires to find unmatched shlibs */ |
153 | | - iter = xbps_dictionary_iterator(shrequires); |
154 | | - assert(iter); |
| 194 | + if (ttype == XBPS_TRANS_HOLD || ttype == XBPS_TRANS_REMOVE) |
| 195 | + continue; |
155 | 196 |
|
156 | | - while ((obj = xbps_object_iterator_next(iter))) { |
157 | | - shlib = xbps_dictionary_keysym_cstring_nocopy(obj); |
158 | | - xbps_dbg_printf("%s: checking for `%s': ", __func__, shlib); |
159 | | - if ((obj2 = xbps_dictionary_get(shprovides, shlib))) { |
160 | | - xbps_dbg_printf_append("provided by `%s'\n", |
161 | | - xbps_string_cstring_nocopy(obj2)); |
| 197 | + array = xbps_dictionary_get(pkgd, "shlib-requires"); |
| 198 | + if (!array) |
162 | 199 | continue; |
| 200 | + for (unsigned int j = 0; j < xbps_array_count(array); j++) { |
| 201 | + const char *pkgver = NULL; |
| 202 | + const char *shlib = NULL; |
| 203 | + char *missing; |
| 204 | + if (!xbps_array_get_cstring_nocopy(array, j, &shlib)) |
| 205 | + return -EINVAL; |
| 206 | + if (shlib_entry_find(ctx->entries, shlib)) |
| 207 | + continue; |
| 208 | + if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) |
| 209 | + return -EINVAL; |
| 210 | + missing = xbps_xasprintf( |
| 211 | + "%s: broken, unresolvable shlib `%s'", |
| 212 | + pkgver, shlib); |
| 213 | + if (!xbps_array_add_cstring_nocopy(ctx->missing, missing)) { |
| 214 | + xbps_error_printf("out of memory\n"); |
| 215 | + return -ENOMEM; |
| 216 | + } |
163 | 217 | } |
164 | | - xbps_dbg_printf_append("not found\n"); |
| 218 | + } |
| 219 | + |
| 220 | + iter = xbps_dictionary_iterator(ctx->xhp->pkgdb); |
| 221 | + if (!iter) { |
| 222 | + xbps_error_printf("out of memory\n"); |
| 223 | + return -ENOMEM; |
| 224 | + } |
| 225 | + |
| 226 | + while ((obj = xbps_object_iterator_next(iter))) { |
| 227 | + xbps_array_t array; |
| 228 | + xbps_dictionary_t pkgd; |
| 229 | + const char *pkgname = NULL; |
| 230 | + |
| 231 | + pkgname = xbps_dictionary_keysym_cstring_nocopy(obj); |
| 232 | + /* ignore internal objs */ |
| 233 | + if (strncmp(pkgname, "_XBPS_", 6) == 0) |
| 234 | + continue; |
| 235 | + |
| 236 | + pkgd = xbps_dictionary_get_keysym(ctx->xhp->pkgdb, obj); |
| 237 | + |
| 238 | + if (xbps_dictionary_get(ctx->seen, pkgname)) |
| 239 | + continue; |
165 | 240 |
|
166 | | - broken = true; |
167 | | - array = xbps_dictionary_get_keysym(shrequires, obj); |
| 241 | + array = xbps_dictionary_get(pkgd, "shlib-requires"); |
| 242 | + if (!array) |
| 243 | + continue; |
168 | 244 | for (unsigned int i = 0; i < xbps_array_count(array); i++) { |
169 | | - xbps_array_get_cstring_nocopy(array, i, &pkgver); |
170 | | - buf = xbps_xasprintf("%s: broken, unresolvable " |
171 | | - "shlib `%s'", pkgver, shlib); |
172 | | - xbps_array_add_cstring(mshlibs, buf); |
173 | | - free(buf); |
| 245 | + const char *pkgver = NULL; |
| 246 | + const char *shlib = NULL; |
| 247 | + char *missing; |
| 248 | + if (!xbps_array_get_cstring_nocopy(array, i, &shlib)) |
| 249 | + return -EINVAL; |
| 250 | + if (shlib_entry_find(ctx->entries, shlib)) |
| 251 | + continue; |
| 252 | + if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) |
| 253 | + return -EINVAL; |
| 254 | + missing = xbps_xasprintf( |
| 255 | + "%s: broken, unresolvable shlib `%s'", pkgver, |
| 256 | + shlib); |
| 257 | + if (!xbps_array_add_cstring_nocopy(ctx->missing, missing)) { |
| 258 | + xbps_error_printf("out of memory\n"); |
| 259 | + return -ENOMEM; |
| 260 | + } |
174 | 261 | } |
175 | 262 | } |
| 263 | + |
176 | 264 | xbps_object_iterator_release(iter); |
177 | | - if (!broken) { |
| 265 | + return 0; |
| 266 | +} |
| 267 | + |
| 268 | +bool HIDDEN |
| 269 | +xbps_transaction_check_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs) |
| 270 | +{ |
| 271 | + struct shlib_entry *entry, *tmp; |
| 272 | + struct shlib_ctx ctx = { .xhp = xhp }; |
| 273 | + int r; |
| 274 | + |
| 275 | + ctx.missing = xbps_dictionary_get(xhp->transd, "missing_shlibs"); |
| 276 | + |
| 277 | + r = collect_shlibs(&ctx, pkgs); |
| 278 | + if (r < 0) |
| 279 | + goto err; |
| 280 | + |
| 281 | + r = check_shlibs(&ctx, pkgs); |
| 282 | + if (r < 0) |
| 283 | + goto err; |
| 284 | + |
| 285 | + if (xbps_array_count(ctx.missing) == 0) |
178 | 286 | xbps_dictionary_remove(xhp->transd, "missing_shlibs"); |
179 | | - } |
180 | | - xbps_object_release(shprovides); |
181 | | - xbps_object_release(shrequires); |
182 | 287 |
|
183 | | - return true; |
| 288 | + r = 0; |
| 289 | +err: |
| 290 | + HASH_ITER(hh, ctx.entries, entry, tmp) { |
| 291 | + HASH_DEL(ctx.entries, entry); |
| 292 | + free(entry); |
| 293 | + } |
| 294 | + if (ctx.seen) |
| 295 | + xbps_object_release(ctx.seen); |
| 296 | + return r == 0; |
184 | 297 | } |
0 commit comments