33d0d68f7428d2f482f2740326ec7041c8352be3
[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      if (conf->noaction)
1146              return 0;
1147
1148      /* XXX: CLEANUP: There must be a better way to handle maintainer
1149         scripts when running with offline_root mode and/or a dest other
1150         than '/'. I've been playing around with some clever chroot
1151         tricks and I might come up with something workable. */
1152      /*
1153       * Attempt to provide a restricted environment for offline operation
1154       * Need the following set as a minimum:
1155       * OPKG_OFFLINE_ROOT = absolute path to root dir
1156       * D                 = absolute path to root dir (for OE generated postinst)
1157       * PATH              = something safe (a restricted set of utilities)
1158       */
1159
1160      if (conf->offline_root) {
1161           if (conf->offline_root_path) {
1162             setenv("PATH", conf->offline_root_path, 1);
1163           } else {
1164             opkg_message(conf, OPKG_NOTICE, 
1165                 "(offline root mode: not running %s.%s)\n", pkg->name, script);
1166             return 0;
1167           }
1168           setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
1169           setenv("D", conf->offline_root, 1);
1170      }
1171
1172      /* XXX: FEATURE: When conf->offline_root is set, we should run the
1173         maintainer script within a chroot environment. */
1174
1175      /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages
1176         have scripts in pkg->tmp_unpack_dir. */
1177      if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) {
1178           if (pkg->dest == NULL) {
1179                fprintf(stderr, "%s: ERROR: installed package %s has a NULL dest\n",
1180                        __FUNCTION__, pkg->name);
1181                return EINVAL;
1182           }
1183           sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script);
1184      } else {
1185           if (pkg->tmp_unpack_dir == NULL) {
1186                fprintf(stderr, "%s: ERROR: uninstalled package %s has a NULL tmp_unpack_dir\n",
1187                        __FUNCTION__, pkg->name);
1188                return EINVAL;
1189           }
1190           sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script);
1191      }
1192
1193      opkg_message(conf, OPKG_INFO, "Running script %s\n", path);
1194
1195      setenv("PKG_ROOT",
1196             pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
1197
1198      if (! file_exists(path)) {
1199           free(path);
1200           return 0;
1201      }
1202
1203      sprintf_alloc(&cmd, "%s %s", path, args);
1204      free(path);
1205
1206      err = xsystem(cmd);
1207      free(cmd);
1208
1209      if (err) {
1210           fprintf(stderr, "%s script returned status %d\n", script, err);
1211           return err;
1212      }
1213
1214      return 0;
1215 }
1216
1217 char *pkg_state_want_to_str(pkg_state_want_t sw)
1218 {
1219      int i;
1220
1221      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
1222           if (pkg_state_want_map[i].value == sw) {
1223                return xstrdup(pkg_state_want_map[i].str);
1224           }
1225      }
1226
1227      fprintf(stderr, "%s: ERROR: Illegal value for state_want: %d\n",
1228              __FUNCTION__, sw);
1229      return xstrdup("<STATE_WANT_UNKNOWN>");
1230 }
1231
1232 pkg_state_want_t pkg_state_want_from_str(char *str)
1233 {
1234      int i;
1235
1236      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
1237           if (strcmp(str, pkg_state_want_map[i].str) == 0) {
1238                return pkg_state_want_map[i].value;
1239           }
1240      }
1241
1242      fprintf(stderr, "%s: ERROR: Illegal value for state_want string: %s\n",
1243              __FUNCTION__, str);
1244      return SW_UNKNOWN;
1245 }
1246
1247 char *pkg_state_flag_to_str(pkg_state_flag_t sf)
1248 {
1249      int i;
1250      int len = 3; /* ok\000 is minimum */
1251      char *str = NULL;
1252
1253      /* clear the temporary flags before converting to string */
1254      sf &= SF_NONVOLATILE_FLAGS;
1255
1256      if (sf == 0) {
1257           return xstrdup("ok");
1258      } else {
1259
1260           for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1261                if (sf & pkg_state_flag_map[i].value) {
1262                     len += strlen(pkg_state_flag_map[i].str) + 1;
1263                }
1264           }
1265           str = malloc(len);
1266           if ( str == NULL ) {
1267               fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
1268               return NULL;
1269           }
1270           str[0] = 0;
1271           for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1272                if (sf & pkg_state_flag_map[i].value) {
1273                     strcat(str, pkg_state_flag_map[i].str);
1274                     strcat(str, ",");
1275                }
1276           }
1277           len = strlen(str);
1278           str[len-1] = 0; /* squash last comma */
1279           return str;
1280      }
1281 }
1282
1283 pkg_state_flag_t pkg_state_flag_from_str(const char *str)
1284 {
1285      int i;
1286      int sf = SF_OK;
1287
1288      if (strcmp(str, "ok") == 0) {
1289           return SF_OK;
1290      }
1291      for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1292           const char *sfname = pkg_state_flag_map[i].str;
1293           int sfname_len = strlen(sfname);
1294           if (strncmp(str, sfname, sfname_len) == 0) {
1295                sf |= pkg_state_flag_map[i].value;
1296                str += sfname_len;
1297                if (str[0] == ',') {
1298                     str++;
1299                } else {
1300                     break;
1301                }
1302           }
1303      }
1304
1305      return sf;
1306 }
1307
1308 char *pkg_state_status_to_str(pkg_state_status_t ss)
1309 {
1310      int i;
1311
1312      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
1313           if (pkg_state_status_map[i].value == ss) {
1314                return xstrdup(pkg_state_status_map[i].str);
1315           }
1316      }
1317
1318      fprintf(stderr, "%s: ERROR: Illegal value for state_status: %d\n",
1319              __FUNCTION__, ss);
1320      return xstrdup("<STATE_STATUS_UNKNOWN>");
1321 }
1322
1323 pkg_state_status_t pkg_state_status_from_str(const char *str)
1324 {
1325      int i;
1326
1327      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
1328           if (strcmp(str, pkg_state_status_map[i].str) == 0) {
1329                return pkg_state_status_map[i].value;
1330           }
1331      }
1332
1333      fprintf(stderr, "%s: ERROR: Illegal value for state_status string: %s\n",
1334              __FUNCTION__, str);
1335      return SS_NOT_INSTALLED;
1336 }
1337
1338 int pkg_arch_supported(opkg_conf_t *conf, pkg_t *pkg)
1339 {
1340      nv_pair_list_elt_t *l;
1341
1342      if (!pkg->architecture)
1343           return 1;
1344
1345      list_for_each_entry(l , &conf->arch_list.head, node) {
1346           nv_pair_t *nv = (nv_pair_t *)l->data;
1347           if (strcmp(nv->name, pkg->architecture) == 0) {
1348                opkg_message(conf, OPKG_DEBUG, "arch %s (priority %s) supported for pkg %s\n", nv->name, nv->value, pkg->name);
1349                return 1;
1350           }
1351      }
1352
1353      opkg_message(conf, OPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
1354      return 0;
1355 }
1356
1357 int pkg_get_arch_priority(opkg_conf_t *conf, const char *archname)
1358 {
1359      nv_pair_list_elt_t *l;
1360
1361      list_for_each_entry(l , &conf->arch_list.head, node) {
1362           nv_pair_t *nv = (nv_pair_t *)l->data;
1363           if (strcmp(nv->name, archname) == 0) {
1364                int priority = strtol(nv->value, NULL, 0);
1365                return priority;
1366           }
1367      }
1368      return 0;
1369 }
1370
1371 int pkg_info_preinstall_check(opkg_conf_t *conf)
1372 {
1373      int i;
1374      hash_table_t *pkg_hash = &conf->pkg_hash;
1375      pkg_vec_t *available_pkgs = pkg_vec_alloc();
1376      pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1377
1378      opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: updating arch priority for each package\n");
1379      pkg_hash_fetch_available(pkg_hash, available_pkgs);
1380      /* update arch_priority for each package */
1381      for (i = 0; i < available_pkgs->len; i++) {
1382           pkg_t *pkg = available_pkgs->pkgs[i];
1383           int arch_priority = 1;
1384           if (!pkg)
1385                continue;
1386           // opkg_message(conf, OPKG_DEBUG2, " package %s version=%s arch=%p:", pkg->name, pkg->version, pkg->architecture);
1387           if (pkg->architecture) 
1388                arch_priority = pkg_get_arch_priority(conf, pkg->architecture);
1389           else 
1390                opkg_message(conf, OPKG_ERROR, "pkg_info_preinstall_check: no architecture for package %s\n", pkg->name);
1391           // opkg_message(conf, OPKG_DEBUG2, "%s arch_priority=%d\n", pkg->architecture, arch_priority);
1392           pkg->arch_priority = arch_priority;
1393      }
1394
1395      for (i = 0; i < available_pkgs->len; i++) {
1396           pkg_t *pkg = available_pkgs->pkgs[i];
1397           if (!pkg->arch_priority && (pkg->state_flag || (pkg->state_want != SW_UNKNOWN))) {
1398                /* clear flags and want for any uninstallable package */
1399                opkg_message(conf, OPKG_DEBUG, "Clearing state_want and state_flag for pkg=%s (arch_priority=%d flag=%d want=%d)\n", 
1400                             pkg->name, pkg->arch_priority, pkg->state_flag, pkg->state_want);
1401                pkg->state_want = SW_UNKNOWN;
1402                pkg->state_flag = 0;
1403           }
1404      }
1405      pkg_vec_free(available_pkgs);
1406
1407      /* update the file owner data structure */
1408      opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: update file owner list\n");
1409      pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
1410      for (i = 0; i < installed_pkgs->len; i++) {
1411           pkg_t *pkg = installed_pkgs->pkgs[i];
1412           str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */
1413           str_list_elt_t *iter, *niter;
1414           if (installed_files == NULL) {
1415                opkg_message(conf, OPKG_ERROR, "No installed files for pkg %s\n", pkg->name);
1416                break;
1417           }
1418           for (iter = str_list_first(installed_files), niter = str_list_next(installed_files, iter); 
1419                   iter; 
1420                   iter = niter, niter = str_list_next(installed_files, iter)) {
1421                char *installed_file = (char *) iter->data;
1422                // opkg_message(conf, OPKG_DEBUG2, "pkg %s: file=%s\n", pkg->name, installed_file);
1423                file_hash_set_file_owner(conf, installed_file, pkg);
1424           }
1425           pkg_free_installed_files(pkg);
1426      }
1427      pkg_vec_free(installed_pkgs);
1428
1429      return 0;
1430 }
1431
1432 struct pkg_write_filelist_data {
1433      opkg_conf_t *conf;
1434      pkg_t *pkg;
1435      FILE *stream;
1436 };
1437
1438 void pkg_write_filelist_helper(const char *key, void *entry_, void *data_)
1439 {
1440      struct pkg_write_filelist_data *data = data_;
1441      pkg_t *entry = entry_;
1442      if (entry == data->pkg) {
1443           fprintf(data->stream, "%s\n", key);
1444      }
1445 }
1446
1447 int pkg_write_filelist(opkg_conf_t *conf, pkg_t *pkg)
1448 {
1449      struct pkg_write_filelist_data data;
1450      char *list_file_name = NULL;
1451      int err = 0;
1452
1453      if (!pkg) {
1454           opkg_message(conf, OPKG_ERROR, "Null pkg\n");
1455           return -EINVAL;
1456      }
1457      opkg_message(conf, OPKG_INFO,
1458                   "    creating %s.list file\n", pkg->name);
1459      sprintf_alloc(&list_file_name, "%s/%s.list", pkg->dest->info_dir, pkg->name);
1460      if (!list_file_name) {
1461           opkg_message(conf, OPKG_ERROR, "Failed to alloc list_file_name\n");
1462           return -ENOMEM;
1463      }
1464      opkg_message(conf, OPKG_INFO,
1465                   "    creating %s file for pkg %s\n", list_file_name, pkg->name);
1466      data.stream = fopen(list_file_name, "w");
1467      if (!data.stream) {
1468           opkg_message(conf, OPKG_ERROR, "Could not open %s for writing: %s\n",
1469                        list_file_name, strerror(errno));
1470                        return errno;
1471      }
1472      data.pkg = pkg;
1473      data.conf = conf;
1474      hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data);
1475      fclose(data.stream);
1476      free(list_file_name);
1477
1478      pkg->state_flag &= ~SF_FILELIST_CHANGED;
1479
1480      return err;
1481 }
1482
1483 int pkg_write_changed_filelists(opkg_conf_t *conf)
1484 {
1485      pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1486      hash_table_t *pkg_hash = &conf->pkg_hash;
1487      int i;
1488      int err;
1489      if (conf->noaction)
1490           return 0;
1491
1492      opkg_message(conf, OPKG_INFO, "%s: saving changed filelists\n", __FUNCTION__);
1493      pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
1494      for (i = 0; i < installed_pkgs->len; i++) {
1495           pkg_t *pkg = installed_pkgs->pkgs[i];
1496           if (pkg->state_flag & SF_FILELIST_CHANGED) {
1497                opkg_message(conf, OPKG_DEBUG, "Calling pkg_write_filelist for pkg=%s from %s\n", pkg->name, __FUNCTION__);
1498                err = pkg_write_filelist(conf, pkg);
1499                if (err)
1500                     opkg_message(conf, OPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
1501           }
1502      }
1503      pkg_vec_free (installed_pkgs);
1504      return 0;
1505 }