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