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