XBPS Library API 20240111
The X Binary Package System
pkgdb.c
1/*-
2 * Copyright (c) 2012-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 <sys/types.h>
27#include <sys/stat.h>
28
29#include <errno.h>
30#include <fcntl.h>
31#include <limits.h>
32#include <stdbool.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37
38#include "xbps_api_impl.h"
39
40/**
41 * @file lib/pkgdb.c
42 * @brief Package database handling routines
43 * @defgroup pkgdb Package database handling functions
44 *
45 * Functions to manipulate the main package database plist file (pkgdb).
46 *
47 * The following image shown below shows the proplib structure used
48 * by the main package database plist:
49 *
50 * @image html images/xbps_pkgdb_dictionary.png
51 *
52 * Legend:
53 * - <b>Salmon filled box</b>: \a pkgdb plist internalized.
54 * - <b>White filled box</b>: mandatory objects.
55 * - <b>Grey filled box</b>: optional objects.
56 * - <b>Green filled box</b>: possible value set in the object, only one
57 * of them is set.
58 *
59 * Text inside of white boxes are the key associated with the object, its
60 * data type is specified on its edge, i.e array, bool, integer, string,
61 * dictionary.
62 */
63static int pkgdb_fd = -1;
64static bool pkgdb_map_names_done = false;
65
66int
68{
69 mode_t prev_umask;
70 int rv = 0;
71 /*
72 * Use a mandatory file lock to only allow one writer to pkgdb,
73 * other writers will block.
74 */
75 prev_umask = umask(022);
76 xhp->pkgdb_plist = xbps_xasprintf("%s/%s", xhp->metadir, XBPS_PKGDB);
77 if (xbps_pkgdb_init(xhp) == ENOENT) {
78 /* if metadir does not exist, create it */
79 if (access(xhp->metadir, R_OK|X_OK) == -1) {
80 if (errno != ENOENT) {
81 rv = errno;
82 goto ret;
83 }
84 if (xbps_mkpath(xhp->metadir, 0755) == -1) {
85 rv = errno;
86 xbps_dbg_printf("[pkgdb] failed to create metadir "
87 "%s: %s\n", xhp->metadir, strerror(rv));
88 goto ret;
89 }
90 }
91 /* if pkgdb is unexistent, create it with an empty dictionary */
92 xhp->pkgdb = xbps_dictionary_create();
93 if (!xbps_dictionary_externalize_to_file(xhp->pkgdb, xhp->pkgdb_plist)) {
94 rv = errno;
95 xbps_dbg_printf("[pkgdb] failed to create pkgdb "
96 "%s: %s\n", xhp->pkgdb_plist, strerror(rv));
97 goto ret;
98 }
99 }
100
101 if ((pkgdb_fd = open(xhp->pkgdb_plist, O_CREAT|O_RDWR|O_CLOEXEC, 0664)) == -1) {
102 rv = errno;
103 xbps_dbg_printf("[pkgdb] cannot open pkgdb for locking "
104 "%s: %s\n", xhp->pkgdb_plist, strerror(rv));
105 free(xhp->pkgdb_plist);
106 goto ret;
107 }
108
109 /*
110 * If we've acquired the file lock, then pkgdb is writable.
111 */
112 if (lockf(pkgdb_fd, F_TLOCK, 0) == -1) {
113 rv = errno;
114 xbps_dbg_printf("[pkgdb] cannot lock pkgdb: %s\n", strerror(rv));
115 }
116 /*
117 * Check if rootdir is writable.
118 */
119 if (access(xhp->rootdir, W_OK) == -1) {
120 rv = errno;
121 xbps_dbg_printf("[pkgdb] rootdir %s: %s\n", xhp->rootdir, strerror(rv));
122 }
123
124ret:
125 umask(prev_umask);
126 return rv;
127}
128
129void
130xbps_pkgdb_unlock(struct xbps_handle *xhp UNUSED)
131{
132 xbps_dbg_printf("%s: pkgdb_fd %d\n", __func__, pkgdb_fd);
133
134 if (pkgdb_fd != -1) {
135 if (lockf(pkgdb_fd, F_ULOCK, 0) == -1)
136 xbps_dbg_printf("[pkgdb] failed to unlock pkgdb: %s\n", strerror(errno));
137
138 (void)close(pkgdb_fd);
139 pkgdb_fd = -1;
140 }
141}
142
143static int
144pkgdb_map_vpkgs(struct xbps_handle *xhp)
145{
146 xbps_object_iterator_t iter;
147 xbps_object_t obj;
148 int rv = 0;
149
150 if (!xbps_dictionary_count(xhp->pkgdb))
151 return 0;
152
153 if (xhp->vpkgd == NULL) {
154 xhp->vpkgd = xbps_dictionary_create();
155 assert(xhp->vpkgd);
156 }
157 /*
158 * This maps all pkgs that have virtualpkgs in pkgdb.
159 */
160 iter = xbps_dictionary_iterator(xhp->pkgdb);
161 assert(iter);
162
163 while ((obj = xbps_object_iterator_next(iter))) {
164 xbps_array_t provides;
165 xbps_dictionary_t pkgd;
166 const char *pkgver = NULL;
167 char pkgname[XBPS_NAME_SIZE] = {0};
168 unsigned int cnt;
169
170 pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj);
171 provides = xbps_dictionary_get(pkgd, "provides");
172 cnt = xbps_array_count(provides);
173 if (!cnt)
174 continue;
175
176 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
177 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
178 rv = EINVAL;
179 goto out;
180 }
181 for (unsigned int i = 0; i < cnt; i++) {
182 const char *vpkg = NULL;
183
184 xbps_array_get_cstring_nocopy(provides, i, &vpkg);
185 if (!xbps_dictionary_set_cstring(xhp->vpkgd, vpkg, pkgname)) {
186 xbps_dbg_printf("%s: set_cstring vpkg "
187 "%s pkgname %s\n", __func__, vpkg, pkgname);
188 rv = EINVAL;
189 goto out;
190 }
191 xbps_dbg_printf("[pkgdb] added vpkg %s for %s\n", vpkg, pkgname);
192 }
193 }
194out:
195 xbps_object_iterator_release(iter);
196 return rv;
197}
198
199static int
200pkgdb_map_names(struct xbps_handle *xhp)
201{
202 xbps_object_iterator_t iter;
203 xbps_object_t obj;
204 int rv = 0;
205
206 if (pkgdb_map_names_done || !xbps_dictionary_count(xhp->pkgdb))
207 return 0;
208
209 /*
210 * This maps all pkgs in pkgdb to have the "pkgname" string property.
211 * This way we do it once and not multiple times.
212 */
213 iter = xbps_dictionary_iterator(xhp->pkgdb);
214 assert(iter);
215
216 while ((obj = xbps_object_iterator_next(iter))) {
217 xbps_dictionary_t pkgd;
218 const char *pkgver;
219 char pkgname[XBPS_NAME_SIZE] = {0};
220
221 pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj);
222 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
223 continue;
224 }
225 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
226 rv = EINVAL;
227 break;
228 }
229 if (!xbps_dictionary_set_cstring(pkgd, "pkgname", pkgname)) {
230 rv = EINVAL;
231 break;
232 }
233 }
234 xbps_object_iterator_release(iter);
235 if (!rv) {
236 pkgdb_map_names_done = true;
237 }
238 return rv;
239}
240
241int HIDDEN
242xbps_pkgdb_init(struct xbps_handle *xhp)
243{
244 int rv;
245
246 assert(xhp);
247
248 if (xhp->pkgdb)
249 return 0;
250
251 if (!xhp->pkgdb_plist)
252 xhp->pkgdb_plist = xbps_xasprintf("%s/%s", xhp->metadir, XBPS_PKGDB);
253
254#if 0
255 if ((rv = xbps_pkgdb_conversion(xhp)) != 0)
256 return rv;
257#endif
258
259
260 if ((rv = xbps_pkgdb_update(xhp, false, true)) != 0) {
261 if (rv != ENOENT)
262 xbps_dbg_printf("[pkgdb] cannot internalize "
263 "pkgdb dictionary: %s\n", strerror(rv));
264
265 return rv;
266 }
267 if ((rv = pkgdb_map_names(xhp)) != 0) {
268 xbps_dbg_printf("[pkgdb] pkgdb_map_names %s\n", strerror(rv));
269 return rv;
270 }
271 if ((rv = pkgdb_map_vpkgs(xhp)) != 0) {
272 xbps_dbg_printf("[pkgdb] pkgdb_map_vpkgs %s\n", strerror(rv));
273 return rv;
274 }
275 assert(xhp->pkgdb);
276 xbps_dbg_printf("[pkgdb] initialized ok.\n");
277
278 return 0;
279}
280
281int
282xbps_pkgdb_update(struct xbps_handle *xhp, bool flush, bool update)
283{
284 xbps_dictionary_t pkgdb_storage;
285 mode_t prev_umask;
286 static int cached_rv;
287 int rv = 0;
288
289 if (cached_rv && !flush)
290 return cached_rv;
291
292 if (xhp->pkgdb && flush) {
293 pkgdb_storage = xbps_dictionary_internalize_from_file(xhp->pkgdb_plist);
294 if (pkgdb_storage == NULL ||
295 !xbps_dictionary_equals(xhp->pkgdb, pkgdb_storage)) {
296 /* flush dictionary to storage */
297 prev_umask = umask(022);
298 if (!xbps_dictionary_externalize_to_file(xhp->pkgdb, xhp->pkgdb_plist)) {
299 umask(prev_umask);
300 return errno;
301 }
302 umask(prev_umask);
303 }
304 if (pkgdb_storage)
305 xbps_object_release(pkgdb_storage);
306
307 xbps_object_release(xhp->pkgdb);
308 xhp->pkgdb = NULL;
309 cached_rv = 0;
310 }
311 if (!update)
312 return rv;
313
314 /* update copy in memory */
315 if ((xhp->pkgdb = xbps_dictionary_internalize_from_file(xhp->pkgdb_plist)) == NULL) {
316 rv = errno;
317 if (!rv)
318 rv = EINVAL;
319
320 if (rv == ENOENT)
321 xhp->pkgdb = xbps_dictionary_create();
322 else
323 xbps_error_printf("cannot access to pkgdb: %s\n", strerror(rv));
324
325 cached_rv = rv = errno;
326 }
327
328 return rv;
329}
330
331void HIDDEN
332xbps_pkgdb_release(struct xbps_handle *xhp)
333{
334 assert(xhp);
335
337 if (xhp->pkgdb)
338 xbps_object_release(xhp->pkgdb);
339 xbps_dbg_printf("[pkgdb] released ok.\n");
340}
341
342int
344 int (*fn)(struct xbps_handle *, xbps_object_t, const char *, void *, bool *),
345 void *arg)
346{
347 xbps_array_t allkeys;
348 int rv;
349
350 if ((rv = xbps_pkgdb_init(xhp)) != 0)
351 return rv;
352
353 allkeys = xbps_dictionary_all_keys(xhp->pkgdb);
354 assert(allkeys);
355 rv = xbps_array_foreach_cb(xhp, allkeys, xhp->pkgdb, fn, arg);
356 xbps_object_release(allkeys);
357 return rv;
358}
359
360int
362 int (*fn)(struct xbps_handle *, xbps_object_t, const char *, void *, bool *),
363 void *arg)
364{
365 xbps_array_t allkeys;
366 int rv;
367
368 if ((rv = xbps_pkgdb_init(xhp)) != 0)
369 return rv;
370
371 allkeys = xbps_dictionary_all_keys(xhp->pkgdb);
372 assert(allkeys);
373 rv = xbps_array_foreach_cb_multi(xhp, allkeys, xhp->pkgdb, fn, arg);
374 xbps_object_release(allkeys);
375 return rv;
376}
377
378xbps_dictionary_t
379xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
380{
381 if (xbps_pkgdb_init(xhp) != 0)
382 return NULL;
383
384 return xbps_find_pkg_in_dict(xhp->pkgdb, pkg);
385}
386
387xbps_dictionary_t
388xbps_pkgdb_get_virtualpkg(struct xbps_handle *xhp, const char *vpkg)
389{
390 if (xbps_pkgdb_init(xhp) != 0)
391 return NULL;
392
393 return xbps_find_virtualpkg_in_dict(xhp, xhp->pkgdb, vpkg);
394}
395
396static void
397generate_full_revdeps_tree(struct xbps_handle *xhp)
398{
399 xbps_object_t obj;
400 xbps_object_iterator_t iter;
401
402 if (xhp->pkgdb_revdeps)
403 return;
404
405 xhp->pkgdb_revdeps = xbps_dictionary_create();
406 assert(xhp->pkgdb_revdeps);
407
408 iter = xbps_dictionary_iterator(xhp->pkgdb);
409 assert(iter);
410
411 while ((obj = xbps_object_iterator_next(iter))) {
412 xbps_array_t rundeps;
413 xbps_dictionary_t pkgd;
414 const char *pkgver = NULL;
415
416 pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj);
417 rundeps = xbps_dictionary_get(pkgd, "run_depends");
418 if (!xbps_array_count(rundeps))
419 continue;
420
421 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
422 for (unsigned int i = 0; i < xbps_array_count(rundeps); i++) {
423 xbps_array_t pkg;
424 const char *pkgdep = NULL, *vpkgname = NULL;
425 char *v, curpkgname[XBPS_NAME_SIZE];
426 bool alloc = false;
427
428 xbps_array_get_cstring_nocopy(rundeps, i, &pkgdep);
429 if ((!xbps_pkgpattern_name(curpkgname, sizeof(curpkgname), pkgdep)) &&
430 (!xbps_pkg_name(curpkgname, sizeof(curpkgname), pkgdep))) {
431 abort();
432 }
433 vpkgname = vpkg_user_conf(xhp, curpkgname, false);
434 if (vpkgname == NULL) {
435 v = strdup(curpkgname);
436 } else {
437 v = strdup(vpkgname);
438 }
439
440 pkg = xbps_dictionary_get(xhp->pkgdb_revdeps, v);
441 if (pkg == NULL) {
442 alloc = true;
443 pkg = xbps_array_create();
444 }
445 if (!xbps_match_string_in_array(pkg, pkgver)) {
446 xbps_array_add_cstring_nocopy(pkg, pkgver);
447 xbps_dictionary_set(xhp->pkgdb_revdeps, v, pkg);
448 }
449 free(v);
450 if (alloc)
451 xbps_object_release(pkg);
452 }
453 }
454 xbps_object_iterator_release(iter);
455}
456
457xbps_array_t
458xbps_pkgdb_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg)
459{
460 xbps_dictionary_t pkgd;
461 const char *pkgver = NULL;
462 char pkgname[XBPS_NAME_SIZE];
463
464 if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkg)) == NULL)
465 return NULL;
466
467 generate_full_revdeps_tree(xhp);
468 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
469 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver))
470 return NULL;
471
472 return xbps_dictionary_get(xhp->pkgdb_revdeps, pkgname);
473}
474
475xbps_array_t
476xbps_pkgdb_get_pkg_fulldeptree(struct xbps_handle *xhp, const char *pkg)
477{
478 return xbps_get_pkg_fulldeptree(xhp, pkg, false);
479}
480
481xbps_dictionary_t
482xbps_pkgdb_get_pkg_files(struct xbps_handle *xhp, const char *pkg)
483{
484 xbps_dictionary_t pkgd;
485 const char *pkgver = NULL;
486 char pkgname[XBPS_NAME_SIZE], plist[PATH_MAX];
487
488 if (pkg == NULL)
489 return NULL;
490
491 pkgd = xbps_pkgdb_get_pkg(xhp, pkg);
492 if (pkgd == NULL)
493 return NULL;
494
495 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
496 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver))
497 return NULL;
498
499 snprintf(plist, sizeof(plist)-1, "%s/.%s-files.plist", xhp->metadir, pkgname);
501}
char metadir[XBPS_MAXPATH+sizeof(XBPS_META_PATH)]
Definition xbps.h:664
char rootdir[XBPS_MAXPATH]
Definition xbps.h:650
char * pkgdb_plist
Definition xbps.h:625
xbps_dictionary_t pkgdb
Definition xbps.h:576
Generic XBPS structure handler for initialization.
Definition xbps.h:550
xbps_array_t xbps_pkgdb_get_pkg_fulldeptree(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:476
int xbps_pkgdb_foreach_cb_multi(struct xbps_handle *xhp, int(*fn)(struct xbps_handle *, xbps_object_t, const char *, void *, bool *), void *arg)
Definition pkgdb.c:361
xbps_dictionary_t xbps_pkgdb_get_pkg_files(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:482
void xbps_pkgdb_unlock(struct xbps_handle *xhp)
xbps_dictionary_t xbps_pkgdb_get_virtualpkg(struct xbps_handle *xhp, const char *vpkg)
Definition pkgdb.c:388
int xbps_pkgdb_foreach_cb(struct xbps_handle *xhp, int(*fn)(struct xbps_handle *, xbps_object_t, const char *, void *, bool *), void *arg)
Definition pkgdb.c:343
xbps_array_t xbps_pkgdb_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:458
int xbps_pkgdb_update(struct xbps_handle *xhp, bool flush, bool update)
Definition pkgdb.c:282
int xbps_pkgdb_lock(struct xbps_handle *xhp)
Definition pkgdb.c:67
xbps_dictionary_t xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:379
bool xbps_match_string_in_array(xbps_array_t array, const char *val)
int xbps_array_foreach_cb_multi(struct xbps_handle *xhp, xbps_array_t array, xbps_dictionary_t dict, int(*fn)(struct xbps_handle *, xbps_object_t obj, const char *, void *arg, bool *done), void *arg)
int xbps_array_foreach_cb(struct xbps_handle *xhp, xbps_array_t array, xbps_dictionary_t dict, int(*fn)(struct xbps_handle *, xbps_object_t obj, const char *, void *arg, bool *done), void *arg)
xbps_dictionary_t xbps_plist_dictionary_from_file(const char *path)
char * xbps_xasprintf(const char *fmt,...) __attribute__((format(printf
bool xbps_pkg_name(char *dst, size_t len, const char *pkg)
Definition util.c:253
int xbps_mkpath(const char *path, mode_t mode)
Definition mkpath.c:42
bool xbps_pkgpattern_name(char *dst, size_t len, const char *pattern)
Definition util.c:289