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