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