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