37#include "xbps_api_impl.h"
54 len = strlen(p) - strlen(strchr(p,
':'));
63 return strchr(str,
':') + 1;
71 for (p = path, seg = NULL; *p; p++) {
72 if (strncmp(p,
"/../", 4) == 0 || strncmp(p,
"/..", 4) == 0) {
73 memmove(seg ? seg : p, p+3, strlen(p+3) + 1);
74 return normpath(path);
75 }
else if (strncmp(p,
"/./", 3) == 0 || strncmp(p,
"/.", 3) == 0) {
76 memmove(p, p+2, strlen(p+2) + 1);
77 }
else if (strncmp(p,
"//", 2) == 0 || strncmp(p,
"/", 2) == 0) {
78 memmove(p, p+1, strlen(p+1) + 1);
87relpath(
char *from,
char *to)
92 assert(from[0] ==
'/');
97 for (; *from == *to && *to; from++, to++) {
102 for (up = -1, from--; from && *from; from = strchr(from + 1,
'/'), up++);
104 rel = calloc(3 * up + strlen(p), 1);
116remove_symlinks(
struct xbps_handle *xhp, xbps_array_t a,
const char *grname)
121 cnt = xbps_array_count(a);
122 for (i = 0; i < cnt; i++) {
126 str = xbps_array_get(a, i);
127 l = left(xbps_string_cstring_nocopy(str));
131 char *tgt_dup, *tgt_dir;
132 tgt = right(xbps_string_cstring_nocopy(str));
133 tgt_dup = strdup(tgt);
135 tgt_dir = dirname(tgt_dup);
141 if (lstat(lnk, &st) == -1 || !S_ISLNK(st.st_mode)) {
146 xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_LINK_REMOVED, 0, NULL,
147 "Removing '%s' alternatives group symlink: %s", grname, l);
157create_symlinks(
struct xbps_handle *xhp, xbps_array_t a,
const char *grname)
161 char *alternative, *tok1, *tok2, *linkpath, *target, *dir, *p;
163 n = xbps_array_count(a);
165 for (i = 0; i < n; i++) {
166 alternative = xbps_string_cstring(xbps_array_get(a, i));
168 if (!(tok1 = strtok(alternative,
":")) ||
169 !(tok2 = strtok(NULL,
":"))) {
174 target = strdup(tok2);
185 if (strcmp(dir,
".") &&
xbps_mkpath(dir, 0755) && errno != EEXIST) {
188 "failed to create target dir '%s' for group '%s': %s\n",
189 dir, grname, strerror(errno));
196 p = strdup(linkpath);
198 if (strcmp(dir,
".") &&
xbps_mkpath(dir, 0755) && errno != EEXIST) {
201 "failed to create symlink dir '%s' for group '%s': %s\n",
202 dir, grname, strerror(errno));
208 xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_LINK_ADDED, 0, NULL,
209 "Creating '%s' alternatives group symlink: %s -> %s",
210 grname, tok1, target);
212 if (target[0] ==
'/') {
213 p = relpath(linkpath + strlen(xhp->
rootdir), target);
219 if ((rv = symlink(target, linkpath)) != 0) {
221 "failed to create alt symlink '%s' for group '%s': %s\n",
222 linkpath, grname, strerror(errno));
244 xbps_array_t allkeys;
245 xbps_dictionary_t alternatives, pkg_alternatives, pkgd, prevpkgd, prevpkg_alts;
246 const char *pkgver = NULL, *prevpkgname = NULL;
252 alternatives = xbps_dictionary_get(xhp->
pkgdb,
"_XBPS_ALTERNATIVES_");
253 if (alternatives == NULL)
260 pkg_alternatives = xbps_dictionary_get(pkgd,
"alternatives");
261 if (!xbps_dictionary_count(pkg_alternatives))
264 if (group && !xbps_dictionary_get(pkg_alternatives, group))
267 xbps_dictionary_get_cstring_nocopy(pkgd,
"pkgver", &pkgver);
269 allkeys = xbps_dictionary_all_keys(pkg_alternatives);
270 for (
unsigned int i = 0; i < xbps_array_count(allkeys); i++) {
272 xbps_object_t keysym;
276 keysym = xbps_array_get(allkeys, i);
277 keyname = xbps_dictionary_keysym_cstring_nocopy(keysym);
279 if (group && strcmp(keyname, group))
282 array = xbps_dictionary_get(alternatives, keyname);
287 xbps_array_get_cstring_nocopy(array, 0, &prevpkgname);
288 if (prevpkgname && strcmp(pkgname, prevpkgname) != 0) {
290 (prevpkg_alts = xbps_dictionary_get(prevpkgd,
"alternatives")) &&
291 xbps_dictionary_count(prevpkg_alts)) {
292 rv = remove_symlinks(xhp,
293 xbps_dictionary_get(prevpkg_alts, keyname),
302 kstr = xbps_string_create_cstring(pkgname);
303 xbps_array_add_first(array, kstr);
304 xbps_object_release(kstr);
307 xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_ADDED, 0, NULL,
308 "%s: applying '%s' alternatives group", pkgver, keyname);
309 rv = create_symlinks(xhp, xbps_dictionary_get(pkg_alternatives, keyname), keyname);
310 if (rv != 0 || group)
313 xbps_object_release(allkeys);
318switch_alt_group(
struct xbps_handle *xhp,
const char *grpn,
const char *pkgn,
319 xbps_dictionary_t *pkg_alternatives)
321 xbps_dictionary_t curpkgd, pkgalts;
326 xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_SWITCHED, 0, NULL,
327 "Switched '%s' alternatives group to '%s'", grpn, pkgn);
328 pkgalts = xbps_dictionary_get(curpkgd,
"alternatives");
329 if (pkg_alternatives) *pkg_alternatives = pkgalts;
330 return create_symlinks(xhp, xbps_dictionary_get(pkgalts, grpn), grpn);
336 xbps_array_t allkeys;
337 xbps_dictionary_t alternatives, pkg_alternatives;
338 const char *pkgver, *pkgname;
344 alternatives = xbps_dictionary_get(xhp->
pkgdb,
"_XBPS_ALTERNATIVES_");
345 if (alternatives == NULL)
348 pkg_alternatives = xbps_dictionary_get(pkgd,
"alternatives");
349 if (!xbps_dictionary_count(pkg_alternatives))
352 xbps_dictionary_get_cstring_nocopy(pkgd,
"pkgver", &pkgver);
353 xbps_dictionary_get_cstring_nocopy(pkgd,
"pkgname", &pkgname);
355 xbps_dictionary_get_bool(pkgd,
"alternatives-update", &update);
357 allkeys = xbps_dictionary_all_keys(pkg_alternatives);
358 for (
unsigned int i = 0; i < xbps_array_count(allkeys); i++) {
360 xbps_object_t keysym;
361 bool current =
false;
362 const char *first = NULL, *keyname;
364 keysym = xbps_array_get(allkeys, i);
365 keyname = xbps_dictionary_keysym_cstring_nocopy(keysym);
367 array = xbps_dictionary_get(alternatives, keyname);
371 xbps_array_get_cstring_nocopy(array, 0, &first);
372 if (strcmp(pkgname, first) == 0) {
375 rv = remove_symlinks(xhp,
376 xbps_dictionary_get(pkg_alternatives, keyname),
383 xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_REMOVED, 0, NULL,
384 "%s: unregistered '%s' alternatives group", pkgver, keyname);
386 xbps_array_get_cstring_nocopy(array, 0, &first);
389 if (xbps_array_count(array) == 0) {
390 xbps_dictionary_remove(alternatives, keyname);
394 if (update || !current)
398 if (switch_alt_group(xhp, keyname, first, &pkg_alternatives) != 0)
401 xbps_object_release(allkeys);
414prune_altgroup(
struct xbps_handle *xhp, xbps_dictionary_t repod,
415 const char *pkgname,
const char *pkgver,
const char *keyname)
417 const char *newpkg = NULL, *curpkg = NULL;
419 xbps_dictionary_t alternatives;
421 unsigned int grp_count;
422 bool current =
false;
424 xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_REMOVED, 0, NULL,
425 "%s: unregistered '%s' alternatives group", pkgver, keyname);
427 alternatives = xbps_dictionary_get(xhp->
pkgdb,
"_XBPS_ALTERNATIVES_");
428 assert(alternatives);
429 array = xbps_dictionary_get(alternatives, keyname);
432 xbps_array_get_cstring_nocopy(array, 0, &curpkg);
433 current = (strcmp(pkgname, curpkg) == 0);
437 grp_count = xbps_array_count(array);
438 if (grp_count == 0) {
440 xbps_dictionary_remove(alternatives, keyname);
448 if (xbps_array_count(xbps_dictionary_get(repod,
"run_depends")) == 0 &&
449 xbps_array_count(xbps_dictionary_get(repod,
"shlib-requires")) == 0) {
454 xbps_array_get_cstring_nocopy(array, 0, &newpkg);
455 switch_alt_group(xhp, keyname, newpkg, NULL);
464 xbps_array_get_cstring_nocopy(array, grp_count - 1, &newpkg);
467 kstr = xbps_string_create_cstring(newpkg);
469 xbps_array_add_first(array, kstr);
470 xbps_array_get_cstring_nocopy(array, 0, &newpkg);
471 xbps_object_release(kstr);
473 switch_alt_group(xhp, keyname, newpkg, NULL);
478remove_obsoletes(
struct xbps_handle *xhp,
const char *pkgname,
const char *pkgver,
479 xbps_dictionary_t pkgdb_alts, xbps_dictionary_t repod)
481 xbps_array_t allkeys;
482 xbps_dictionary_t pkgd, pkgd_alts, repod_alts;
485 if (xbps_object_type(pkgd) != XBPS_TYPE_DICTIONARY) {
489 pkgd_alts = xbps_dictionary_get(pkgd,
"alternatives");
490 repod_alts = xbps_dictionary_get(repod,
"alternatives");
492 if (xbps_object_type(pkgd_alts) != XBPS_TYPE_DICTIONARY) {
496 allkeys = xbps_dictionary_all_keys(pkgd_alts);
497 for (
unsigned int i = 0; i < xbps_array_count(allkeys); i++) {
498 xbps_array_t array, array2, array_repo;
499 xbps_object_t keysym;
500 const char *keyname, *first = NULL;
502 keysym = xbps_array_get(allkeys, i);
503 array = xbps_dictionary_get_keysym(pkgd_alts, keysym);
504 keyname = xbps_dictionary_keysym_cstring_nocopy(keysym);
506 array_repo = xbps_dictionary_get(repod_alts, keyname);
507 if (!xbps_array_equals(array, array_repo)) {
511 array2 = xbps_dictionary_get(pkgdb_alts, keyname);
513 xbps_array_get_cstring_nocopy(array2, 0, &first);
514 if (strcmp(pkgname, first) == 0) {
515 remove_symlinks(xhp, array_repo, keyname);
525 if (xbps_array_count(array_repo) == 0) {
526 prune_altgroup(xhp, repod, pkgname, pkgver, keyname);
529 xbps_object_release(allkeys);
535 xbps_array_t allkeys;
536 xbps_dictionary_t alternatives, pkg_alternatives;
537 const char *pkgver, *pkgname;
542 if (xhp->
pkgdb == NULL)
545 alternatives = xbps_dictionary_get(xhp->
pkgdb,
"_XBPS_ALTERNATIVES_");
546 if (alternatives == NULL) {
547 alternatives = xbps_dictionary_create();
548 xbps_dictionary_set(xhp->
pkgdb,
"_XBPS_ALTERNATIVES_", alternatives);
549 xbps_object_release(alternatives);
551 alternatives = xbps_dictionary_get(xhp->
pkgdb,
"_XBPS_ALTERNATIVES_");
552 assert(alternatives);
554 xbps_dictionary_get_cstring_nocopy(pkg_repod,
"pkgver", &pkgver);
555 xbps_dictionary_get_cstring_nocopy(pkg_repod,
"pkgname", &pkgname);
561 remove_obsoletes(xhp, pkgname, pkgver, alternatives, pkg_repod);
563 pkg_alternatives = xbps_dictionary_get(pkg_repod,
"alternatives");
564 if (!xbps_dictionary_count(pkg_alternatives))
567 allkeys = xbps_dictionary_all_keys(pkg_alternatives);
568 for (
unsigned int i = 0; i < xbps_array_count(allkeys); i++) {
570 xbps_object_t keysym;
571 const char *keyname, *first = NULL;
573 keysym = xbps_array_get(allkeys, i);
574 keyname = xbps_dictionary_keysym_cstring_nocopy(keysym);
576 array = xbps_dictionary_get(alternatives, keyname);
578 array = xbps_array_create();
581 xbps_array_get_cstring_nocopy(array, 0, &first);
582 if (strcmp(pkgname, first)) {
587 rv = create_symlinks(xhp,
588 xbps_dictionary_get(pkg_alternatives, keyname),
594 xbps_array_add_cstring(array, pkgname);
595 xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_ADDED, 0, NULL,
596 "%s: registered '%s' alternatives group", pkgver, keyname);
601 xbps_array_add_cstring(array, pkgname);
602 xbps_dictionary_set(alternatives, keyname, array);
603 xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_ADDED, 0, NULL,
604 "%s: registered '%s' alternatives group", pkgver, keyname);
606 rv = create_symlinks(xhp,
607 xbps_dictionary_get(pkg_alternatives, keyname),
609 xbps_object_release(array);
613 xbps_object_release(allkeys);
int xbps_alternatives_register(struct xbps_handle *xhp, xbps_dictionary_t pkg_repod)
int xbps_alternatives_set(struct xbps_handle *xhp, const char *pkgname, const char *group)
int xbps_alternatives_unregister(struct xbps_handle *xhp, xbps_dictionary_t pkgd)
char rootdir[XBPS_MAXPATH]
Generic XBPS structure handler for initialization.
xbps_dictionary_t xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
bool xbps_match_string_in_array(xbps_array_t array, const char *val)
char * xbps_xasprintf(const char *fmt,...) __attribute__((format(printf
int xbps_mkpath(const char *path, mode_t mode)
bool xbps_remove_string_from_array(xbps_array_t array, const char *str)