XBPS Library API 20260501
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))
285 rv = trans_find_pkg(xhp, curpkgn, false);
286 xbps_dbg_printf("%s: trans_find_pkg revdep %s: %d\n", __func__, curpkgver, rv);
287 if (rv && rv != ENOENT && rv != EEXIST && rv != ENODEV)
288 return -1;
289 }
290 /*
291 * Set XBPS_FLAG_FORCE_REMOVE_REVDEPS to ignore broken
292 * reverse dependencies in xbps_transaction_prepare().
293 *
294 * This won't skip revdeps of the xbps pkg, rather other
295 * packages in rootdir that could be broken indirectly.
296 *
297 * A sysup transaction after updating xbps should fix them
298 * again.
299 */
300 xhp->flags |= XBPS_FLAG_FORCE_REMOVE_REVDEPS;
301 return 1;
302 } else if (rv == ENOENT || rv == EEXIST || rv == ENODEV) {
303 /* no update */
304 return 0;
305 } else {
306 /* error */
307 return -1;
308 }
309
310 return 0;
311}
312
313int
315{
316 xbps_object_t obj;
317 xbps_object_iterator_t iter;
318 xbps_dictionary_t pkgd;
319 bool newpkg_found = false;
320 int rv = 0;
321
322 rv = xbps_autoupdate(xhp);
323 switch (rv) {
324 case 1:
325 /* xbps needs to be updated, don't allow any other update */
326 return EBUSY;
327 case -1:
328 /* error */
329 return EINVAL;
330 default:
331 break;
332 }
333
334 iter = xbps_dictionary_iterator(xhp->pkgdb);
335 assert(iter);
336
337 while ((obj = xbps_object_iterator_next(iter))) {
338 const char *pkgver = NULL;
339 char pkgname[XBPS_NAME_SIZE] = {0};
340
341 pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj);
342 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
343 continue;
344 }
345 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
346 rv = EINVAL;
347 break;
348 }
349 rv = trans_find_pkg(xhp, pkgname, false);
350 xbps_dbg_printf("%s: trans_find_pkg %s: %d\n", __func__, pkgver, rv);
351 if (rv == 0) {
352 newpkg_found = true;
353 } else if (rv == ENOENT || rv == EEXIST || rv == ENODEV) {
354 /*
355 * missing pkg or installed version is greater than or
356 * equal than pkg in repositories.
357 */
358 rv = 0;
359 }
360 }
361 xbps_object_iterator_release(iter);
362
363 return newpkg_found ? rv : EEXIST;
364}
365
366int
367xbps_transaction_update_pkg(struct xbps_handle *xhp, const char *pkg, bool force)
368{
369 xbps_array_t rdeps;
370 int rv;
371
372 rv = xbps_autoupdate(xhp);
373 xbps_dbg_printf("%s: xbps_autoupdate %d\n", __func__, rv);
374 switch (rv) {
375 case 1:
376 /* xbps needs to be updated, only allow xbps to be updated */
377 if (strcmp(pkg, "xbps"))
378 return EBUSY;
379 return 0;
380 case -1:
381 /* error */
382 return EINVAL;
383 default:
384 /* no update */
385 break;
386 }
387
388 /* update its reverse dependencies */
389 rdeps = xbps_pkgdb_get_pkg_revdeps(xhp, pkg);
390 if (xhp->flags & XBPS_FLAG_DOWNLOAD_ONLY) {
391 rdeps = NULL;
392 }
393 for (unsigned int i = 0; i < xbps_array_count(rdeps); i++) {
394 char pkgname[XBPS_NAME_SIZE];
395 const char *pkgver = NULL;
396
397 if (!xbps_array_get_cstring_nocopy(rdeps, i, &pkgver))
399 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver))
401
402 rv = trans_find_pkg(xhp, pkgname, false);
403 xbps_dbg_printf("%s: trans_find_pkg %s: %d\n", __func__, pkgver, rv);
404 if (rv && rv != ENOENT && rv != EEXIST && rv != ENODEV) {
405 return rv;
406 }
407 }
408 /* add pkg repod */
409 rv = trans_find_pkg(xhp, pkg, force);
410 xbps_dbg_printf("%s: trans_find_pkg %s: %d\n", __func__, pkg, rv);
411 return rv;
412}
413
414int
415xbps_transaction_install_pkg(struct xbps_handle *xhp, const char *pkg, bool force)
416{
417 xbps_array_t rdeps;
418 int rv;
419
420 rv = xbps_autoupdate(xhp);
421 switch (rv) {
422 case 1:
423 /* xbps needs to be updated, only allow xbps to be updated */
424 if (strcmp(pkg, "xbps"))
425 return EBUSY;
426 return 0;
427 case -1:
428 /* error */
429 return EINVAL;
430 default:
431 /* no update */
432 break;
433 }
434
435 /* update its reverse dependencies */
436 rdeps = xbps_pkgdb_get_pkg_revdeps(xhp, pkg);
437 if (xhp->flags & XBPS_FLAG_DOWNLOAD_ONLY) {
438 rdeps = NULL;
439 }
440 for (unsigned int i = 0; i < xbps_array_count(rdeps); i++) {
441 char pkgname[XBPS_NAME_SIZE];
442 const char *pkgver = NULL;
443
444 if (!xbps_array_get_cstring_nocopy(rdeps, i, &pkgver))
446 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver))
448
449 rv = trans_find_pkg(xhp, pkgname, false);
450 xbps_dbg_printf("%s: trans_find_pkg %s: %d\n", __func__, pkgver, rv);
451 if (rv && rv != ENOENT && rv != EEXIST && rv != ENODEV) {
452 return rv;
453 }
454 }
455 rv = trans_find_pkg(xhp, pkg, force);
456 xbps_dbg_printf("%s: trans_find_pkg %s: %d\n", __func__, pkg, rv);
457 return rv;
458}
459
460int
462 const char *pkgname,
463 bool recursive)
464{
465 xbps_dictionary_t pkgd;
466 xbps_array_t pkgs, orphans, orphans_pkg;
467 xbps_object_t obj;
468 int rv = 0;
469
470 assert(xhp);
471 assert(pkgname);
472
473 if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) {
474 /* pkg not installed */
475 return ENOENT;
476 }
477 /*
478 * Prepare transaction dictionary and missing deps array.
479 */
480 if ((rv = xbps_transaction_init(xhp)) != 0)
481 return rv;
482
483 pkgs = xbps_dictionary_get(xhp->transd, "packages");
484
485 if (!recursive)
486 goto rmpkg;
487 /*
488 * If recursive is set, find out which packages would be orphans
489 * if the supplied package were already removed.
490 */
491 if ((orphans_pkg = xbps_array_create()) == NULL)
492 return ENOMEM;
493
494 xbps_array_set_cstring_nocopy(orphans_pkg, 0, pkgname);
495 orphans = xbps_find_pkg_orphans(xhp, orphans_pkg);
496 xbps_object_release(orphans_pkg);
497 if (xbps_object_type(orphans) != XBPS_TYPE_ARRAY)
498 return EINVAL;
499
500 for (unsigned int i = 0; i < xbps_array_count(orphans); i++) {
501 obj = xbps_array_get(orphans, i);
502 xbps_transaction_pkg_type_set(obj, XBPS_TRANS_REMOVE);
503 if (!xbps_transaction_store(xhp, pkgs, obj, false)) {
504 return EINVAL;
505 }
506 }
507 xbps_object_release(orphans);
508 return rv;
509
510rmpkg:
511 /*
512 * Add pkg dictionary into the transaction pkgs queue.
513 */
514 xbps_transaction_pkg_type_set(pkgd, XBPS_TRANS_REMOVE);
515 if (!xbps_transaction_store(xhp, pkgs, pkgd, false)) {
516 return EINVAL;
517 }
518 return rv;
519}
520
521int
523{
524 xbps_array_t orphans, pkgs;
525 xbps_object_t obj;
526 int rv = 0;
527
528 orphans = xbps_find_pkg_orphans(xhp, NULL);
529 if (xbps_array_count(orphans) == 0) {
530 /* no orphans? we are done */
531 goto out;
532 }
533 /*
534 * Prepare transaction dictionary and missing deps array.
535 */
536 if ((rv = xbps_transaction_init(xhp)) != 0)
537 goto out;
538
539 pkgs = xbps_dictionary_get(xhp->transd, "packages");
540 /*
541 * Add pkg orphan dictionary into the transaction pkgs queue.
542 */
543 for (unsigned int i = 0; i < xbps_array_count(orphans); i++) {
544 obj = xbps_array_get(orphans, i);
545 xbps_transaction_pkg_type_set(obj, XBPS_TRANS_REMOVE);
546 if (!xbps_transaction_store(xhp, pkgs, obj, false)) {
547 rv = EINVAL;
548 goto out;
549 }
550 }
551out:
552 if (orphans)
553 xbps_object_release(orphans);
554
555 return rv;
556}
557
559xbps_transaction_pkg_type(xbps_dictionary_t pkg_repod)
560{
561 uint8_t r;
562
563 if (xbps_object_type(pkg_repod) != XBPS_TYPE_DICTIONARY)
564 return 0;
565
566 if (!xbps_dictionary_get_uint8(pkg_repod, "transaction", &r))
567 return 0;
568
569 return r;
570}
571
572bool
573xbps_transaction_pkg_type_set(xbps_dictionary_t pkg_repod, xbps_trans_type_t ttype)
574{
575 uint8_t r;
576
577 if (xbps_object_type(pkg_repod) != XBPS_TYPE_DICTIONARY)
578 return false;
579
580 switch (ttype) {
581 case XBPS_TRANS_INSTALL:
582 case XBPS_TRANS_UPDATE:
583 case XBPS_TRANS_CONFIGURE:
584 case XBPS_TRANS_REMOVE:
585 case XBPS_TRANS_REINSTALL:
586 case XBPS_TRANS_HOLD:
587 case XBPS_TRANS_DOWNLOAD:
588 break;
589 default:
590 return false;
591 }
592 r = ttype;
593 if (!xbps_dictionary_set_uint8(pkg_repod, "transaction", r))
594 return false;
595
596 return true;
597}
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
#define xbps_unreachable()
Log and abort for code that should be unreachable.
Definition xbps.h:783
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:403
xbps_array_t xbps_pkgdb_get_pkg_revdeps(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:490
xbps_dictionary_t xbps_pkgdb_get_pkg(struct xbps_handle *xhp, const char *pkg)
Definition pkgdb.c:389
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:1831
xbps_dictionary_t xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg)
Definition repo.c:610
struct xbps_handle * xhp
Definition xbps.h:1501
Repository structure.
Definition xbps.h:1489
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:1400
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