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 *
dpkg_arch_name_is_illegal(const char * name)56 dpkg_arch_name_is_illegal(const char *name)
57 {
58 static char buf[150];
59 const char *p = name;
60
61 if (name == NULL)
62 internerr("arch name argument is NULL");
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. */
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 *
dpkg_arch_new(const char * name,enum dpkg_arch_type type)112 dpkg_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 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 *
dpkg_arch_find(const char * name)136 dpkg_arch_find(const char *name)
137 {
138 struct dpkg_arch *arch, *last_arch = NULL;
139 enum dpkg_arch_type type;
140
141 if (name == NULL)
142 return &arch_item_none;
143 if (name[0] == '\0')
144 return &arch_item_empty;
145
146 for (arch = arch_head; arch; arch = arch->next) {
147 if (strcmp(arch->name, name) == 0)
148 return arch;
149 last_arch = arch;
150 }
151
152 if (dpkg_arch_name_is_illegal(name))
153 type = DPKG_ARCH_ILLEGAL;
154 else
155 type = DPKG_ARCH_UNKNOWN;
156
157 arch = dpkg_arch_new(name, type);
158 last_arch->next = arch;
159
160 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 *
dpkg_arch_get(enum dpkg_arch_type type)170 dpkg_arch_get(enum dpkg_arch_type type)
171 {
172 switch (type) {
173 case DPKG_ARCH_NONE:
174 return &arch_item_none;
175 case DPKG_ARCH_EMPTY:
176 return &arch_item_empty;
177 case DPKG_ARCH_WILDCARD:
178 return &arch_item_any;
179 case DPKG_ARCH_ALL:
180 return &arch_item_all;
181 case DPKG_ARCH_NATIVE:
182 return &arch_item_native;
183 case DPKG_ARCH_ILLEGAL:
184 case DPKG_ARCH_FOREIGN:
185 case DPKG_ARCH_UNKNOWN:
186 internerr("architecture type %d is not unique", type);
187 default:
188 /* Ignore unknown types for forward-compatibility. */
189 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 *
dpkg_arch_get_list(void)200 dpkg_arch_get_list(void)
201 {
202 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
dpkg_arch_reset_list(void)212 dpkg_arch_reset_list(void)
213 {
214 arch_builtin_tail->next = NULL;
215 arch_list_dirty = false;
216 }
217
218 void
varbuf_add_archqual(struct varbuf * vb,const struct dpkg_arch * arch)219 varbuf_add_archqual(struct varbuf *vb, const struct dpkg_arch *arch)
220 {
221 if (arch->type == DPKG_ARCH_NONE)
222 return;
223 if (arch->type == DPKG_ARCH_EMPTY)
224 return;
225
226 varbuf_add_char(vb, ':');
227 varbuf_add_str(vb, arch->name);
228 }
229
230 /**
231 * Return a descriptive architecture name.
232 */
233 const char *
dpkg_arch_describe(const struct dpkg_arch * arch)234 dpkg_arch_describe(const struct dpkg_arch *arch)
235 {
236 if (arch->type == DPKG_ARCH_NONE)
237 return C_("architecture", "<none>");
238 if (arch->type == DPKG_ARCH_EMPTY)
239 return C_("architecture", "<empty>");
240
241 return arch->name;
242 }
243
244 /**
245 * Add a new foreign dpkg_arch architecture.
246 */
247 struct dpkg_arch *
dpkg_arch_add(const char * name)248 dpkg_arch_add(const char *name)
249 {
250 struct dpkg_arch *arch;
251
252 arch = dpkg_arch_find(name);
253 if (arch->type == DPKG_ARCH_UNKNOWN) {
254 arch->type = DPKG_ARCH_FOREIGN;
255 arch_list_dirty = true;
256 }
257
258 return arch;
259 }
260
261 /**
262 * Unmark a foreign dpkg_arch architecture.
263 */
264 void
dpkg_arch_unmark(struct dpkg_arch * arch_remove)265 dpkg_arch_unmark(struct dpkg_arch *arch_remove)
266 {
267 struct dpkg_arch *arch;
268
269 for (arch = arch_builtin_tail->next; arch; arch = arch->next) {
270 if (arch->type != DPKG_ARCH_FOREIGN)
271 continue;
272
273 if (arch == arch_remove) {
274 arch->type = DPKG_ARCH_UNKNOWN;
275 arch_list_dirty = true;
276 return;
277 }
278 }
279 }
280
281 /**
282 * Load the architecture database.
283 */
284 void
dpkg_arch_load_list(void)285 dpkg_arch_load_list(void)
286 {
287 FILE *fp;
288 char *archfile;
289 char archname[_POSIX2_LINE_MAX];
290
291 archfile = dpkg_db_get_path(DPKG_DB_ARCH_FILE);
292 fp = fopen(archfile, "r");
293 if (fp == NULL) {
294 arch_list_dirty = true;
295 free(archfile);
296 return;
297 }
298
299 while (fgets_checked(archname, sizeof(archname), fp, archfile) >= 0)
300 dpkg_arch_add(archname);
301
302 free(archfile);
303 fclose(fp);
304 }
305
306 /**
307 * Save the architecture database.
308 */
309 void
dpkg_arch_save_list(void)310 dpkg_arch_save_list(void)
311 {
312 struct atomic_file *file;
313 struct dpkg_arch *arch;
314 char *archfile;
315
316 if (!arch_list_dirty)
317 return;
318
319 archfile = dpkg_db_get_path(DPKG_DB_ARCH_FILE);
320 file = atomic_file_new(archfile, 0);
321 atomic_file_open(file);
322
323 for (arch = arch_head; arch; arch = arch->next) {
324 if (arch->type != DPKG_ARCH_FOREIGN &&
325 arch->type != DPKG_ARCH_NATIVE)
326 continue;
327
328 if (fprintf(file->fp, "%s\n", arch->name) < 0)
329 ohshite(_("error writing to architecture list"));
330 }
331
332 atomic_file_sync(file);
333 atomic_file_close(file);
334 atomic_file_commit(file);
335 atomic_file_free(file);
336
337 dir_sync_path(dpkg_db_get_dir());
338
339 arch_list_dirty = false;
340
341 free(archfile);
342 }
343