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