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