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