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