XBPS Library API 20260214
The X Binary Package System
transaction_ops.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 <stdbool.h>
27#include <stdlib.h>
28#include <string.h>
29#include <errno.h>
30#include <fnmatch.h>
31
32#include "xbps_api_impl.h"
33
34/**
35 * @file lib/transaction_ops.c
36 * @brief Transaction handling routines
37 * @defgroup transaction Transaction handling functions
38 *
39 * The following image shows off the full transaction dictionary returned
40 * by xbps_transaction_prepare().
41 *
42 * @image html images/xbps_transaction_dictionary.png
43 *
44 * Legend:
45 * - <b>Salmon bg box</b>: The transaction dictionary.
46 * - <b>White bg box</b>: mandatory objects.
47 * - <b>Grey bg box</b>: optional objects.
48 * - <b>Green bg box</b>: possible value set in the object, only one of them
49 * will be set.
50 *
51 * Text inside of white boxes are the key associated with the object, its
52 * data type is specified on its edge, i.e string, array, integer, dictionary.
53 */
54static int
55trans_find_pkg(struct xbps_handle *xhp, const char *pkg, bool force)
56{
57 char buf[XBPS_NAME_SIZE];
58 xbps_dictionary_t pkg_pkgdb = NULL, pkg_repod = NULL, vpkg_pkgdb = NULL;
59 xbps_object_t obj;
60 xbps_array_t pkgs;
61 pkg_state_t state = 0;
63 const char *repoloc, *repopkgver, *instpkgver, *pkgname;
64 bool autoinst = false;
65 int rv = 0;
66
67 assert(pkg != NULL);
68
69 /*
70 * Find out if pkg is installed first.
71 */
72 if (xbps_pkg_name(buf, sizeof(buf), pkg)) {
73 pkg_pkgdb = xbps_pkgdb_get_pkg(xhp, buf);
74 if (!pkg_pkgdb)
75 vpkg_pkgdb = xbps_pkgdb_get_virtualpkg(xhp, buf);
76 } else {
77 pkg_pkgdb = xbps_pkgdb_get_pkg(xhp, pkg);
78 if (!pkg_pkgdb)
79 vpkg_pkgdb = xbps_pkgdb_get_virtualpkg(xhp, pkg);
80 }
81
82 if (xhp->flags & XBPS_FLAG_DOWNLOAD_ONLY) {
83 pkg_pkgdb = NULL;
84 ttype = XBPS_TRANS_DOWNLOAD;
85 }
86
87 if (vpkg_pkgdb) {
88 // virtual package installed, if there is no real package in
89 // the rpool, we are keeping the virtual package.
90 pkg_repod = xbps_rpool_get_pkg(xhp, pkg);
91 if (!pkg_repod) {
92 pkg_pkgdb = vpkg_pkgdb;
93 // if we are using the installed virtual package,
94 // use the provider to query the repository pool.
95 if (!xbps_dictionary_get_cstring_nocopy(
96 pkg_pkgdb, "pkgname", &pkg)) {
97 xbps_error_printf("missing `pkgname` property\n");
98 return EINVAL;
99 }
100 }
101 }
102 if (pkg_pkgdb) {
103 // package already installed
104 if (force) {
105 ttype = XBPS_TRANS_REINSTALL;
106 } else {
107 ttype = XBPS_TRANS_UPDATE;
108 }
109 if (xbps_dictionary_get(pkg_pkgdb, "repolock")) {
110 struct xbps_repo *repo;
111 /* find update from repo */
112 xbps_dictionary_get_cstring_nocopy(pkg_pkgdb, "repository", &repoloc);
113 assert(repoloc);
114 if ((repo = xbps_regget_repo(xhp, repoloc)) == NULL) {
115 /* not found */
116 return ENOENT;
117 }
118 pkg_repod = xbps_repo_get_pkg(repo, pkg);
119 } else {
120 /* find update from rpool */
121 pkg_repod = xbps_rpool_get_pkg(xhp, pkg);
122 }
123 } else {
124 ttype = XBPS_TRANS_INSTALL;
125 pkg_repod = xbps_rpool_get_pkg(xhp, pkg);
126 if (!pkg_repod)
127 pkg_repod = xbps_rpool_get_virtualpkg(xhp, pkg);
128 }
129
130 if (!pkg_repod) {
131 /* not found */
132 return ENOENT;
133 }
134
135 xbps_dictionary_get_cstring_nocopy(pkg_repod, "pkgver", &repopkgver);
136
137 if (ttype == XBPS_TRANS_UPDATE) {
138 /*
139 * Compare installed version vs best pkg available in repos
140 * for pkg updates.
141 */
142 xbps_dictionary_get_cstring_nocopy(pkg_pkgdb,
143 "pkgver", &instpkgver);
144 if (xbps_cmpver(repopkgver, instpkgver) <= 0 &&
145 !xbps_pkg_reverts(pkg_repod, instpkgver)) {
146 xbps_dictionary_get_cstring_nocopy(pkg_repod,
147 "repository", &repoloc);
148 xbps_dbg_printf("[rpool] Skipping `%s' "
149 "(installed: %s) from repository `%s'\n",
150 repopkgver, instpkgver, repoloc);
151 return EEXIST;
152 }
153 } else if (ttype == XBPS_TRANS_REINSTALL) {
154 /*
155 * For reinstallation check if installed version is less than
156 * or equal to the pkg in repos, if true, continue with reinstallation;
157 * otherwise perform an update.
158 */
159 xbps_dictionary_get_cstring_nocopy(pkg_pkgdb, "pkgver", &instpkgver);
160 if (xbps_cmpver(repopkgver, instpkgver) == 1) {
161 ttype = XBPS_TRANS_UPDATE;
162 }
163 }
164
165 if (pkg_pkgdb) {
166 /*
167 * If pkg is already installed, respect some properties.
168 */
169 if ((obj = xbps_dictionary_get(pkg_pkgdb, "automatic-install")))
170 xbps_dictionary_set(pkg_repod, "automatic-install", obj);
171 if ((obj = xbps_dictionary_get(pkg_pkgdb, "hold")))
172 xbps_dictionary_set(pkg_repod, "hold", obj);
173 if ((obj = xbps_dictionary_get(pkg_pkgdb, "repolock")))
174 xbps_dictionary_set(pkg_repod, "repolock", obj);
175 }
176 /*
177 * Prepare transaction dictionary.
178 */
179 if ((rv = xbps_transaction_init(xhp)) != 0)
180 return rv;
181
182 pkgs = xbps_dictionary_get(xhp->transd, "packages");
183 /*
184 * Find out if package being updated matches the one already
185 * in transaction, in that case ignore it.
186 */
187 if (ttype == XBPS_TRANS_UPDATE) {
188 if (xbps_find_pkg_in_array(pkgs, repopkgver, 0)) {
189 xbps_dbg_printf("[update] `%s' already queued in "
190 "transaction.\n", repopkgver);
191 return EEXIST;
192 }
193 }
194
195 if (!xbps_dictionary_get_cstring_nocopy(pkg_repod, "pkgname", &pkgname)) {
196 xbps_error_printf("missing `pkgname` property\n");
197 return EINVAL;
198 }
199 /*
200 * Set package state in dictionary with same state than the
201 * package currently uses, otherwise not-installed.
202 */
203 if ((rv = xbps_pkg_state_installed(xhp, pkgname, &state)) != 0) {
204 if (rv != ENOENT) {
205 return rv;
206 }
207 /* Package not installed, don't error out */
208 state = XBPS_PKG_STATE_NOT_INSTALLED;
209 }
210 if ((rv = xbps_set_pkg_state_dictionary(pkg_repod, state)) != 0) {
211 return rv;
212 }
213
214 if (state == XBPS_PKG_STATE_NOT_INSTALLED)
215 ttype = XBPS_TRANS_INSTALL;
216
217 if (!force && xbps_dictionary_get(pkg_repod, "hold"))
218 ttype = XBPS_TRANS_HOLD;
219
220 /*
221 * Store pkgd from repo into the transaction.
222 */
223 if (!xbps_transaction_pkg_type_set(pkg_repod, ttype)) {
224 return EINVAL;
225 }
226
227 /*
228 * Set automatic-install to true if it was requested and this is a new install.
229 */
230 if (ttype == XBPS_TRANS_INSTALL)
231 autoinst = xhp->flags & XBPS_FLAG_INSTALL_AUTO;
232
233 if (!xbps_transaction_store(xhp, pkgs, pkg_repod, autoinst)) {
234 return EINVAL;
235 }
236
237 return 0;
238}
239
240/*
241 * Returns 1 if there's an update, 0 if none or -1 on error.
242 */
243static int
244xbps_autoupdate(struct xbps_handle *xhp)
245{
246 xbps_array_t rdeps;
247 xbps_dictionary_t pkgd;
248 const char *pkgver = NULL, *pkgname = NULL;
249 int rv;
250
251 /*
252 * Check if there's a new update for XBPS before starting
253 * another transaction.
254 */
255 if (((pkgd = xbps_pkgdb_get_pkg(xhp, "xbps")) == NULL) &&
256 ((pkgd = xbps_pkgdb_get_virtualpkg(xhp, "xbps")) == NULL))
257 return 0;
258
259 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
260 return EINVAL;
261 }
262 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname)) {
263 return EINVAL;
264 }
265
266 rv = trans_find_pkg(xhp, pkgname, false);
267
268 xbps_dbg_printf("%s: trans_find_pkg xbps: %d\n", __func__, rv);
269
270 if (rv == 0) {
271 if (xhp->flags & XBPS_FLAG_DOWNLOAD_ONLY) {
272 return 0;
273 }
274 /* a new xbps version is available, check its revdeps */
275 rdeps = xbps_pkgdb_get_pkg_revdeps(xhp, "xbps");
276 for (unsigned int i = 0; i < xbps_array_count(rdeps); i++) {
277 const char *curpkgver = NULL;
278 char curpkgn[XBPS_NAME_SIZE] = {0};
279
280 xbps_array_get_cstring_nocopy(rdeps, i, &curpkgver);
281 xbps_dbg_printf("%s: processing revdep %s\n", __func__, curpkgver);
282
283 if (!xbps_pkg_name(curpkgn, sizeof(curpkgn), curpkgver)) {
284 abort();
285 }
286 rv = trans_find_pkg(xhp, curpkgn, false);
287 xbps_dbg_printf("%s: trans_find_pkg revdep %s: %d\n", __func__, curpkgver, rv);
288 if (rv && rv != ENOENT && rv != EEXIST && rv != ENODEV)
289 return -1;
290 }
291 /*
292 * Set XBPS_FLAG_FORCE_REMOVE_REVDEPS to ignore broken
293 * reverse dependencies in xbps_transaction_prepare().
294 *
295 * This won't skip revdeps of the xbps pkg, rather other
296 * packages in rootdir that could be broken indirectly.
297 *
298 * A sysup transaction after updating xbps should fix them
299 * again.
300 */
301 xhp->flags |= XBPS_FLAG_FORCE_REMOVE_REVDEPS;
302 return 1;
303 } else if (rv == ENOENT || rv == EEXIST || rv == ENODEV) {
304 /* no update */
305 return 0;
306 } else {
307 /* error */
308 return -1;
309 }
310
311 return 0;
312}
313
314int
316{
317 xbps_object_t obj;
318 xbps_object_iterator_t iter;
319 xbps_dictionary_t pkgd;
320 bool newpkg_found = false;
321 int rv = 0;
322
323 rv = xbps_autoupdate(xhp);
324 switch (rv) {
325 case 1:
326 /* xbps needs to be updated, don't allow any other update */
327 return EBUSY;
328 case -1:
329 /* error */
330 return EINVAL;
331 default:
332 break;
333 }
334
335 iter = xbps_dictionary_iterator(xhp->pkgdb);
336 assert(iter);
337
338 while ((obj = xbps_object_iterator_next(iter))) {
339 const char *pkgver = NULL;
340 char pkgname[XBPS_NAME_SIZE] = {0};
341
342 pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj);
343 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
344 continue;
345 }
346 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
347 rv = EINVAL;
348 break;
349 }
350 rv = trans_find_pkg(xhp, pkgname, false);
351 xbps_dbg_printf("%s: trans_find_pkg %s: %d\n", __func__, pkgver, rv);
352 if (rv == 0) {
353 newpkg_found = true;
354 } else if (rv == ENOENT || rv == EEXIST || rv == ENODEV) {
355 /*
356 * missing pkg or installed version is greater than or
357 * equal than pkg in repositories.
358 */
359 rv = 0;
360 }
361 }
362 xbps_object_iterator_release(iter);
363
364 return newpkg_found ? rv : EEXIST;
365}
366
367int
368xbps_transaction_update_pkg(struct xbps_handle *xhp, const char *pkg, bool force)
369{
370 xbps_array_t rdeps;
371 int rv;
372
373 rv = xbps_autoupdate(xhp);
374 xbps_dbg_printf("%s: xbps_autoupdate %d\n", __func__, rv);
375 switch (rv) {
376 case 1:
377 /* xbps needs to be updated, only allow xbps to be updated */
378 if (strcmp(pkg, "xbps"))
379 return EBUSY;
380 return 0;
381 case -1:
382 /* error */
383 return EINVAL;
384 default:
385 /* no update */
386 break;
387 }
388
389 /* update its reverse dependencies */
390 rdeps = xbps_pkgdb_get_pkg_revdeps(xhp, pkg);
391 if (xhp->flags & XBPS_FLAG_DOWNLOAD_ONLY) {
392 rdeps = NULL;
393 }
394 for (unsigned int i = 0; i < xbps_array_count(rdeps); i++) {
395 const char *pkgver = NULL;
396 char pkgname[XBPS_NAME_SIZE] = {0};
397
398 if (!xbps_array_get_cstring_nocopy(rdeps, i, &pkgver)) {
399 rv = EINVAL;
400 break;
401 }
402 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
403 rv = EINVAL;
404 break;
405 }
406 rv = trans_find_pkg(xhp, pkgname, false);
407 xbps_dbg_printf("%s: trans_find_pkg %s: %d\n", __func__, pkgver, rv);
408 if (rv && rv != ENOENT && rv != EEXIST && rv != ENODEV) {
409 return rv;
410 }
411 }
412 /* add pkg repod */
413 rv = trans_find_pkg(xhp, pkg, force);
414 xbps_dbg_printf("%s: trans_find_pkg %s: %d\n", __func__, pkg, rv);
415 return rv;
416}
417
418int
419xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, bool force)
420{
421 xbps_array_t rdeps;
422 int rv;
423
424 rv = xbps_autoupdate(xhp);
425 switch (rv) {
426 case 1:
427 /* xbps needs to be updated, only allow xbps to be updated */
428 if (strcmp(pkg, "xbps"))
429 return EBUSY;
430 return 0;
431 case -1:
432 /* error */
433 return EINVAL;
434 default:
435 /* no update */
436 break;
437 }
438
439 /* update its reverse dependencies */
440 rdeps = xbps_pkgdb_get_pkg_revdeps(xhp, pkg);
441 if (xhp->flags & XBPS_FLAG_DOWNLOAD_ONLY) {
442 rdeps = NULL;
443 }
444 for (unsigned int i = 0; i < xbps_array_count(rdeps); i++) {
445 const char *pkgver = NULL;
446 char pkgname[XBPS_NAME_SIZE] = {0};
447
448 if (!xbps_array_get_cstring_nocopy(rdeps, i, &pkgver)) {
449 rv = EINVAL;
450 break;
451 }
452 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
453 rv = EINVAL;
454 break;
455 }
456 rv = trans_find_pkg(xhp, pkgname, false);
457 xbps_dbg_printf("%s: trans_find_pkg %s: %d\n", __func__, pkgver, rv);
458 if (rv && rv != ENOENT && rv != EEXIST && rv != ENODEV) {
459 return rv;
460 }
461 }
462 rv = trans_find_pkg(xhp, pkg, force);
463 xbps_dbg_printf("%s: trans_find_pkg %s: %d\n", __func__, pkg, rv);
464 return rv;
465}
466
467int
469 const char *pkgname,
470 bool recursive)
471{
472 xbps_dictionary_t pkgd;
473 xbps_array_t pkgs, orphans, orphans_pkg;
474 xbps_object_t obj;
475 int rv = 0;
476
477 assert(xhp);
478 assert(pkgname);
479
480 if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) {
481 /* pkg not installed */
482 return ENOENT;
483 }
484 /*
485 * Prepare transaction dictionary and missing deps array.
486 */
487 if ((rv = xbps_transaction_init(xhp)) != 0)
488 return rv;
489
490 pkgs = xbps_dictionary_get(xhp->transd, "packages");
491
492 if (!recursive)
493 goto rmpkg;
494 /*
495 * If recursive is set, find out which packages would be orphans
496 * if the supplied package were already removed.
497 */
498 if ((orphans_pkg = xbps_array_create()) == NULL)
499 return ENOMEM;
500
501 xbps_array_set_cstring_nocopy(orphans_pkg, 0, pkgname);
502 orphans = xbps_find_pkg_orphans(xhp, orphans_pkg);
503 xbps_object_release(orphans_pkg);
504 if (xbps_object_type(orphans) != XBPS_TYPE_ARRAY)
505 return EINVAL;
506
507 for (unsigned int i = 0; i < xbps_array_count(orphans); i++) {
508 obj = xbps_array_get(orphans, i);
509 xbps_transaction_pkg_type_set(obj, XBPS_TRANS_REMOVE);
510 if (!xbps_transaction_store(xhp, pkgs, obj, false)) {
511 return EINVAL;
512 }
513 }
514 xbps_object_release(orphans);
515 return rv;
516
517rmpkg:
518 /*
519 * Add pkg dictionary into the transaction pkgs queue.
520 */
521 xbps_transaction_pkg_type_set(pkgd, XBPS_TRANS_REMOVE);
522 if (!xbps_transaction_store(xhp, pkgs, pkgd, false)) {
523 return EINVAL;
524 }
525 return rv;
526}
527
528int
530{
531 xbps_array_t orphans, pkgs;
532 xbps_object_t obj;
533 int rv = 0;
534
535 orphans = xbps_find_pkg_orphans(xhp, NULL);
536 if (xbps_array_count(orphans) == 0) {
537 /* no orphans? we are done */
538 goto out;
539 }
540 /*
541 * Prepare transaction dictionary and missing deps array.
542 */
543 if ((rv = xbps_transaction_init(xhp)) != 0)
544 goto out;
545
546 pkgs = xbps_dictionary_get(xhp->transd, "packages");
547 /*
548 * Add pkg orphan dictionary into the transaction pkgs queue.
549 */
550 for (unsigned int i = 0; i < xbps_array_count(orphans); i++) {
551 obj = xbps_array_get(orphans, i);
552 xbps_transaction_pkg_type_set(obj, XBPS_TRANS_REMOVE);
553 if (!xbps_transaction_store(xhp, pkgs, obj, false)) {
554 rv = EINVAL;
555 goto out;
556 }
557 }
558out:
559 if (orphans)
560 xbps_object_release(orphans);
561
562 return rv;
563}
564
566xbps_transaction_pkg_type(xbps_dictionary_t pkg_repod)
567{
568 uint8_t r;
569
570 if (xbps_object_type(pkg_repod) != XBPS_TYPE_DICTIONARY)
571 return 0;
572
573 if (!xbps_dictionary_get_uint8(pkg_repod, "transaction", &r))
574 return 0;
575
576 return r;
577}
578
579bool
580xbps_transaction_pkg_type_set(xbps_dictionary_t pkg_repod, xbps_trans_type_t ttype)
581{
582 uint8_t r;
583
584 if (xbps_object_type(pkg_repod) != XBPS_TYPE_DICTIONARY)
585 return false;
586
587 switch (ttype) {
588 case XBPS_TRANS_INSTALL:
589 case XBPS_TRANS_UPDATE:
590 case XBPS_TRANS_CONFIGURE:
591 case XBPS_TRANS_REMOVE:
592 case XBPS_TRANS_REINSTALL:
593 case XBPS_TRANS_HOLD:
594 case XBPS_TRANS_DOWNLOAD:
595 break;
596 default:
597 return false;
598 }
599 r = ttype;
600 if (!xbps_dictionary_set_uint8(pkg_repod, "transaction", r))
601 return false;
602
603 return true;
604}
xbps_dictionary_t pkgdb
Definition xbps.h:590
xbps_dictionary_t transd
Definition xbps.h:597
int flags
Definition xbps.h:693
Generic XBPS structure handler for initialization.
Definition xbps.h:560
void xbps_error_printf(const char *fmt,...)
Prints error messages to stderr.
Definition log.c:93
void xbps_dbg_printf(const char *fmt,...)
Prints debug messages to stderr.
Definition log.c:67
xbps_array_t xbps_find_pkg_orphans(struct xbps_handle *xhp, xbps_array_t orphans)
xbps_dictionary_t xbps_pkgdb_get_virtualpkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:422
xbps_array_t xbps_pkgdb_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:509
xbps_dictionary_t xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:408
int xbps_pkg_state_installed(struct xbps_handle *xhp, const char *pkgname, pkg_state_t *state)
int xbps_set_pkg_state_dictionary(xbps_dictionary_t dict, pkg_state_t state)
pkg_state_t
Definition xbps.h:1821
xbps_dictionary_t xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg)
Definition repo.c:598
struct xbps_handle * xhp
Definition xbps.h:1491
Repository structure.
Definition xbps.h:1479
xbps_dictionary_t xbps_rpool_get_virtualpkg(struct xbps_handle *xhp, const char *pkg)
Definition rpool.c:323
xbps_dictionary_t xbps_rpool_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition rpool.c:329
xbps_trans_type_t xbps_transaction_pkg_type(xbps_dictionary_t pkg_repod)
int xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, bool force)
int xbps_transaction_autoremove_pkgs(struct xbps_handle *xhp)
xbps_trans_type_t
Definition xbps.h:1390
int xbps_transaction_remove_pkg(struct xbps_handle *xhp, const char *pkgname, bool recursive)
bool xbps_transaction_pkg_type_set(xbps_dictionary_t pkg_repod, xbps_trans_type_t ttype)
int xbps_transaction_update_pkg(struct xbps_handle *xhp, const char *pkg, bool force)
int xbps_transaction_update_packages(struct xbps_handle *xhp)
bool xbps_pkg_name(char *dst, size_t len, const char *pkg)
Definition util.c:249
bool xbps_pkg_reverts(xbps_dictionary_t pkg, const char *pkgver)
Definition util.c:583
int xbps_cmpver(const char *pkg1, const char *pkg2)
Definition dewey.c:273