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