30602bf87f6850f05a6b4ddcb46a66b96150cc6a
[oweals/opkg-lede.git] / libopkg / pkg.c
1 /* pkg.c - the opkg package management system
2
3    Carl D. Worth
4
5    Copyright (C) 2001 University of Southern California
6
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2, or (at
10    your option) any later version.
11
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 */
17
18 #include "config.h"
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <unistd.h>
24 #include <libgen.h>
25
26 #include "pkg.h"
27
28 #include "pkg_parse.h"
29 #include "pkg_extract.h"
30 #include "opkg_message.h"
31 #include "opkg_utils.h"
32
33 #include "libbb/libbb.h"
34 #include "sprintf_alloc.h"
35 #include "file_util.h"
36 #include "xsystem.h"
37 #include "opkg_conf.h"
38
39 typedef struct enum_map enum_map_t;
40 struct enum_map {
41         unsigned int value;
42         const char *str;
43 };
44
45 static const enum_map_t pkg_state_want_map[] = {
46         {SW_UNKNOWN, "unknown"},
47         {SW_INSTALL, "install"},
48         {SW_DEINSTALL, "deinstall"},
49         {SW_PURGE, "purge"}
50 };
51
52 static const enum_map_t pkg_state_flag_map[] = {
53         {SF_OK, "ok"},
54         {SF_REINSTREQ, "reinstreq"},
55         {SF_HOLD, "hold"},
56         {SF_REPLACE, "replace"},
57         {SF_NOPRUNE, "noprune"},
58         {SF_PREFER, "prefer"},
59         {SF_OBSOLETE, "obsolete"},
60         {SF_USER, "user"},
61 };
62
63 static const enum_map_t pkg_state_status_map[] = {
64         {SS_NOT_INSTALLED, "not-installed"},
65         {SS_UNPACKED, "unpacked"},
66         {SS_HALF_CONFIGURED, "half-configured"},
67         {SS_INSTALLED, "installed"},
68         {SS_HALF_INSTALLED, "half-installed"},
69         {SS_CONFIG_FILES, "config-files"},
70         {SS_POST_INST_FAILED, "post-inst-failed"},
71         {SS_REMOVAL_FAILED, "removal-failed"}
72 };
73
74 static void pkg_init(pkg_t * pkg)
75 {
76         pkg->name = NULL;
77         pkg->dest = NULL;
78         pkg->src = NULL;
79         pkg->state_want = SW_UNKNOWN;
80         pkg->state_flag = SF_OK;
81         pkg->state_status = SS_NOT_INSTALLED;
82         pkg->depends_str = NULL;
83         pkg->provides_str = NULL;
84         pkg->depends_count = 0;
85         pkg->depends = NULL;
86         pkg->suggests_str = NULL;
87         pkg->recommends_str = NULL;
88         pkg->suggests_count = 0;
89         pkg->recommends_count = 0;
90
91         active_list_init(&pkg->list);
92
93         pkg->conflicts = NULL;
94         pkg->conflicts_count = 0;
95
96         pkg->replaces = NULL;
97         pkg->replaces_count = 0;
98
99         pkg->pre_depends_count = 0;
100         pkg->pre_depends_str = NULL;
101         pkg->provides_count = 0;
102         pkg->provides = NULL;
103         pkg->tmp_unpack_dir = NULL;
104         pkg->size = 0;
105         pkg->installed_size = 0;
106         conffile_list_init(&pkg->conffiles);
107         pkg->installed_files = NULL;
108         pkg->installed_files_ref_cnt = 0;
109         pkg->essential = 0;
110         pkg->provided_by_hand = 0;
111
112         blob_buf_init(&pkg->blob, 0);
113 }
114
115 pkg_t *pkg_new(void)
116 {
117         pkg_t *pkg;
118
119         pkg = xcalloc(1, sizeof(pkg_t));
120         pkg_init(pkg);
121
122         return pkg;
123 }
124
125 void *pkg_set_raw(pkg_t *pkg, int id, const void *val, size_t len)
126 {
127         int rem;
128         struct blob_attr *cur;
129
130         blob_for_each_attr(cur, pkg->blob.head, rem) {
131                 if (blob_id(cur) == id) {
132                         if (blob_len(cur) < len) {
133                                 fprintf(stderr, "ERROR: truncating field %d <%p> to %d byte",
134                                         id, val, blob_len(cur));
135                         }
136                         memcpy(blob_data(cur), val, blob_len(cur));
137                         return blob_data(cur);
138                 }
139         }
140
141         cur = blob_put(&pkg->blob, id, val, len);
142         return cur ? blob_data(cur) : NULL;
143 }
144
145 void *pkg_get_raw(const pkg_t * pkg, int id)
146 {
147         int rem;
148         struct blob_attr *cur;
149
150         blob_for_each_attr(cur, pkg->blob.head, rem)
151                 if (blob_id(cur) == id)
152                         return blob_data(cur);
153
154         return NULL;
155 }
156
157 char *pkg_set_string(pkg_t *pkg, int id, const char *s)
158 {
159         size_t len;
160         char *p;
161
162         if (!s)
163                 return NULL;
164
165         len = strlen(s);
166
167         while (isspace(*s)) {
168                 s++;
169                 len--;
170         }
171
172         while (len > 0 && isspace(s[len - 1]))
173                 len--;
174
175         if (!len)
176                 return NULL;
177
178         p = pkg_set_raw(pkg, id, s, len + 1);
179         p[len] = 0;
180
181         return p;
182 }
183
184
185 static void compound_depend_deinit(compound_depend_t * depends)
186 {
187         int i;
188         for (i = 0; i < depends->possibility_count; i++) {
189                 depend_t *d;
190                 d = depends->possibilities[i];
191                 free(d->version);
192                 free(d);
193         }
194         free(depends->possibilities);
195 }
196
197 void pkg_deinit(pkg_t * pkg)
198 {
199         int i;
200
201         if (pkg->name)
202                 free(pkg->name);
203         pkg->name = NULL;
204
205         /* owned by opkg_conf_t */
206         pkg->dest = NULL;
207         /* owned by opkg_conf_t */
208         pkg->src = NULL;
209
210         pkg->state_want = SW_UNKNOWN;
211         pkg->state_flag = SF_OK;
212         pkg->state_status = SS_NOT_INSTALLED;
213
214         active_list_clear(&pkg->list);
215
216         if (pkg->replaces)
217                 free(pkg->replaces);
218         pkg->replaces = NULL;
219
220         if (pkg->depends) {
221                 int count = pkg->pre_depends_count
222                     + pkg->depends_count
223                     + pkg->recommends_count + pkg->suggests_count;
224
225                 for (i = 0; i < count; i++)
226                         compound_depend_deinit(&pkg->depends[i]);
227                 free(pkg->depends);
228         }
229
230         if (pkg->conflicts) {
231                 for (i = 0; i < pkg->conflicts_count; i++)
232                         compound_depend_deinit(&pkg->conflicts[i]);
233                 free(pkg->conflicts);
234         }
235
236         if (pkg->provides)
237                 free(pkg->provides);
238
239         pkg->pre_depends_count = 0;
240         pkg->provides_count = 0;
241
242         /* CLEANUP: It'd be nice to pullin the cleanup function from
243            opkg_install.c here. See comment in
244            opkg_install.c:cleanup_temporary_files */
245         if (pkg->tmp_unpack_dir)
246                 free(pkg->tmp_unpack_dir);
247         pkg->tmp_unpack_dir = NULL;
248
249         conffile_list_deinit(&pkg->conffiles);
250
251         /* XXX: QUESTION: Is forcing this to 1 correct? I suppose so,
252            since if they are calling deinit, they should know. Maybe do an
253            assertion here instead? */
254         pkg->installed_files_ref_cnt = 1;
255         pkg_free_installed_files(pkg);
256         pkg->essential = 0;
257
258         blob_buf_free(&pkg->blob);
259 }
260
261 int pkg_init_from_file(pkg_t * pkg, const char *filename)
262 {
263         int fd, err = 0;
264         FILE *control_file;
265         char *control_path, *tmp;
266
267         pkg_init(pkg);
268
269         pkg_set_string(pkg, PKG_LOCAL_FILENAME, filename);
270
271         tmp = xstrdup(filename);
272         sprintf_alloc(&control_path, "%s/%s.control.XXXXXX",
273                       conf->tmp_dir, basename(tmp));
274         free(tmp);
275         fd = mkstemp(control_path);
276         if (fd == -1) {
277                 opkg_perror(ERROR, "Failed to make temp file %s", control_path);
278                 err = -1;
279                 goto err0;
280         }
281
282         control_file = fdopen(fd, "r+");
283         if (control_file == NULL) {
284                 opkg_perror(ERROR, "Failed to fdopen %s", control_path);
285                 close(fd);
286                 err = -1;
287                 goto err1;
288         }
289
290         err = pkg_extract_control_file_to_stream(pkg, control_file);
291         if (err) {
292                 opkg_msg(ERROR, "Failed to extract control file from %s.\n",
293                          filename);
294                 goto err2;
295         }
296
297         rewind(control_file);
298
299         if ((err = pkg_parse_from_stream(pkg, control_file, 0))) {
300                 if (err == 1) {
301                         opkg_msg(ERROR, "Malformed package file %s.\n",
302                                  filename);
303                 }
304                 err = -1;
305         }
306
307 err2:
308         fclose(control_file);
309 err1:
310         unlink(control_path);
311 err0:
312         free(control_path);
313
314         return err;
315 }
316
317 /* Merge any new information in newpkg into oldpkg */
318 int pkg_merge(pkg_t * oldpkg, pkg_t * newpkg)
319 {
320         if (oldpkg == newpkg) {
321                 return 0;
322         }
323
324         if (!oldpkg->auto_installed)
325                 oldpkg->auto_installed = newpkg->auto_installed;
326
327         if (!oldpkg->src)
328                 oldpkg->src = newpkg->src;
329         if (!oldpkg->dest)
330                 oldpkg->dest = newpkg->dest;
331         if (!pkg_get_string(oldpkg, PKG_ARCHITECTURE))
332                 pkg_set_string(oldpkg, PKG_ARCHITECTURE, pkg_get_string(newpkg, PKG_ARCHITECTURE));
333         if (!oldpkg->arch_priority)
334                 oldpkg->arch_priority = newpkg->arch_priority;
335         if (!pkg_get_string(oldpkg, PKG_SECTION))
336                 pkg_set_string(oldpkg, PKG_SECTION, pkg_get_string(newpkg, PKG_SECTION));
337         if (!pkg_get_string(oldpkg, PKG_MAINTAINER))
338                 pkg_set_string(oldpkg, PKG_MAINTAINER, pkg_get_string(newpkg, PKG_MAINTAINER));
339         if (!pkg_get_string(oldpkg, PKG_DESCRIPTION))
340                 pkg_set_string(oldpkg, PKG_DESCRIPTION, pkg_get_string(newpkg, PKG_DESCRIPTION));
341
342         if (!oldpkg->depends_count && !oldpkg->pre_depends_count
343             && !oldpkg->recommends_count && !oldpkg->suggests_count) {
344                 oldpkg->depends_count = newpkg->depends_count;
345                 newpkg->depends_count = 0;
346
347                 oldpkg->depends = newpkg->depends;
348                 newpkg->depends = NULL;
349
350                 oldpkg->pre_depends_count = newpkg->pre_depends_count;
351                 newpkg->pre_depends_count = 0;
352
353                 oldpkg->recommends_count = newpkg->recommends_count;
354                 newpkg->recommends_count = 0;
355
356                 oldpkg->suggests_count = newpkg->suggests_count;
357                 newpkg->suggests_count = 0;
358         }
359
360         if (oldpkg->provides_count <= 1) {
361                 oldpkg->provides_count = newpkg->provides_count;
362                 newpkg->provides_count = 0;
363
364                 if (!oldpkg->provides) {
365                         oldpkg->provides = newpkg->provides;
366                         newpkg->provides = NULL;
367                 }
368         }
369
370         if (!oldpkg->conflicts_count) {
371                 oldpkg->conflicts_count = newpkg->conflicts_count;
372                 newpkg->conflicts_count = 0;
373
374                 oldpkg->conflicts = newpkg->conflicts;
375                 newpkg->conflicts = NULL;
376         }
377
378         if (!oldpkg->replaces_count) {
379                 oldpkg->replaces_count = newpkg->replaces_count;
380                 newpkg->replaces_count = 0;
381
382                 oldpkg->replaces = newpkg->replaces;
383                 newpkg->replaces = NULL;
384         }
385
386         if (!pkg_get_string(oldpkg, PKG_FILENAME))
387                 pkg_set_string(oldpkg, PKG_FILENAME, pkg_get_string(newpkg, PKG_FILENAME));
388         if (!pkg_get_string(oldpkg, PKG_LOCAL_FILENAME))
389                 pkg_set_string(oldpkg, PKG_LOCAL_FILENAME, pkg_get_string(newpkg, PKG_LOCAL_FILENAME));
390         if (!oldpkg->tmp_unpack_dir)
391                 oldpkg->tmp_unpack_dir = xstrdup(newpkg->tmp_unpack_dir);
392         if (!pkg_get_string(oldpkg, PKG_MD5SUM))
393                 pkg_set_string(oldpkg, PKG_MD5SUM, pkg_get_string(newpkg, PKG_MD5SUM));
394         if (!pkg_get_string(oldpkg, PKG_SHA256SUM))
395                 pkg_set_string(oldpkg, PKG_SHA256SUM, pkg_get_string(newpkg, PKG_SHA256SUM));
396         if (!oldpkg->size)
397                 oldpkg->size = newpkg->size;
398         if (!oldpkg->installed_size)
399                 oldpkg->installed_size = newpkg->installed_size;
400         if (!pkg_get_string(oldpkg, PKG_PRIORITY))
401                 pkg_set_string(oldpkg, PKG_PRIORITY, pkg_get_string(newpkg, PKG_PRIORITY));
402         if (!pkg_get_string(oldpkg, PKG_SOURCE))
403                 pkg_set_string(oldpkg, PKG_SOURCE, pkg_get_string(newpkg, PKG_SOURCE));
404
405         if (nv_pair_list_empty(&oldpkg->conffiles)) {
406                 list_splice_init(&newpkg->conffiles.head,
407                                  &oldpkg->conffiles.head);
408         }
409
410         if (!oldpkg->installed_files) {
411                 oldpkg->installed_files = newpkg->installed_files;
412                 oldpkg->installed_files_ref_cnt =
413                     newpkg->installed_files_ref_cnt;
414                 newpkg->installed_files = NULL;
415         }
416
417         if (!oldpkg->essential)
418                 oldpkg->essential = newpkg->essential;
419
420         return 0;
421 }
422
423 static void abstract_pkg_init(abstract_pkg_t * ab_pkg)
424 {
425         ab_pkg->provided_by = abstract_pkg_vec_alloc();
426         ab_pkg->dependencies_checked = 0;
427         ab_pkg->state_status = SS_NOT_INSTALLED;
428 }
429
430 abstract_pkg_t *abstract_pkg_new(void)
431 {
432         abstract_pkg_t *ab_pkg;
433
434         ab_pkg = xcalloc(1, sizeof(abstract_pkg_t));
435         abstract_pkg_init(ab_pkg);
436
437         return ab_pkg;
438 }
439
440 void set_flags_from_control(pkg_t * pkg)
441 {
442         char *file_name;
443         FILE *fp;
444
445         sprintf_alloc(&file_name, "%s/%s.control", pkg->dest->info_dir,
446                       pkg->name);
447
448         fp = fopen(file_name, "r");
449         if (fp == NULL) {
450                 opkg_perror(ERROR, "Failed to open %s", file_name);
451                 free(file_name);
452                 return;
453         }
454
455         free(file_name);
456
457         if (pkg_parse_from_stream(pkg, fp, PFM_ALL ^ PFM_ESSENTIAL)) {
458                 opkg_msg(DEBUG,
459                          "Unable to read control file for %s. May be empty.\n",
460                          pkg->name);
461         }
462
463         fclose(fp);
464
465         return;
466 }
467
468 static const char *pkg_state_want_to_str(pkg_state_want_t sw)
469 {
470         int i;
471
472         for (i = 0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
473                 if (pkg_state_want_map[i].value == sw) {
474                         return pkg_state_want_map[i].str;
475                 }
476         }
477
478         opkg_msg(ERROR, "Internal error: state_want=%d\n", sw);
479         return "<STATE_WANT_UNKNOWN>";
480 }
481
482 pkg_state_want_t pkg_state_want_from_str(char *str)
483 {
484         int i;
485
486         for (i = 0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
487                 if (strcmp(str, pkg_state_want_map[i].str) == 0) {
488                         return pkg_state_want_map[i].value;
489                 }
490         }
491
492         opkg_msg(ERROR, "Internal error: state_want=%s\n", str);
493         return SW_UNKNOWN;
494 }
495
496 static char *pkg_state_flag_to_str(pkg_state_flag_t sf)
497 {
498         int i;
499         unsigned int len;
500         char *str;
501
502         /* clear the temporary flags before converting to string */
503         sf &= SF_NONVOLATILE_FLAGS;
504
505         if (sf == 0)
506                 return xstrdup("ok");
507
508         len = 0;
509         for (i = 0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
510                 if (sf & pkg_state_flag_map[i].value)
511                         len += strlen(pkg_state_flag_map[i].str) + 1;
512         }
513
514         str = xmalloc(len + 1);
515         str[0] = '\0';
516
517         for (i = 0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
518                 if (sf & pkg_state_flag_map[i].value) {
519                         strncat(str, pkg_state_flag_map[i].str, len);
520                         strncat(str, ",", len);
521                 }
522         }
523
524         len = strlen(str);
525         str[len - 1] = '\0';    /* squash last comma */
526
527         return str;
528 }
529
530 pkg_state_flag_t pkg_state_flag_from_str(const char *str)
531 {
532         int i;
533         int sf = SF_OK;
534         const char *sfname;
535         unsigned int sfname_len;
536
537         if (strcmp(str, "ok") == 0) {
538                 return SF_OK;
539         }
540         for (i = 0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
541                 sfname = pkg_state_flag_map[i].str;
542                 sfname_len = strlen(sfname);
543                 if (strncmp(str, sfname, sfname_len) == 0) {
544                         sf |= pkg_state_flag_map[i].value;
545                         str += sfname_len;
546                         if (str[0] == ',') {
547                                 str++;
548                         } else {
549                                 break;
550                         }
551                 }
552         }
553
554         return sf;
555 }
556
557 static const char *pkg_state_status_to_str(pkg_state_status_t ss)
558 {
559         int i;
560
561         for (i = 0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
562                 if (pkg_state_status_map[i].value == ss) {
563                         return pkg_state_status_map[i].str;
564                 }
565         }
566
567         opkg_msg(ERROR, "Internal error: state_status=%d\n", ss);
568         return "<STATE_STATUS_UNKNOWN>";
569 }
570
571 pkg_state_status_t pkg_state_status_from_str(const char *str)
572 {
573         int i;
574
575         for (i = 0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
576                 if (strcmp(str, pkg_state_status_map[i].str) == 0) {
577                         return pkg_state_status_map[i].value;
578                 }
579         }
580
581         opkg_msg(ERROR, "Internal error: state_status=%s\n", str);
582         return SS_NOT_INSTALLED;
583 }
584
585 void pkg_formatted_field(FILE * fp, pkg_t * pkg, const char *field)
586 {
587         int i, j;
588         char *str;
589         const char *p;
590         int depends_count = pkg->pre_depends_count +
591             pkg->depends_count + pkg->recommends_count + pkg->suggests_count;
592
593         if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
594                 goto UNKNOWN_FMT_FIELD;
595         }
596
597         switch (field[0]) {
598         case 'a':
599         case 'A':
600                 if (strcasecmp(field, "Architecture") == 0) {
601                         p = pkg_get_string(pkg, PKG_ARCHITECTURE);
602                         if (p) {
603                                 fprintf(fp, "Architecture: %s\n",
604                                         p);
605                         }
606                 } else if (strcasecmp(field, "Auto-Installed") == 0) {
607                         if (pkg->auto_installed)
608                                 fprintf(fp, "Auto-Installed: yes\n");
609                 } else {
610                         goto UNKNOWN_FMT_FIELD;
611                 }
612                 break;
613         case 'c':
614         case 'C':
615                 if (strcasecmp(field, "Conffiles") == 0) {
616                         conffile_list_elt_t *iter;
617
618                         if (nv_pair_list_empty(&pkg->conffiles))
619                                 return;
620
621                         fprintf(fp, "Conffiles:\n");
622                         for (iter = nv_pair_list_first(&pkg->conffiles); iter;
623                              iter = nv_pair_list_next(&pkg->conffiles, iter)) {
624                                 if (((conffile_t *) iter->data)->name
625                                     && ((conffile_t *) iter->data)->value) {
626                                         fprintf(fp, " %s %s\n",
627                                                 ((conffile_t *) iter->data)->
628                                                 name,
629                                                 ((conffile_t *) iter->data)->
630                                                 value);
631                                 }
632                         }
633                 } else if (strcasecmp(field, "Conflicts") == 0) {
634                         struct depend *cdep;
635                         if (pkg->conflicts_count) {
636                                 fprintf(fp, "Conflicts:");
637                                 for (i = 0; i < pkg->conflicts_count; i++) {
638                                         cdep =
639                                             pkg->conflicts[i].possibilities[0];
640                                         fprintf(fp, "%s %s", i == 0 ? "" : ",",
641                                                 cdep->pkg->name);
642                                         if (cdep->version) {
643                                                 fprintf(fp, " (%s%s)",
644                                                         constraint_to_str(cdep->
645                                                                           constraint),
646                                                         cdep->version);
647                                         }
648                                 }
649                                 fprintf(fp, "\n");
650                         }
651                 } else {
652                         goto UNKNOWN_FMT_FIELD;
653                 }
654                 break;
655         case 'd':
656         case 'D':
657                 if (strcasecmp(field, "Depends") == 0) {
658                         if (pkg->depends_count) {
659                                 fprintf(fp, "Depends:");
660                                 for (j = 0, i = 0; i < depends_count; i++) {
661                                         if (pkg->depends[i].type != DEPEND)
662                                                 continue;
663                                         str = pkg_depend_str(pkg, i);
664                                         fprintf(fp, "%s %s", j == 0 ? "" : ",",
665                                                 str);
666                                         free(str);
667                                         j++;
668                                 }
669                                 fprintf(fp, "\n");
670                         }
671                 } else if (strcasecmp(field, "Description") == 0) {
672                         p = pkg_get_string(pkg, PKG_DESCRIPTION);
673                         if (p) {
674                                 fprintf(fp, "Description: %s\n",
675                                         p);
676                         }
677                 } else {
678                         goto UNKNOWN_FMT_FIELD;
679                 }
680                 break;
681         case 'e':
682         case 'E':
683                 if (pkg->essential) {
684                         fprintf(fp, "Essential: yes\n");
685                 }
686                 break;
687         case 'f':
688         case 'F':
689                 p = pkg_get_string(pkg, PKG_FILENAME);
690                 if (p) {
691                         fprintf(fp, "Filename: %s\n", p);
692                 }
693                 break;
694         case 'i':
695         case 'I':
696                 if (strcasecmp(field, "Installed-Size") == 0) {
697                         fprintf(fp, "Installed-Size: %ld\n",
698                                 pkg->installed_size);
699                 } else if (strcasecmp(field, "Installed-Time") == 0
700                            && pkg->installed_time) {
701                         fprintf(fp, "Installed-Time: %lu\n",
702                                 pkg->installed_time);
703                 }
704                 break;
705         case 'm':
706         case 'M':
707                 if (strcasecmp(field, "Maintainer") == 0) {
708                         p = pkg_get_string(pkg, PKG_MAINTAINER);
709                         if (p) {
710                                 fprintf(fp, "Maintainer: %s\n", p);
711                         }
712                 } else if (strcasecmp(field, "MD5sum") == 0) {
713                         p = pkg_get_string(pkg, PKG_MD5SUM);
714                         if (p) {
715                                 fprintf(fp, "MD5Sum: %s\n", p);
716                         }
717                 } else {
718                         goto UNKNOWN_FMT_FIELD;
719                 }
720                 break;
721         case 'p':
722         case 'P':
723                 if (strcasecmp(field, "Package") == 0) {
724                         fprintf(fp, "Package: %s\n", pkg->name);
725                 } else if (strcasecmp(field, "Priority") == 0) {
726                         fprintf(fp, "Priority: %s\n", pkg_get_string(pkg, PKG_PRIORITY));
727                 } else if (strcasecmp(field, "Provides") == 0) {
728                         if (pkg->provides_count > 1) {
729                                 fprintf(fp, "Provides:");
730                                 for (i = 1; i < pkg->provides_count; i++) {
731                                         fprintf(fp, "%s %s", i == 1 ? "" : ",",
732                                                 pkg->provides[i]->name);
733                                 }
734                                 fprintf(fp, "\n");
735                         }
736                 } else {
737                         goto UNKNOWN_FMT_FIELD;
738                 }
739                 break;
740         case 'r':
741         case 'R':
742                 if (strcasecmp(field, "Replaces") == 0) {
743                         if (pkg->replaces_count) {
744                                 fprintf(fp, "Replaces:");
745                                 for (i = 0; i < pkg->replaces_count; i++) {
746                                         fprintf(fp, "%s %s", i == 0 ? "" : ",",
747                                                 pkg->replaces[i]->name);
748                                 }
749                                 fprintf(fp, "\n");
750                         }
751                 } else if (strcasecmp(field, "Recommends") == 0) {
752                         if (pkg->recommends_count) {
753                                 fprintf(fp, "Recommends:");
754                                 for (j = 0, i = 0; i < depends_count; i++) {
755                                         if (pkg->depends[i].type != RECOMMEND)
756                                                 continue;
757                                         str = pkg_depend_str(pkg, i);
758                                         fprintf(fp, "%s %s", j == 0 ? "" : ",",
759                                                 str);
760                                         free(str);
761                                         j++;
762                                 }
763                                 fprintf(fp, "\n");
764                         }
765                 } else {
766                         goto UNKNOWN_FMT_FIELD;
767                 }
768                 break;
769         case 's':
770         case 'S':
771                 if (strcasecmp(field, "Section") == 0) {
772                         p = pkg_get_string(pkg, PKG_SECTION);
773                         if (p) {
774                                 fprintf(fp, "Section: %s\n", p);
775                         }
776 #if defined HAVE_SHA256
777                 } else if (strcasecmp(field, "SHA256sum") == 0) {
778                         p = pkg_get_string(pkg, PKG_SHA256SUM);
779                         if (p) {
780                                 fprintf(fp, "SHA256sum: %s\n", p);
781                         }
782 #endif
783                 } else if (strcasecmp(field, "Size") == 0) {
784                         if (pkg->size) {
785                                 fprintf(fp, "Size: %ld\n", pkg->size);
786                         }
787                 } else if (strcasecmp(field, "Source") == 0) {
788                         p = pkg_get_string(pkg, PKG_SOURCE);
789                         if (p) {
790                                 fprintf(fp, "Source: %s\n", p);
791                         }
792                 } else if (strcasecmp(field, "Status") == 0) {
793                         char *pflag = pkg_state_flag_to_str(pkg->state_flag);
794                         fprintf(fp, "Status: %s %s %s\n",
795                                 pkg_state_want_to_str(pkg->state_want),
796                                 pflag,
797                                 pkg_state_status_to_str(pkg->state_status));
798                         free(pflag);
799                 } else if (strcasecmp(field, "Suggests") == 0) {
800                         if (pkg->suggests_count) {
801                                 fprintf(fp, "Suggests:");
802                                 for (j = 0, i = 0; i < depends_count; i++) {
803                                         if (pkg->depends[i].type != SUGGEST)
804                                                 continue;
805                                         str = pkg_depend_str(pkg, i);
806                                         fprintf(fp, "%s %s", j == 0 ? "" : ",",
807                                                 str);
808                                         free(str);
809                                         j++;
810                                 }
811                                 fprintf(fp, "\n");
812                         }
813                 } else {
814                         goto UNKNOWN_FMT_FIELD;
815                 }
816                 break;
817         case 't':
818         case 'T':
819                 if (strcasecmp(field, "Tags") == 0) {
820                         p = pkg_get_string(pkg, PKG_TAGS);
821                         if (p) {
822                                 fprintf(fp, "Tags: %s\n", p);
823                         }
824                 }
825                 break;
826         case 'v':
827         case 'V':
828                 {
829                         char *version = pkg_version_str_alloc(pkg);
830                         if (version == NULL)
831                                 return;
832                         fprintf(fp, "Version: %s\n", version);
833                         free(version);
834                 }
835                 break;
836         default:
837                 goto UNKNOWN_FMT_FIELD;
838         }
839
840         return;
841
842 UNKNOWN_FMT_FIELD:
843         opkg_msg(ERROR, "Internal error: field=%s\n", field);
844 }
845
846 void pkg_formatted_info(FILE * fp, pkg_t * pkg)
847 {
848         pkg_formatted_field(fp, pkg, "Package");
849         pkg_formatted_field(fp, pkg, "Version");
850         pkg_formatted_field(fp, pkg, "Depends");
851         pkg_formatted_field(fp, pkg, "Recommends");
852         pkg_formatted_field(fp, pkg, "Suggests");
853         pkg_formatted_field(fp, pkg, "Provides");
854         pkg_formatted_field(fp, pkg, "Replaces");
855         pkg_formatted_field(fp, pkg, "Conflicts");
856         pkg_formatted_field(fp, pkg, "Status");
857         pkg_formatted_field(fp, pkg, "Section");
858         pkg_formatted_field(fp, pkg, "Essential");
859         pkg_formatted_field(fp, pkg, "Architecture");
860         pkg_formatted_field(fp, pkg, "Maintainer");
861         pkg_formatted_field(fp, pkg, "MD5sum");
862         pkg_formatted_field(fp, pkg, "Size");
863         pkg_formatted_field(fp, pkg, "Filename");
864         pkg_formatted_field(fp, pkg, "Conffiles");
865         pkg_formatted_field(fp, pkg, "Source");
866         pkg_formatted_field(fp, pkg, "Description");
867         pkg_formatted_field(fp, pkg, "Installed-Time");
868         pkg_formatted_field(fp, pkg, "Tags");
869         fputs("\n", fp);
870 }
871
872 void pkg_print_status(pkg_t * pkg, FILE * file)
873 {
874         if (pkg == NULL) {
875                 return;
876         }
877
878         pkg_formatted_field(file, pkg, "Package");
879         pkg_formatted_field(file, pkg, "Version");
880         pkg_formatted_field(file, pkg, "Depends");
881         pkg_formatted_field(file, pkg, "Recommends");
882         pkg_formatted_field(file, pkg, "Suggests");
883         pkg_formatted_field(file, pkg, "Provides");
884         pkg_formatted_field(file, pkg, "Replaces");
885         pkg_formatted_field(file, pkg, "Conflicts");
886         pkg_formatted_field(file, pkg, "Status");
887         pkg_formatted_field(file, pkg, "Essential");
888         pkg_formatted_field(file, pkg, "Architecture");
889         pkg_formatted_field(file, pkg, "Conffiles");
890         pkg_formatted_field(file, pkg, "Installed-Time");
891         pkg_formatted_field(file, pkg, "Auto-Installed");
892         fputs("\n", file);
893 }
894
895 /*
896  * libdpkg - Debian packaging suite library routines
897  * vercmp.c - comparison of version numbers
898  *
899  * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
900  */
901
902 /* assume ascii; warning: evaluates x multiple times! */
903 #define order(x) ((x) == '~' ? -1 \
904                 : isdigit((x)) ? 0 \
905                 : !(x) ? 0 \
906                 : isalpha((x)) ? (x) \
907                 : (x) + 256)
908
909 static int verrevcmp(const char *val, const char *ref)
910 {
911         if (!val)
912                 val = "";
913         if (!ref)
914                 ref = "";
915
916         while (*val || *ref) {
917                 int first_diff = 0;
918
919                 while ((*val && !isdigit(*val)) || (*ref && !isdigit(*ref))) {
920                         int vc = order(*val), rc = order(*ref);
921                         if (vc != rc)
922                                 return vc - rc;
923                         val++;
924                         ref++;
925                 }
926
927                 while (*val == '0')
928                         val++;
929                 while (*ref == '0')
930                         ref++;
931                 while (isdigit(*val) && isdigit(*ref)) {
932                         if (!first_diff)
933                                 first_diff = *val - *ref;
934                         val++;
935                         ref++;
936                 }
937                 if (isdigit(*val))
938                         return 1;
939                 if (isdigit(*ref))
940                         return -1;
941                 if (first_diff)
942                         return first_diff;
943         }
944         return 0;
945 }
946
947 int pkg_compare_versions(const pkg_t * pkg, const pkg_t * ref_pkg)
948 {
949         unsigned int epoch1 = (unsigned int) pkg_get_int(pkg, PKG_EPOCH);
950         unsigned int epoch2 = (unsigned int) pkg_get_int(ref_pkg, PKG_EPOCH);
951         char *revision1 = pkg_get_ptr(pkg, PKG_REVISION);
952         char *revision2 = pkg_get_ptr(ref_pkg, PKG_REVISION);
953         const char *version1 = pkg_get_string(pkg, PKG_VERSION);
954         const char *version2 = pkg_get_string(ref_pkg, PKG_VERSION);
955         int r;
956
957         if (epoch1 > epoch2) {
958                 return 1;
959         }
960
961         if (epoch1 < epoch2) {
962                 return -1;
963         }
964
965         r = verrevcmp(version1, version2);
966         if (r) {
967                 return r;
968         }
969
970         r = verrevcmp(revision1, revision2);
971         if (r) {
972                 return r;
973         }
974
975         return r;
976 }
977
978 int pkg_version_satisfied(pkg_t * it, pkg_t * ref, const char *op)
979 {
980         int r;
981
982         r = pkg_compare_versions(it, ref);
983
984         if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) {
985                 return r <= 0;
986         }
987
988         if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) {
989                 return r >= 0;
990         }
991
992         if (strcmp(op, "<<") == 0) {
993                 return r < 0;
994         }
995
996         if (strcmp(op, ">>") == 0) {
997                 return r > 0;
998         }
999
1000         if (strcmp(op, "=") == 0) {
1001                 return r == 0;
1002         }
1003
1004         opkg_msg(ERROR, "Unknown operator: %s.\n", op);
1005         return 0;
1006 }
1007
1008 int pkg_name_version_and_architecture_compare(const void *p1, const void *p2)
1009 {
1010         const pkg_t * a = *(const pkg_t **)p1;
1011         const pkg_t * b = *(const pkg_t **)p2;
1012         int namecmp;
1013         int vercmp;
1014         if (!a->name || !b->name) {
1015                 opkg_msg(ERROR, "Internal error: a->name=%p, b->name=%p.\n",
1016                          a->name, b->name);
1017                 return 0;
1018         }
1019
1020         namecmp = strcmp(a->name, b->name);
1021         if (namecmp)
1022                 return namecmp;
1023         vercmp = pkg_compare_versions(a, b);
1024         if (vercmp)
1025                 return vercmp;
1026         if (!a->arch_priority || !b->arch_priority) {
1027                 opkg_msg(ERROR,
1028                          "Internal error: a->arch_priority=%i b->arch_priority=%i.\n",
1029                          a->arch_priority, b->arch_priority);
1030                 return 0;
1031         }
1032         if (a->arch_priority > b->arch_priority)
1033                 return 1;
1034         if (a->arch_priority < b->arch_priority)
1035                 return -1;
1036         return 0;
1037 }
1038
1039 int abstract_pkg_name_compare(const void *p1, const void *p2)
1040 {
1041         const abstract_pkg_t *a = *(const abstract_pkg_t **)p1;
1042         const abstract_pkg_t *b = *(const abstract_pkg_t **)p2;
1043         if (!a->name || !b->name) {
1044                 opkg_msg(ERROR, "Internal error: a->name=%p b->name=%p.\n",
1045                          a->name, b->name);
1046                 return 0;
1047         }
1048         return strcmp(a->name, b->name);
1049 }
1050
1051 char *pkg_version_str_alloc(pkg_t * pkg)
1052 {
1053         const char *verstr;
1054         char *version, *revptr;
1055         unsigned int epoch = (unsigned int) pkg_get_int(pkg, PKG_EPOCH);
1056
1057         revptr = pkg_get_ptr(pkg, PKG_REVISION);
1058         verstr = pkg_get_string(pkg, PKG_VERSION);
1059
1060         if (epoch) {
1061                 if (revptr)
1062                         sprintf_alloc(&version, "%d:%s-%s",
1063                                       epoch, verstr, revptr);
1064                 else
1065                         sprintf_alloc(&version, "%d:%s",
1066                                       epoch, verstr);
1067         } else {
1068                 if (revptr)
1069                         sprintf_alloc(&version, "%s-%s",
1070                                       verstr, revptr);
1071                 else
1072                         version = xstrdup(verstr);
1073         }
1074
1075         return version;
1076 }
1077
1078 /*
1079  * XXX: this should be broken into two functions
1080  */
1081 str_list_t *pkg_get_installed_files(pkg_t * pkg)
1082 {
1083         int err, fd;
1084         char *list_file_name = NULL;
1085         FILE *list_file = NULL;
1086         char *line;
1087         char *installed_file_name;
1088         unsigned int rootdirlen = 0;
1089         int list_from_package;
1090         const char *local_filename;
1091
1092         pkg->installed_files_ref_cnt++;
1093
1094         if (pkg->installed_files) {
1095                 return pkg->installed_files;
1096         }
1097
1098         pkg->installed_files = str_list_alloc();
1099
1100         /*
1101          * For installed packages, look at the package.list file in the database.
1102          * For uninstalled packages, get the file list directly from the package.
1103          */
1104         if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL)
1105                 list_from_package = 1;
1106         else
1107                 list_from_package = 0;
1108
1109         if (list_from_package) {
1110                 local_filename = pkg_get_string(pkg, PKG_LOCAL_FILENAME);
1111
1112                 if (!local_filename) {
1113                         return pkg->installed_files;
1114                 }
1115                 /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary
1116                    file. In other words, change deb_extract so that it can
1117                    simply return the file list as a char *[] rather than
1118                    insisting on writing it to a FILE * as it does now. */
1119                 sprintf_alloc(&list_file_name, "%s/%s.list.XXXXXX",
1120                               conf->tmp_dir, pkg->name);
1121                 fd = mkstemp(list_file_name);
1122                 if (fd == -1) {
1123                         opkg_perror(ERROR, "Failed to make temp file %s.",
1124                                     list_file_name);
1125                         free(list_file_name);
1126                         return pkg->installed_files;
1127                 }
1128                 list_file = fdopen(fd, "r+");
1129                 if (list_file == NULL) {
1130                         opkg_perror(ERROR, "Failed to fdopen temp file %s.",
1131                                     list_file_name);
1132                         close(fd);
1133                         unlink(list_file_name);
1134                         free(list_file_name);
1135                         return pkg->installed_files;
1136                 }
1137                 err = pkg_extract_data_file_names_to_stream(pkg, list_file);
1138                 if (err) {
1139                         opkg_msg(ERROR, "Error extracting file list from %s.\n",
1140                                  local_filename);
1141                         fclose(list_file);
1142                         unlink(list_file_name);
1143                         free(list_file_name);
1144                         str_list_deinit(pkg->installed_files);
1145                         pkg->installed_files = NULL;
1146                         return NULL;
1147                 }
1148                 rewind(list_file);
1149         } else {
1150                 sprintf_alloc(&list_file_name, "%s/%s.list",
1151                               pkg->dest->info_dir, pkg->name);
1152                 list_file = fopen(list_file_name, "r");
1153                 if (list_file == NULL) {
1154                         opkg_perror(ERROR, "Failed to open %s", list_file_name);
1155                         free(list_file_name);
1156                         return pkg->installed_files;
1157                 }
1158                 free(list_file_name);
1159         }
1160
1161         if (conf->offline_root)
1162                 rootdirlen = strlen(conf->offline_root);
1163
1164         while (1) {
1165                 char *file_name;
1166
1167                 line = file_read_line_alloc(list_file);
1168                 if (line == NULL) {
1169                         break;
1170                 }
1171                 file_name = line;
1172
1173                 if (list_from_package) {
1174                         if (*file_name == '.') {
1175                                 file_name++;
1176                         }
1177                         if (*file_name == '/') {
1178                                 file_name++;
1179                         }
1180                         sprintf_alloc(&installed_file_name, "%s%s",
1181                                       pkg->dest->root_dir, file_name);
1182                 } else {
1183                         if (conf->offline_root &&
1184                             strncmp(conf->offline_root, file_name,
1185                                     rootdirlen)) {
1186                                 sprintf_alloc(&installed_file_name, "%s%s",
1187                                               conf->offline_root, file_name);
1188                         } else {
1189                                 // already contains root_dir as header -> ABSOLUTE
1190                                 sprintf_alloc(&installed_file_name, "%s",
1191                                               file_name);
1192                         }
1193                 }
1194                 str_list_append(pkg->installed_files, installed_file_name);
1195                 free(installed_file_name);
1196                 free(line);
1197         }
1198
1199         fclose(list_file);
1200
1201         if (list_from_package) {
1202                 unlink(list_file_name);
1203                 free(list_file_name);
1204         }
1205
1206         return pkg->installed_files;
1207 }
1208
1209 /* XXX: CLEANUP: This function and it's counterpart,
1210    (pkg_get_installed_files), do not match our init/deinit naming
1211    convention. Nor the alloc/free convention. But, then again, neither
1212    of these conventions currrently fit the way these two functions
1213    work. */
1214 void pkg_free_installed_files(pkg_t * pkg)
1215 {
1216         pkg->installed_files_ref_cnt--;
1217
1218         if (pkg->installed_files_ref_cnt > 0)
1219                 return;
1220
1221         if (pkg->installed_files) {
1222                 str_list_purge(pkg->installed_files);
1223         }
1224
1225         pkg->installed_files = NULL;
1226 }
1227
1228 void pkg_remove_installed_files_list(pkg_t * pkg)
1229 {
1230         char *list_file_name;
1231
1232         sprintf_alloc(&list_file_name, "%s/%s.list",
1233                       pkg->dest->info_dir, pkg->name);
1234
1235         if (!conf->noaction)
1236                 (void)unlink(list_file_name);
1237
1238         free(list_file_name);
1239 }
1240
1241 conffile_t *pkg_get_conffile(pkg_t * pkg, const char *file_name)
1242 {
1243         conffile_list_elt_t *iter;
1244         conffile_t *conffile;
1245
1246         if (pkg == NULL) {
1247                 return NULL;
1248         }
1249
1250         for (iter = nv_pair_list_first(&pkg->conffiles); iter;
1251              iter = nv_pair_list_next(&pkg->conffiles, iter)) {
1252                 conffile = (conffile_t *) iter->data;
1253
1254                 if (strcmp(conffile->name, file_name) == 0) {
1255                         return conffile;
1256                 }
1257         }
1258
1259         return NULL;
1260 }
1261
1262 int pkg_run_script(pkg_t * pkg, const char *script, const char *args)
1263 {
1264         int err;
1265         char *path;
1266         char *cmd;
1267
1268         if (conf->noaction)
1269                 return 0;
1270
1271         /* XXX: FEATURE: When conf->offline_root is set, we should run the
1272            maintainer script within a chroot environment. */
1273         if (conf->offline_root && !conf->force_postinstall) {
1274                 opkg_msg(INFO, "Offline root mode: not running %s.%s.\n",
1275                          pkg->name, script);
1276                 return 0;
1277         }
1278
1279         /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages
1280            have scripts in pkg->tmp_unpack_dir. */
1281         if (pkg->state_status == SS_INSTALLED
1282             || pkg->state_status == SS_UNPACKED) {
1283                 if (pkg->dest == NULL) {
1284                         opkg_msg(ERROR, "Internal error: %s has a NULL dest.\n",
1285                                  pkg->name);
1286                         return -1;
1287                 }
1288                 sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name,
1289                               script);
1290         } else {
1291                 if (pkg->tmp_unpack_dir == NULL) {
1292                         opkg_msg(ERROR,
1293                                  "Internal error: %s has a NULL tmp_unpack_dir.\n",
1294                                  pkg->name);
1295                         return -1;
1296                 }
1297                 sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script);
1298         }
1299
1300         opkg_msg(INFO, "Running script %s.\n", path);
1301
1302         setenv("PKG_ROOT",
1303                pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir,
1304                1);
1305
1306         if (pkg->is_upgrade)
1307                 setenv("PKG_UPGRADE", "1", 1);
1308         else
1309                 setenv("PKG_UPGRADE", "0", 1);
1310
1311         if (!file_exists(path)) {
1312                 free(path);
1313                 return 0;
1314         }
1315
1316         sprintf_alloc(&cmd, "%s %s", path, args);
1317         free(path);
1318         {
1319                 const char *argv[] = { "sh", "-c", cmd, NULL };
1320                 err = xsystem(argv);
1321         }
1322         free(cmd);
1323
1324         if (err) {
1325                 opkg_msg(ERROR,
1326                          "package \"%s\" %s script returned status %d.\n",
1327                          pkg->name, script, err);
1328                 return err;
1329         }
1330
1331         return 0;
1332 }
1333
1334 int pkg_arch_supported(pkg_t * pkg)
1335 {
1336         nv_pair_list_elt_t *l;
1337         char *architecture = pkg_get_string(pkg, PKG_ARCHITECTURE);
1338
1339         if (!architecture)
1340                 return 1;
1341
1342         list_for_each_entry(l, &conf->arch_list.head, node) {
1343                 nv_pair_t *nv = (nv_pair_t *) l->data;
1344                 if (strcmp(nv->name, architecture) == 0) {
1345                         opkg_msg(DEBUG,
1346                                  "Arch %s (priority %s) supported for pkg %s.\n",
1347                                  nv->name, nv->value, pkg->name);
1348                         return 1;
1349                 }
1350         }
1351
1352         opkg_msg(DEBUG, "Arch %s unsupported for pkg %s.\n",
1353                  architecture, pkg->name);
1354         return 0;
1355 }
1356
1357 void pkg_info_preinstall_check(void)
1358 {
1359         int i;
1360         pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1361
1362         /* update the file owner data structure */
1363         opkg_msg(INFO, "Updating file owner list.\n");
1364         pkg_hash_fetch_all_installed(installed_pkgs);
1365         for (i = 0; i < installed_pkgs->len; i++) {
1366                 pkg_t *pkg = installed_pkgs->pkgs[i];
1367                 str_list_t *installed_files = pkg_get_installed_files(pkg);     /* this causes installed_files to be cached */
1368                 str_list_elt_t *iter, *niter;
1369                 if (installed_files == NULL) {
1370                         opkg_msg(ERROR, "Failed to determine installed "
1371                                  "files for pkg %s.\n", pkg->name);
1372                         break;
1373                 }
1374                 for (iter = str_list_first(installed_files), niter =
1375                      str_list_next(installed_files, iter); iter;
1376                      iter = niter, niter =
1377                      str_list_next(installed_files, iter)) {
1378                         char *installed_file = (char *)iter->data;
1379                         file_hash_set_file_owner(installed_file, pkg);
1380                 }
1381                 pkg_free_installed_files(pkg);
1382         }
1383         pkg_vec_free(installed_pkgs);
1384 }
1385
1386 struct pkg_write_filelist_data {
1387         pkg_t *pkg;
1388         FILE *stream;
1389 };
1390
1391 static void
1392 pkg_write_filelist_helper(const char *key, void *entry_, void *data_)
1393 {
1394         struct pkg_write_filelist_data *data = data_;
1395         pkg_t *entry = entry_;
1396         if (entry == data->pkg) {
1397                 fprintf(data->stream, "%s\n", key);
1398         }
1399 }
1400
1401 int pkg_write_filelist(pkg_t * pkg)
1402 {
1403         struct pkg_write_filelist_data data;
1404         char *list_file_name;
1405
1406         sprintf_alloc(&list_file_name, "%s/%s.list",
1407                       pkg->dest->info_dir, pkg->name);
1408
1409         opkg_msg(INFO, "Creating %s file for pkg %s.\n",
1410                  list_file_name, pkg->name);
1411
1412         data.stream = fopen(list_file_name, "w");
1413         if (!data.stream) {
1414                 opkg_perror(ERROR, "Failed to open %s", list_file_name);
1415                 free(list_file_name);
1416                 return -1;
1417         }
1418
1419         data.pkg = pkg;
1420         hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data);
1421         fclose(data.stream);
1422         free(list_file_name);
1423
1424         pkg->state_flag &= ~SF_FILELIST_CHANGED;
1425
1426         return 0;
1427 }
1428
1429 int pkg_write_changed_filelists(void)
1430 {
1431         pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1432         int i, err, ret = 0;
1433
1434         if (conf->noaction)
1435                 return 0;
1436
1437         opkg_msg(INFO, "Saving changed filelists.\n");
1438
1439         pkg_hash_fetch_all_installed(installed_pkgs);
1440         for (i = 0; i < installed_pkgs->len; i++) {
1441                 pkg_t *pkg = installed_pkgs->pkgs[i];
1442                 if (pkg->state_flag & SF_FILELIST_CHANGED) {
1443                         err = pkg_write_filelist(pkg);
1444                         if (err)
1445                                 ret = -1;
1446                 }
1447         }
1448
1449         pkg_vec_free(installed_pkgs);
1450
1451         return ret;
1452 }