Branch data Line data Source code
1 : : /*
2 : : * libdpkg - Debian packaging suite library routines
3 : : * arch.c - architecture database functions
4 : : *
5 : : * Copyright © 2011 Linaro Limited
6 : : * Copyright © 2011 Raphaël Hertzog <hertzog@debian.org>
7 : : * Copyright © 2011-2014 Guillem Jover <guillem@debian.org>
8 : : *
9 : : * This is free software; you can redistribute it and/or modify
10 : : * it under the terms of the GNU General Public License as published by
11 : : * the Free Software Foundation; either version 2 of the License, or
12 : : * (at your option) any later version.
13 : : *
14 : : * This is distributed in the hope that it will be useful,
15 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : : * GNU General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU General Public License
20 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : : */
22 : :
23 : : #include <config.h>
24 : : #include <compat.h>
25 : :
26 : : #include <limits.h>
27 : : #include <string.h>
28 : : #include <stdbool.h>
29 : : #include <stdlib.h>
30 : : #include <stdio.h>
31 : :
32 : : #include <dpkg/i18n.h>
33 : : #include <dpkg/c-ctype.h>
34 : : #include <dpkg/ehandle.h>
35 : : #include <dpkg/dpkg.h>
36 : : #include <dpkg/dpkg-db.h>
37 : : #include <dpkg/dir.h>
38 : : #include <dpkg/varbuf.h>
39 : : #include <dpkg/arch.h>
40 : :
41 : : #define DPKG_DB_ARCH_FILE "arch"
42 : :
43 : : /**
44 : : * Verify if the architecture name is valid.
45 : : *
46 : : * Returns NULL if the architecture name is valid. Otherwise it returns a
47 : : * string describing why it's not valid. Currently it ensures the name
48 : : * starts with an alphanumeric and is then composed of a combinations of
49 : : * hyphens and alphanumerics.
50 : : *
51 : : * The function will abort if you pass it a NULL pointer.
52 : : *
53 : : * @param name The architecture name to verify.
54 : : */
55 : : const char *
56 : 33 : dpkg_arch_name_is_illegal(const char *name)
57 : : {
58 : : static char buf[150];
59 : 33 : const char *p = name;
60 : :
61 [ - + ]: 33 : if (p == NULL)
62 : 0 : internerr("arch name argument is NULL");
63 [ + + ]: 33 : if (!*p)
64 : 1 : return _("may not be empty string");
65 [ + + ]: 32 : if (!c_isalnum(*p))
66 : 3 : return _("must start with an alphanumeric");
67 [ + + ]: 156 : while (*++p != '\0')
68 [ + + + + ]: 133 : if (!c_isalnum(*p) && *p != '-')
69 : 6 : break;
70 [ + + ]: 29 : if (*p == '\0')
71 : 23 : return NULL;
72 : :
73 : 6 : snprintf(buf, sizeof(buf), _("character '%c' not allowed (only "
74 : : "letters, digits and characters '%s')"),
75 : 6 : *p, "-");
76 : 6 : return buf;
77 : : }
78 : :
79 : : /* This is a special architecture used to guarantee we always have a valid
80 : : * structure to handle. */
81 : : static struct dpkg_arch arch_item_none = {
82 : : .name = "",
83 : : .type = DPKG_ARCH_NONE,
84 : : .next = NULL,
85 : : };
86 : : static struct dpkg_arch arch_item_empty = {
87 : : .name = "",
88 : : .type = DPKG_ARCH_EMPTY,
89 : : .next = NULL,
90 : : };
91 : :
92 : : static struct dpkg_arch arch_item_any = {
93 : : .name = "any",
94 : : .type = DPKG_ARCH_WILDCARD,
95 : : .next = NULL,
96 : : };
97 : : static struct dpkg_arch arch_item_all = {
98 : : .name = "all",
99 : : .type = DPKG_ARCH_ALL,
100 : : .next = &arch_item_any,
101 : : };
102 : : static struct dpkg_arch arch_item_native = {
103 : : .name = ARCHITECTURE,
104 : : .type = DPKG_ARCH_NATIVE,
105 : : .next = &arch_item_all,
106 : : };
107 : : static struct dpkg_arch *arch_head = &arch_item_native;
108 : : static struct dpkg_arch *arch_builtin_tail = &arch_item_any;
109 : : static bool arch_list_dirty;
110 : :
111 : : static struct dpkg_arch *
112 : 10 : dpkg_arch_new(const char *name, enum dpkg_arch_type type)
113 : : {
114 : : struct dpkg_arch *new;
115 : :
116 : 10 : new = nfmalloc(sizeof(*new));
117 : 10 : new->next = NULL;
118 : 10 : new->name = nfstrsave(name);
119 : 10 : new->type = type;
120 : :
121 : 10 : return new;
122 : : }
123 : :
124 : : /**
125 : : * Retrieve the struct dpkg_arch for the given architecture.
126 : : *
127 : : * Create a new structure for the architecture if it is not yet known from
128 : : * the system, in that case it will have type == DPKG_ARCH_UNKNOWN, if the
129 : : * architecture is illegal it will have type == DPKG_ARCH_ILLEGAL, if name
130 : : * is an empty string it will have type == DPKG_ARCH_EMPTY, and if it is
131 : : * NULL then it will have type == DPKG_ARCH_NONE.
132 : : *
133 : : * @param name The architecture name.
134 : : */
135 : : struct dpkg_arch *
136 : 51 : dpkg_arch_find(const char *name)
137 : : {
138 : 51 : struct dpkg_arch *arch, *last_arch = NULL;
139 : : enum dpkg_arch_type type;
140 : :
141 [ + + ]: 51 : if (name == NULL)
142 : 2 : return &arch_item_none;
143 [ + + ]: 49 : if (name[0] == '\0')
144 : 1 : return &arch_item_empty;
145 : :
146 [ + + ]: 132 : for (arch = arch_head; arch; arch = arch->next) {
147 [ + + ]: 122 : if (strcmp(arch->name, name) == 0)
148 : 38 : return arch;
149 : 84 : last_arch = arch;
150 : : }
151 : :
152 [ + + ]: 10 : if (dpkg_arch_name_is_illegal(name))
153 : 1 : type = DPKG_ARCH_ILLEGAL;
154 : : else
155 : 9 : type = DPKG_ARCH_UNKNOWN;
156 : :
157 : 10 : arch = dpkg_arch_new(name, type);
158 : 10 : last_arch->next = arch;
159 : :
160 : 10 : return arch;
161 : : }
162 : :
163 : : /**
164 : : * Return the struct dpkg_arch corresponding to the architecture type.
165 : : *
166 : : * The function only returns instances for types which are unique. For
167 : : * forward-compatibility any unknown type will return NULL.
168 : : */
169 : : struct dpkg_arch *
170 : 261 : dpkg_arch_get(enum dpkg_arch_type type)
171 : : {
172 [ + + + + : 261 : switch (type) {
+ - + ]
173 : 247 : case DPKG_ARCH_NONE:
174 : 247 : return &arch_item_none;
175 : 3 : case DPKG_ARCH_EMPTY:
176 : 3 : return &arch_item_empty;
177 : 3 : case DPKG_ARCH_WILDCARD:
178 : 3 : return &arch_item_any;
179 : 5 : case DPKG_ARCH_ALL:
180 : 5 : return &arch_item_all;
181 : 2 : case DPKG_ARCH_NATIVE:
182 : 2 : return &arch_item_native;
183 : 0 : case DPKG_ARCH_ILLEGAL:
184 : : case DPKG_ARCH_FOREIGN:
185 : : case DPKG_ARCH_UNKNOWN:
186 : 0 : internerr("architecture type %d is not unique", type);
187 : 1 : default:
188 : : /* Ignore unknown types for forward-compatibility. */
189 : 1 : return NULL;
190 : : }
191 : : }
192 : :
193 : : /**
194 : : * Return the complete list of architectures.
195 : : *
196 : : * In fact it returns the first item of the linked list and you can
197 : : * traverse the list by following arch->next until it's NULL.
198 : : */
199 : : struct dpkg_arch *
200 : 2 : dpkg_arch_get_list(void)
201 : : {
202 : 2 : return arch_head;
203 : : }
204 : :
205 : : /**
206 : : * Reset the list of architectures.
207 : : *
208 : : * Must be called before nffreeall() to ensure we don't point to
209 : : * unallocated memory.
210 : : */
211 : : void
212 : 55 : dpkg_arch_reset_list(void)
213 : : {
214 : 55 : arch_builtin_tail->next = NULL;
215 : 55 : arch_list_dirty = false;
216 : 55 : }
217 : :
218 : : void
219 : 4 : varbuf_add_archqual(struct varbuf *vb, const struct dpkg_arch *arch)
220 : : {
221 [ + + ]: 4 : if (arch->type == DPKG_ARCH_NONE)
222 : 1 : return;
223 [ + + ]: 3 : if (arch->type == DPKG_ARCH_EMPTY)
224 : 1 : return;
225 : :
226 : 2 : varbuf_add_char(vb, ':');
227 : 2 : varbuf_add_str(vb, arch->name);
228 : : }
229 : :
230 : : /**
231 : : * Return a descriptive architecture name.
232 : : */
233 : : const char *
234 : 10 : dpkg_arch_describe(const struct dpkg_arch *arch)
235 : : {
236 [ + + ]: 10 : if (arch->type == DPKG_ARCH_NONE)
237 : 2 : return C_("architecture", "<none>");
238 [ + + ]: 8 : if (arch->type == DPKG_ARCH_EMPTY)
239 : 2 : return C_("architecture", "<empty>");
240 : :
241 : 6 : return arch->name;
242 : : }
243 : :
244 : : /**
245 : : * Add a new foreign dpkg_arch architecture.
246 : : */
247 : : struct dpkg_arch *
248 : 2 : dpkg_arch_add(const char *name)
249 : : {
250 : : struct dpkg_arch *arch;
251 : :
252 : 2 : arch = dpkg_arch_find(name);
253 [ + - ]: 2 : if (arch->type == DPKG_ARCH_UNKNOWN) {
254 : 2 : arch->type = DPKG_ARCH_FOREIGN;
255 : 2 : arch_list_dirty = true;
256 : : }
257 : :
258 : 2 : return arch;
259 : : }
260 : :
261 : : /**
262 : : * Unmark a foreign dpkg_arch architecture.
263 : : */
264 : : void
265 : 3 : dpkg_arch_unmark(const struct dpkg_arch *arch_remove)
266 : : {
267 : : struct dpkg_arch *arch;
268 : :
269 [ + + ]: 7 : for (arch = arch_builtin_tail->next; arch; arch = arch->next) {
270 [ + + ]: 6 : if (arch->type != DPKG_ARCH_FOREIGN)
271 : 3 : continue;
272 : :
273 [ + + ]: 3 : if (arch == arch_remove) {
274 : 2 : arch->type = DPKG_ARCH_UNKNOWN;
275 : 2 : arch_list_dirty = true;
276 : 2 : return;
277 : : }
278 : : }
279 : : }
280 : :
281 : : /**
282 : : * Load the architecture database.
283 : : */
284 : : void
285 : 74 : dpkg_arch_load_list(void)
286 : : {
287 : : FILE *fp;
288 : : char *archfile;
289 : : char archname[_POSIX2_LINE_MAX];
290 : :
291 : 74 : archfile = dpkg_db_get_path(DPKG_DB_ARCH_FILE);
292 : 74 : fp = fopen(archfile, "r");
293 [ + - ]: 74 : if (fp == NULL) {
294 : 74 : arch_list_dirty = true;
295 : 74 : free(archfile);
296 : 74 : return;
297 : : }
298 : :
299 [ # # ]: 0 : while (fgets_checked(archname, sizeof(archname), fp, archfile) >= 0)
300 : 0 : dpkg_arch_add(archname);
301 : :
302 : 0 : free(archfile);
303 : 0 : fclose(fp);
304 : : }
305 : :
306 : : /**
307 : : * Save the architecture database.
308 : : */
309 : : void
310 : 0 : dpkg_arch_save_list(void)
311 : : {
312 : : struct atomic_file *file;
313 : : struct dpkg_arch *arch;
314 : : char *archfile;
315 : :
316 [ # # ]: 0 : if (!arch_list_dirty)
317 : 0 : return;
318 : :
319 : 0 : archfile = dpkg_db_get_path(DPKG_DB_ARCH_FILE);
320 : 0 : file = atomic_file_new(archfile, ATOMIC_FILE_MKPATH);
321 : 0 : atomic_file_open(file);
322 : :
323 [ # # ]: 0 : for (arch = arch_head; arch; arch = arch->next) {
324 [ # # ]: 0 : if (arch->type != DPKG_ARCH_FOREIGN &&
325 [ # # ]: 0 : arch->type != DPKG_ARCH_NATIVE)
326 : 0 : continue;
327 : :
328 [ # # ]: 0 : if (fprintf(file->fp, "%s\n", arch->name) < 0)
329 : 0 : ohshite(_("error writing to architecture list"));
330 : : }
331 : :
332 : 0 : atomic_file_sync(file);
333 : 0 : atomic_file_close(file);
334 : 0 : atomic_file_commit(file);
335 : 0 : atomic_file_free(file);
336 : :
337 : 0 : dir_sync_path(dpkg_db_get_dir());
338 : :
339 : 0 : arch_list_dirty = false;
340 : :
341 : 0 : free(archfile);
342 : : }
|