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