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