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