1 /* opkg_conf.c - the opkg package management system
2 
3    Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com>
4 
5    Carl D. Worth
6    Copyright (C) 2001 University of Southern California
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17 */
18 
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <glob.h>
24 #include <unistd.h>
25 
26 #include "opkg_conf.h"
27 #include "pkg_vec.h"
28 #include "pkg.h"
29 #include "xregex.h"
30 #include "sprintf_alloc.h"
31 #include "opkg_message.h"
32 #include "file_util.h"
33 #include "opkg_defines.h"
34 #include "libbb/libbb.h"
35 
36 static int lock_fd;
37 static char *lock_file = NULL;
38 
39 static opkg_conf_t _conf;
40 opkg_conf_t *conf = &_conf;
41 
42 /*
43  * Config file options
44  */
45 opkg_option_t options[] = {
46 	{"cache", OPKG_OPT_TYPE_STRING, &_conf.cache},
47 	{"force_defaults", OPKG_OPT_TYPE_BOOL, &_conf.force_defaults},
48 	{"force_maintainer", OPKG_OPT_TYPE_BOOL, &_conf.force_maintainer},
49 	{"force_depends", OPKG_OPT_TYPE_BOOL, &_conf.force_depends},
50 	{"force_overwrite", OPKG_OPT_TYPE_BOOL, &_conf.force_overwrite},
51 	{"force_downgrade", OPKG_OPT_TYPE_BOOL, &_conf.force_downgrade},
52 	{"force_reinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_reinstall},
53 	{"force_space", OPKG_OPT_TYPE_BOOL, &_conf.force_space},
54 	{"force_postinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_postinstall},
55 	{"force_checksum", OPKG_OPT_TYPE_BOOL, &_conf.force_checksum},
56 	{"check_signature", OPKG_OPT_TYPE_BOOL, &_conf.check_signature},
57 	{"no_check_certificate", OPKG_OPT_TYPE_BOOL, &_conf.no_check_certificate},
58 	{"ftp_proxy", OPKG_OPT_TYPE_STRING, &_conf.ftp_proxy},
59 	{"http_proxy", OPKG_OPT_TYPE_STRING, &_conf.http_proxy},
60 	{"http_timeout", OPKG_OPT_TYPE_STRING, &_conf.http_timeout},
61 	{"no_proxy", OPKG_OPT_TYPE_STRING, &_conf.no_proxy},
62 	{"test", OPKG_OPT_TYPE_BOOL, &_conf.noaction},
63 	{"noaction", OPKG_OPT_TYPE_BOOL, &_conf.noaction},
64 	{"download_only", OPKG_OPT_TYPE_BOOL, &_conf.download_only},
65 	{"nodeps", OPKG_OPT_TYPE_BOOL, &_conf.nodeps},
66 	{"nocase", OPKG_OPT_TYPE_BOOL, &_conf.nocase},
67 	{"offline_root", OPKG_OPT_TYPE_STRING, &_conf.offline_root},
68 	{"overlay_root", OPKG_OPT_TYPE_STRING, &_conf.overlay_root},
69 	{"proxy_passwd", OPKG_OPT_TYPE_STRING, &_conf.proxy_passwd},
70 	{"proxy_user", OPKG_OPT_TYPE_STRING, &_conf.proxy_user},
71 	{"query-all", OPKG_OPT_TYPE_BOOL, &_conf.query_all},
72 	{"size", OPKG_OPT_TYPE_BOOL, &_conf.size},
73 	{"tmp_dir", OPKG_OPT_TYPE_STRING, &_conf.tmp_dir},
74 	{"verbosity", OPKG_OPT_TYPE_INT, &_conf.verbosity},
75 	{NULL, 0, NULL}
76 };
77 
resolve_pkg_dest_list(void)78 static int resolve_pkg_dest_list(void)
79 {
80 	nv_pair_list_elt_t *iter;
81 	nv_pair_t *nv_pair;
82 	pkg_dest_t *dest;
83 	char *root_dir;
84 
85 	for (iter = nv_pair_list_first(&conf->tmp_dest_list); iter;
86 	     iter = nv_pair_list_next(&conf->tmp_dest_list, iter)) {
87 		nv_pair = (nv_pair_t *) iter->data;
88 
89 		if (conf->offline_root) {
90 			sprintf_alloc(&root_dir, "%s%s", conf->offline_root,
91 				      nv_pair->value);
92 		} else {
93 			root_dir = xstrdup(nv_pair->value);
94 		}
95 
96 		dest =
97 		    pkg_dest_list_append(&conf->pkg_dest_list, nv_pair->name,
98 					 root_dir, conf->lists_dir);
99 		free(root_dir);
100 
101 		if (conf->default_dest == NULL)
102 			conf->default_dest = dest;
103 
104 		if (conf->dest_str && !strcmp(dest->name, conf->dest_str)) {
105 			conf->default_dest = dest;
106 			conf->restrict_to_default_dest = 1;
107 		}
108 	}
109 
110 	if (conf->dest_str && !conf->restrict_to_default_dest) {
111 		opkg_msg(ERROR, "Unknown dest name: `%s'.\n", conf->dest_str);
112 		return -1;
113 	}
114 
115 	return 0;
116 }
117 
opkg_conf_set_option(const char * name,const char * value)118 static int opkg_conf_set_option(const char *name, const char *value)
119 {
120 	int i = 0;
121 
122 	while (options[i].name) {
123 		if (strcmp(options[i].name, name) == 0) {
124 			switch (options[i].type) {
125 			case OPKG_OPT_TYPE_BOOL:
126 				if (*(int *)options[i].value) {
127 					opkg_msg(ERROR,
128 						 "Duplicate boolean option %s, "
129 						 "leaving this option on.\n",
130 						 name);
131 					return 0;
132 				}
133 				*((int *const)options[i].value) = 1;
134 				return 0;
135 			case OPKG_OPT_TYPE_INT:
136 				if (value) {
137 					if (*(int *)options[i].value) {
138 						opkg_msg(ERROR,
139 							 "Duplicate option %s, "
140 							 "using first seen value \"%d\".\n",
141 							 name,
142 							 *((int *)options[i].
143 							   value));
144 						return 0;
145 					}
146 					*((int *const)options[i].value) =
147 					    atoi(value);
148 					return 0;
149 				} else {
150 					opkg_msg(ERROR,
151 						 "Option %s needs an argument\n",
152 						 name);
153 					return -1;
154 				}
155 			case OPKG_OPT_TYPE_STRING:
156 				if (value) {
157 					if (*(char **)options[i].value) {
158 						opkg_msg(ERROR,
159 							 "Duplicate option %s, "
160 							 "using first seen value \"%s\".\n",
161 							 name,
162 							 *((char **)options[i].
163 							   value));
164 						return 0;
165 					}
166 					*((char **const)options[i].value) =
167 					    xstrdup(value);
168 					return 0;
169 				} else {
170 					opkg_msg(ERROR,
171 						 "Option %s needs an argument\n",
172 						 name);
173 					return -1;
174 				}
175 			}
176 		}
177 		i++;
178 	}
179 
180 	opkg_msg(ERROR, "Unrecognized option: %s=%s\n", name, value);
181 	return -1;
182 }
183 
184 static int
opkg_conf_parse_file(const char * filename,pkg_src_list_t * pkg_src_list,pkg_src_list_t * dist_src_list)185 opkg_conf_parse_file(const char *filename,
186 		     pkg_src_list_t * pkg_src_list,
187 		     pkg_src_list_t * dist_src_list)
188 {
189 	int line_num = 0;
190 	int err = 0;
191 	FILE *file;
192 	regex_t valid_line_re, comment_re;
193 #define regmatch_size 14
194 	regmatch_t regmatch[regmatch_size];
195 
196 	file = fopen(filename, "r");
197 	if (file == NULL) {
198 		opkg_perror(ERROR, "Failed to open %s", filename);
199 		err = -1;
200 		goto err0;
201 	}
202 
203 	opkg_msg(INFO, "Loading conf file %s.\n", filename);
204 
205 	err = xregcomp(&comment_re,
206 		       "^[[:space:]]*(#.*|[[:space:]]*)$", REG_EXTENDED);
207 	if (err)
208 		goto err1;
209 
210 	err = xregcomp(&valid_line_re,
211 		       "^[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))"
212 		       "[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))"
213 		       "[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))"
214 		       "([[:space:]]+([^[:space:]]+))?([[:space:]]+(.*))?[[:space:]]*$",
215 		       REG_EXTENDED);
216 	if (err)
217 		goto err2;
218 
219 	while (1) {
220 		char *line;
221 		char *type, *name, *value, *extra;
222 
223 		line_num++;
224 
225 		line = file_read_line_alloc(file);
226 		if (line == NULL)
227 			break;
228 
229 		if (regexec(&comment_re, line, 0, 0, 0) == 0)
230 			goto NEXT_LINE;
231 
232 		if (regexec(&valid_line_re, line, regmatch_size, regmatch, 0) ==
233 		    REG_NOMATCH) {
234 			opkg_msg(ERROR, "%s:%d: Ignoring invalid line: `%s'\n",
235 				 filename, line_num, line);
236 			goto NEXT_LINE;
237 		}
238 
239 		/* This has to be so ugly to deal with optional quotation marks */
240 		if (regmatch[2].rm_so > 0) {
241 			type = xstrndup(line + regmatch[2].rm_so,
242 					regmatch[2].rm_eo - regmatch[2].rm_so);
243 		} else {
244 			type = xstrndup(line + regmatch[3].rm_so,
245 					regmatch[3].rm_eo - regmatch[3].rm_so);
246 		}
247 
248 		if (regmatch[5].rm_so > 0) {
249 			name = xstrndup(line + regmatch[5].rm_so,
250 					regmatch[5].rm_eo - regmatch[5].rm_so);
251 		} else {
252 			name = xstrndup(line + regmatch[6].rm_so,
253 					regmatch[6].rm_eo - regmatch[6].rm_so);
254 		}
255 
256 		if (regmatch[8].rm_so > 0) {
257 			value = xstrndup(line + regmatch[8].rm_so,
258 					 regmatch[8].rm_eo - regmatch[8].rm_so);
259 		} else {
260 			value = xstrndup(line + regmatch[9].rm_so,
261 					 regmatch[9].rm_eo - regmatch[9].rm_so);
262 		}
263 
264 		extra = NULL;
265 		if (regmatch[11].rm_so > 0) {
266 			if (regmatch[13].rm_so > 0
267 			    && regmatch[13].rm_so != regmatch[13].rm_eo)
268 				extra =
269 				    xstrndup(line + regmatch[11].rm_so,
270 					     regmatch[13].rm_eo -
271 					     regmatch[11].rm_so);
272 			else
273 				extra = xstrndup(line + regmatch[11].rm_so,
274 						 regmatch[11].rm_eo -
275 						 regmatch[11].rm_so);
276 		}
277 
278 		if (regmatch[13].rm_so != regmatch[13].rm_eo
279 		    && strncmp(type, "dist", 4) != 0) {
280 			opkg_msg(ERROR,
281 				 "%s:%d: Ignoring config line with trailing garbage: `%s'\n",
282 				 filename, line_num, line);
283 		} else {
284 
285 			/* We use the conf->tmp_dest_list below instead of
286 			   conf->pkg_dest_list because we might encounter an
287 			   offline_root option later and that would invalidate the
288 			   directories we would have computed in
289 			   pkg_dest_list_init. (We do a similar thing with
290 			   tmp_src_nv_pair_list for sake of symmetry.) */
291 			if (strcmp(type, "option") == 0) {
292 				opkg_conf_set_option(name, value);
293 			} else if (strcmp(type, "dist") == 0) {
294 				if (!nv_pair_list_find
295 				    ((nv_pair_list_t *) dist_src_list, name)) {
296 					pkg_src_list_append(dist_src_list, name,
297 							    value, extra, 0);
298 				} else {
299 					opkg_msg(ERROR,
300 						 "Duplicate dist declaration (%s %s). "
301 						 "Skipping.\n", name, value);
302 				}
303 			} else if (strcmp(type, "dist/gz") == 0) {
304 				if (!nv_pair_list_find
305 				    ((nv_pair_list_t *) dist_src_list, name)) {
306 					pkg_src_list_append(dist_src_list, name,
307 							    value, extra, 1);
308 				} else {
309 					opkg_msg(ERROR,
310 						 "Duplicate dist declaration (%s %s). "
311 						 "Skipping.\n", name, value);
312 				}
313 			} else if (strcmp(type, "src") == 0) {
314 				if (!nv_pair_list_find
315 				    ((nv_pair_list_t *) pkg_src_list, name)) {
316 					pkg_src_list_append(pkg_src_list, name,
317 							    value, extra, 0);
318 				} else {
319 					opkg_msg(ERROR,
320 						 "Duplicate src declaration (%s %s). "
321 						 "Skipping.\n", name, value);
322 				}
323 			} else if (strcmp(type, "src/gz") == 0) {
324 				if (!nv_pair_list_find
325 				    ((nv_pair_list_t *) pkg_src_list, name)) {
326 					pkg_src_list_append(pkg_src_list, name,
327 							    value, extra, 1);
328 				} else {
329 					opkg_msg(ERROR,
330 						 "Duplicate src declaration (%s %s). "
331 						 "Skipping.\n", name, value);
332 				}
333 			} else if (strcmp(type, "dest") == 0) {
334 				nv_pair_list_append(&conf->tmp_dest_list, name,
335 						    value);
336 			} else if (strcmp(type, "lists_dir") == 0) {
337 				conf->lists_dir = xstrdup(value);
338 			} else if (strcmp(type, "arch") == 0) {
339 				opkg_msg(INFO,
340 					 "Supported arch %s priority (%s)\n",
341 					 name, value);
342 				if (!value) {
343 					opkg_msg(NOTICE,
344 						 "No priority given for architecture %s,"
345 						 "defaulting to 10\n", name);
346 					value = xstrdup("10");
347 				}
348 				nv_pair_list_append(&conf->arch_list, name,
349 						    value);
350 			} else {
351 				opkg_msg(ERROR,
352 					 "%s:%d: Ignoring invalid line: `%s'\n",
353 					 filename, line_num, line);
354 			}
355 
356 		}
357 
358 		free(type);
359 		free(name);
360 		free(value);
361 		if (extra)
362 			free(extra);
363 
364 NEXT_LINE:
365 		free(line);
366 	}
367 
368 	regfree(&valid_line_re);
369 err2:
370 	regfree(&comment_re);
371 err1:
372 	if (fclose(file) == EOF) {
373 		opkg_perror(ERROR, "Couldn't close %s", filename);
374 		err = -1;
375 	}
376 err0:
377 	return err;
378 }
379 
opkg_conf_write_status_files(void)380 int opkg_conf_write_status_files(void)
381 {
382 	pkg_dest_list_elt_t *iter;
383 	pkg_dest_t *dest;
384 	pkg_vec_t *all;
385 	pkg_t *pkg;
386 	int i, ret = 0;
387 
388 	if (conf->noaction)
389 		return 0;
390 
391 	list_for_each_entry(iter, &conf->pkg_dest_list.head, node) {
392 		dest = (pkg_dest_t *) iter->data;
393 
394 		dest->status_fp = fopen(dest->status_file_name, "w");
395 		if (dest->status_fp == NULL && errno != EROFS) {
396 			opkg_perror(ERROR, "Can't open status file %s",
397 				    dest->status_file_name);
398 			ret = -1;
399 		}
400 	}
401 
402 	all = pkg_vec_alloc();
403 	pkg_hash_fetch_available(all);
404 
405 	for (i = 0; i < all->len; i++) {
406 		pkg = all->pkgs[i];
407 		/* We don't need most uninstalled packages in the status file */
408 		if (pkg->state_status == SS_NOT_INSTALLED
409 		    && (pkg->state_want == SW_UNKNOWN
410 			|| (pkg->state_want == SW_DEINSTALL
411 			    && pkg->state_flag != SF_HOLD)
412 			|| pkg->state_want == SW_PURGE)) {
413 			continue;
414 		}
415 		if (pkg->dest == NULL) {
416 			opkg_msg(ERROR,
417 				 "Internal error: package %s has a NULL dest\n",
418 				 pkg->name);
419 			continue;
420 		}
421 		if (pkg->dest->status_fp)
422 			pkg_print_status(pkg, pkg->dest->status_fp);
423 	}
424 
425 	pkg_vec_free(all);
426 
427 	list_for_each_entry(iter, &conf->pkg_dest_list.head, node) {
428 		dest = (pkg_dest_t *) iter->data;
429 		if (dest->status_fp && fclose(dest->status_fp) == EOF) {
430 			opkg_perror(ERROR, "Couldn't close %s",
431 				    dest->status_file_name);
432 			ret = -1;
433 		}
434 	}
435 
436 	return ret;
437 }
438 
root_filename_alloc(char * filename)439 char *root_filename_alloc(char *filename)
440 {
441 	char *root_filename;
442 	sprintf_alloc(&root_filename, "%s%s",
443 		      (conf->offline_root ? conf->offline_root : ""), filename);
444 	return root_filename;
445 }
446 
glob_errfunc(const char * epath,int eerrno)447 static int glob_errfunc(const char *epath, int eerrno)
448 {
449 	if (eerrno == ENOENT)
450 		/* If leading dir does not exist, we get GLOB_NOMATCH. */
451 		return 0;
452 
453 	opkg_msg(ERROR, "glob failed for %s: %s\n", epath, strerror(eerrno));
454 	return 0;
455 }
456 
opkg_conf_init(void)457 int opkg_conf_init(void)
458 {
459 	pkg_src_list_init(&conf->pkg_src_list);
460 	pkg_src_list_init(&conf->dist_src_list);
461 	pkg_dest_list_init(&conf->pkg_dest_list);
462 	pkg_dest_list_init(&conf->tmp_dest_list);
463 	nv_pair_list_init(&conf->arch_list);
464 
465 	return 0;
466 }
467 
opkg_conf_load(void)468 int opkg_conf_load(void)
469 {
470 	int i, glob_ret;
471 	char *tmp, *tmp_dir_base, **tmp_val;
472 	glob_t globbuf;
473 	char *etc_opkg_conf_pattern;
474 
475 	conf->restrict_to_default_dest = 0;
476 	conf->default_dest = NULL;
477 
478 	if (!conf->offline_root)
479 		conf->offline_root = xstrdup(getenv("OFFLINE_ROOT"));
480 
481 	if (conf->conf_file) {
482 		struct stat st;
483 		if (stat(conf->conf_file, &st) == -1) {
484 			opkg_perror(ERROR, "Couldn't stat %s", conf->conf_file);
485 			goto err0;
486 		}
487 		if (opkg_conf_parse_file(conf->conf_file,
488 					 &conf->pkg_src_list,
489 					 &conf->dist_src_list))
490 			goto err1;
491 	}
492 
493 	if (conf->offline_root)
494 		sprintf_alloc(&etc_opkg_conf_pattern, "%s/etc/opkg/*.conf",
495 			      conf->offline_root);
496 	else {
497 		const char *conf_file_dir = getenv("OPKG_CONF_DIR");
498 		if (conf_file_dir == NULL)
499 			conf_file_dir = OPKG_CONF_DEFAULT_CONF_FILE_DIR;
500 		sprintf_alloc(&etc_opkg_conf_pattern, "%s/*.conf",
501 			      conf_file_dir);
502 	}
503 
504 	memset(&globbuf, 0, sizeof(globbuf));
505 	glob_ret = glob(etc_opkg_conf_pattern, 0, glob_errfunc, &globbuf);
506 	if (glob_ret && glob_ret != GLOB_NOMATCH) {
507 		free(etc_opkg_conf_pattern);
508 		globfree(&globbuf);
509 		goto err1;
510 	}
511 
512 	free(etc_opkg_conf_pattern);
513 
514 	for (i = 0; i < globbuf.gl_pathc; i++) {
515 		if (globbuf.gl_pathv[i])
516 			if (conf->conf_file &&
517 			    !strcmp(conf->conf_file, globbuf.gl_pathv[i]))
518 				continue;
519 		if (opkg_conf_parse_file(globbuf.gl_pathv[i],
520 					 &conf->pkg_src_list,
521 					 &conf->dist_src_list) < 0) {
522 			globfree(&globbuf);
523 			goto err1;
524 		}
525 	}
526 
527 	globfree(&globbuf);
528 
529 	if (conf->offline_root)
530 		sprintf_alloc(&lock_file, "%s/%s", conf->offline_root,
531 			      OPKGLOCKFILE);
532 	else
533 		sprintf_alloc(&lock_file, "%s", OPKGLOCKFILE);
534 
535 	lock_fd = creat(lock_file, S_IRUSR | S_IWUSR | S_IRGRP);
536 	if (lock_fd == -1) {
537 		opkg_perror(ERROR, "Could not create lock file %s", lock_file);
538 		goto err2;
539 	}
540 
541 	if (lockf(lock_fd, F_TLOCK, (off_t) 0) == -1) {
542 		opkg_perror(ERROR, "Could not lock %s", lock_file);
543 		if (close(lock_fd) == -1)
544 			opkg_perror(ERROR, "Couldn't close descriptor %d (%s)",
545 				    lock_fd, lock_file);
546 		lock_fd = -1;
547 		goto err2;
548 	}
549 
550 	if (conf->tmp_dir)
551 		tmp_dir_base = conf->tmp_dir;
552 	else
553 		tmp_dir_base = getenv("TMPDIR");
554 
555 	sprintf_alloc(&tmp, "%s/%s",
556 		      tmp_dir_base ? tmp_dir_base :
557 		      OPKG_CONF_DEFAULT_TMP_DIR_BASE, OPKG_CONF_TMP_DIR_SUFFIX);
558 	if (conf->tmp_dir)
559 		free(conf->tmp_dir);
560 	conf->tmp_dir = mkdtemp(tmp);
561 	if (conf->tmp_dir == NULL) {
562 		opkg_perror(ERROR, "Creating temp dir %s failed", tmp);
563 		goto err3;
564 	}
565 
566 	pkg_hash_init();
567 	hash_table_init("file-hash", &conf->file_hash,
568 			OPKG_CONF_DEFAULT_HASH_LEN);
569 	hash_table_init("obs-file-hash", &conf->obs_file_hash,
570 			OPKG_CONF_DEFAULT_HASH_LEN / 16);
571 
572 	if (conf->lists_dir == NULL)
573 		conf->lists_dir = xstrdup(OPKG_CONF_LISTS_DIR);
574 
575 	if (conf->offline_root) {
576 		sprintf_alloc(&tmp, "%s/%s", conf->offline_root,
577 			      conf->lists_dir);
578 		free(conf->lists_dir);
579 		conf->lists_dir = tmp;
580 	}
581 
582 	/* if no architectures were defined, then default all, noarch, and host architecture */
583 	if (nv_pair_list_empty(&conf->arch_list)) {
584 		nv_pair_list_append(&conf->arch_list, "all", "1");
585 		nv_pair_list_append(&conf->arch_list, "noarch", "1");
586 		nv_pair_list_append(&conf->arch_list, HOST_CPU_STR, "10");
587 	}
588 
589 	/* Even if there is no conf file, we'll need at least one dest. */
590 	if (nv_pair_list_empty(&conf->tmp_dest_list)) {
591 		nv_pair_list_append(&conf->tmp_dest_list,
592 				    OPKG_CONF_DEFAULT_DEST_NAME,
593 				    OPKG_CONF_DEFAULT_DEST_ROOT_DIR);
594 	}
595 
596 	if (resolve_pkg_dest_list())
597 		goto err4;
598 
599 	nv_pair_list_deinit(&conf->tmp_dest_list);
600 
601 	return 0;
602 
603 err4:
604 	free(conf->lists_dir);
605 
606 	pkg_hash_deinit();
607 	hash_table_deinit(&conf->file_hash);
608 	hash_table_deinit(&conf->obs_file_hash);
609 
610 	if (rmdir(conf->tmp_dir) == -1)
611 		opkg_perror(ERROR, "Couldn't remove dir %s", conf->tmp_dir);
612 err3:
613 	if (lockf(lock_fd, F_ULOCK, (off_t) 0) == -1)
614 		opkg_perror(ERROR, "Couldn't unlock %s", lock_file);
615 
616 	if (close(lock_fd) == -1)
617 		opkg_perror(ERROR, "Couldn't close descriptor %d (%s)",
618 			    lock_fd, lock_file);
619 	if (unlink(lock_file) == -1)
620 		opkg_perror(ERROR, "Couldn't unlink %s", lock_file);
621 err2:
622 	if (lock_file) {
623 		free(lock_file);
624 		lock_file = NULL;
625 	}
626 err1:
627 	pkg_src_list_deinit(&conf->pkg_src_list);
628 	pkg_src_list_deinit(&conf->dist_src_list);
629 	pkg_dest_list_deinit(&conf->pkg_dest_list);
630 	nv_pair_list_deinit(&conf->arch_list);
631 
632 	for (i = 0; options[i].name; i++) {
633 		if (options[i].type == OPKG_OPT_TYPE_STRING) {
634 			tmp_val = (char **)options[i].value;
635 			if (*tmp_val) {
636 				free(*tmp_val);
637 				*tmp_val = NULL;
638 			}
639 		}
640 	}
641 err0:
642 	nv_pair_list_deinit(&conf->tmp_dest_list);
643 	if (conf->dest_str)
644 		free(conf->dest_str);
645 	if (conf->conf_file)
646 		free(conf->conf_file);
647 
648 	return -1;
649 }
650 
opkg_conf_deinit(void)651 void opkg_conf_deinit(void)
652 {
653 	int i;
654 	char **tmp;
655 
656 	if (conf->tmp_dir)
657 		rm_r(conf->tmp_dir);
658 
659 	if (conf->lists_dir)
660 		free(conf->lists_dir);
661 
662 	if (conf->dest_str)
663 		free(conf->dest_str);
664 
665 	if (conf->conf_file)
666 		free(conf->conf_file);
667 
668 	pkg_src_list_deinit(&conf->pkg_src_list);
669 	pkg_src_list_deinit(&conf->dist_src_list);
670 	pkg_dest_list_deinit(&conf->pkg_dest_list);
671 	nv_pair_list_deinit(&conf->arch_list);
672 
673 	for (i = 0; options[i].name; i++) {
674 		if (options[i].type == OPKG_OPT_TYPE_STRING) {
675 			tmp = (char **)options[i].value;
676 			if (*tmp) {
677 				free(*tmp);
678 				*tmp = NULL;
679 			}
680 		}
681 	}
682 
683 	if (conf->verbosity >= DEBUG) {
684 		hash_print_stats(&conf->pkg_hash);
685 		hash_print_stats(&conf->file_hash);
686 		hash_print_stats(&conf->obs_file_hash);
687 	}
688 
689 	pkg_hash_deinit();
690 	hash_table_deinit(&conf->file_hash);
691 	hash_table_deinit(&conf->obs_file_hash);
692 
693 	if (lock_fd != -1) {
694 		if (lockf(lock_fd, F_ULOCK, (off_t) 0) == -1)
695 			opkg_perror(ERROR, "Couldn't unlock %s", lock_file);
696 
697 		if (close(lock_fd) == -1)
698 			opkg_perror(ERROR, "Couldn't close descriptor %d (%s)",
699 				    lock_fd, lock_file);
700 
701 	}
702 
703 	if (lock_file) {
704 		if (unlink(lock_file) == -1)
705 			opkg_perror(ERROR, "Couldn't unlink %s", lock_file);
706 
707 		free(lock_file);
708 	}
709 }
710