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