XBPS Library API 20240111
The X Binary Package System
transaction_check_shlibs.c
1/*-
2 * Copyright (c) 2014-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#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <stdbool.h>
29#include <errno.h>
30
31#include "xbps_api_impl.h"
32
33/*
34 * Verify shlib-{provides,requires} for packages in transaction.
35 * This will catch cases where a package update would break its reverse
36 * dependencies due to an incompatible SONAME bump:
37 *
38 * - foo-1.0 is installed and provides the 'libfoo.so.0' soname.
39 * - foo-2.0 provides the 'libfoo.so.1' soname.
40 * - baz-1.0 requires 'libfoo.so.0'.
41 * - foo is updated to 2.0, hence baz-1.0 is now broken.
42 *
43 * Abort transaction if such case is found.
44 */
45
46static void
47shlib_register(xbps_dictionary_t d, const char *shlib, const char *pkgver)
48{
49 xbps_array_t array;
50 bool alloc = false;
51
52 if ((array = xbps_dictionary_get(d, shlib)) == NULL) {
53 alloc = true;
54 array = xbps_array_create();
55 xbps_dictionary_set(d, shlib, array);
56 }
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);
61}
62
63static xbps_dictionary_t
64collect_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs, bool req)
65{
66 xbps_object_t obj;
67 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;
87
88 /* ignore shlibs if pkg is on hold mode */
89 if (xbps_transaction_pkg_type(obj) == XBPS_TRANS_HOLD) {
90 continue;
91 }
92
93 xbps_dictionary_set(pd, pkgname, obj);
94 }
95 xbps_object_iterator_release(iter);
96
97 /*
98 * iterate over our dictionary to collect shlib-{requires,provides}.
99 */
100 iter = xbps_dictionary_iterator(pd);
101 assert(iter);
102
103 while ((obj = xbps_object_iterator_next(iter))) {
104 xbps_array_t shobjs;
105 xbps_dictionary_t pkgd;
106
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)
118 continue;
119
120 for (unsigned int i = 0; i < xbps_array_count(shobjs); i++) {
121 const char *shlib = NULL;
122
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);
130 }
131 }
132 xbps_object_iterator_release(iter);
133 xbps_object_release(pd);
134 return d;
135}
136
137bool HIDDEN
138xbps_transaction_check_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs)
139{
140 xbps_array_t array, mshlibs;
141 xbps_object_t obj, obj2;
142 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;
147
148 shrequires = collect_shlibs(xhp, pkgs, true);
149 shprovides = collect_shlibs(xhp, pkgs, false);
150
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);
155
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));
162 continue;
163 }
164 xbps_dbg_printf_append("not found\n");
165
166 broken = true;
167 array = xbps_dictionary_get_keysym(shrequires, obj);
168 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);
174 }
175 }
176 xbps_object_iterator_release(iter);
177 if (!broken) {
178 xbps_dictionary_remove(xhp->transd, "missing_shlibs");
179 }
180 xbps_object_release(shprovides);
181 xbps_object_release(shrequires);
182
183 return true;
184}
xbps_dictionary_t transd
Definition xbps.h:583
xbps_dictionary_t pkgdb
Definition xbps.h:576
Generic XBPS structure handler for initialization.
Definition xbps.h:550
bool xbps_match_string_in_array(xbps_array_t array, const char *val)
xbps_trans_type_t xbps_transaction_pkg_type(xbps_dictionary_t pkg_repod)
char * xbps_xasprintf(const char *fmt,...) __attribute__((format(printf