Put the tmp file under conf->tmp_dir.
[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 /*
995  * XXX: this should be broken into two functions
996  */
997 str_list_t *pkg_get_installed_files(opkg_conf_t *conf, pkg_t *pkg)
998 {
999      int err, fd;
1000      char *list_file_name = NULL;
1001      FILE *list_file = NULL;
1002      char *line;
1003      char *installed_file_name;
1004      int rootdirlen = 0;
1005
1006      pkg->installed_files_ref_cnt++;
1007
1008      if (pkg->installed_files) {
1009           return pkg->installed_files;
1010      }
1011
1012      pkg->installed_files = str_list_alloc();
1013
1014      /* For uninstalled packages, get the file list directly from the package.
1015         For installed packages, look at the package.list file in the database.
1016      */
1017      if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
1018           if (pkg->local_filename == NULL) {
1019                return pkg->installed_files;
1020           }
1021           /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary
1022              file. In other words, change deb_extract so that it can
1023              simply return the file list as a char *[] rather than
1024              insisting on writing in to a FILE * as it does now. */
1025           sprintf_alloc(&list_file_name, "%s/%s.list.XXXXXX",
1026                                           conf->tmp_dir, pkg->name);
1027           fd = mkstemp(list_file_name);
1028           if (fd == -1) {
1029                opkg_message(conf, OPKG_ERROR, "%s: mkstemp(%s): %s",
1030                                __FUNCTION__, list_file_name, strerror(errno));
1031                free(list_file_name);
1032                return pkg->installed_files;
1033           }
1034           list_file = fdopen(fd, "rw");
1035           if (list_file == NULL) {
1036                opkg_message(conf, OPKG_ERROR, "%s: fdopen: %s",
1037                                __FUNCTION__, strerror(errno));
1038                close(fd);
1039                unlink(list_file_name);
1040                free(list_file_name);
1041                return pkg->installed_files;
1042           }
1043           err = pkg_extract_data_file_names_to_stream(pkg, list_file);
1044           if (err) {
1045                opkg_message(conf, OPKG_ERROR, "%s: Error extracting file list "
1046                                "from %s: %s\n", __FUNCTION__,
1047                                pkg->local_filename, strerror(err));
1048                fclose(list_file);
1049                unlink(list_file_name);
1050                free(list_file_name);
1051                return pkg->installed_files;
1052           }
1053           rewind(list_file);
1054      } else {
1055           sprintf_alloc(&list_file_name, "%s/%s.list",
1056                         pkg->dest->info_dir, pkg->name);
1057           list_file = fopen(list_file_name, "r");
1058           if (list_file == NULL) {
1059                opkg_message(conf, OPKG_ERROR, "%s: fopen(%s): %s\n",
1060                        __FUNCTION__, list_file_name, strerror(errno));
1061                free(list_file_name);
1062                return pkg->installed_files;
1063           }
1064           free(list_file_name);
1065      }
1066
1067      if (conf->offline_root)
1068           rootdirlen = strlen(conf->offline_root);
1069
1070      while (1) {
1071           char *file_name;
1072         
1073           line = file_read_line_alloc(list_file);
1074           if (line == NULL) {
1075                break;
1076           }
1077           str_chomp(line);
1078           file_name = line;
1079
1080           if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
1081                if (*file_name == '.') {
1082                     file_name++;
1083                }
1084                if (*file_name == '/') {
1085                     file_name++;
1086                }
1087                sprintf_alloc(&installed_file_name, "%s%s",
1088                                pkg->dest->root_dir, file_name);
1089           } else {
1090                if (conf->offline_root &&
1091                        strncmp(conf->offline_root, file_name, rootdirlen)) {
1092                     sprintf_alloc(&installed_file_name, "%s%s",
1093                                     conf->offline_root, file_name);
1094                } else {
1095                     // already contains root_dir as header -> ABSOLUTE
1096                     sprintf_alloc(&installed_file_name, "%s", file_name);
1097                }
1098           }
1099           str_list_append(pkg->installed_files, installed_file_name);
1100           free(installed_file_name);
1101           free(line);
1102      }
1103
1104      fclose(list_file);
1105
1106      if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
1107           unlink(list_file_name);
1108           free(list_file_name);
1109      }
1110
1111      return pkg->installed_files;
1112 }
1113
1114 /* XXX: CLEANUP: This function and it's counterpart,
1115    (pkg_get_installed_files), do not match our init/deinit naming
1116    convention. Nor the alloc/free convention. But, then again, neither
1117    of these conventions currrently fit the way these two functions
1118    work. */
1119 int pkg_free_installed_files(pkg_t *pkg)
1120 {
1121      pkg->installed_files_ref_cnt--;
1122
1123      if (pkg->installed_files_ref_cnt > 0)
1124           return 0;
1125
1126      if (pkg->installed_files) {
1127          str_list_purge(pkg->installed_files);
1128      }
1129
1130      pkg->installed_files = NULL;
1131
1132      return 0;
1133 }
1134
1135 int pkg_remove_installed_files_list(opkg_conf_t *conf, pkg_t *pkg)
1136 {
1137      int err;
1138      char *list_file_name;
1139
1140      //I don't think pkg_free_installed_files should be called here. Jamey
1141      //pkg_free_installed_files(pkg);
1142
1143      sprintf_alloc(&list_file_name, "%s/%s.list",
1144                    pkg->dest->info_dir, pkg->name);
1145      if (!conf->noaction) {
1146           err = unlink(list_file_name);
1147           free(list_file_name);
1148
1149           if (err) {
1150                return errno;
1151           }
1152      }
1153      return 0;
1154 }
1155
1156 conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name)
1157 {
1158      conffile_list_elt_t *iter;
1159      conffile_t *conffile;
1160
1161      if (pkg == NULL) {
1162           return NULL;
1163      }
1164
1165      for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
1166           conffile = (conffile_t *)iter->data;
1167
1168           if (strcmp(conffile->name, file_name) == 0) {
1169                return conffile;
1170           }
1171      }
1172
1173      return NULL;
1174 }
1175
1176 int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
1177                    const char *script, const char *args)
1178 {
1179      int err;
1180      char *path;
1181      char *cmd;
1182
1183      if (conf->noaction)
1184              return 0;
1185
1186      /* XXX: CLEANUP: There must be a better way to handle maintainer
1187         scripts when running with offline_root mode and/or a dest other
1188         than '/'. I've been playing around with some clever chroot
1189         tricks and I might come up with something workable. */
1190      /*
1191       * Attempt to provide a restricted environment for offline operation
1192       * Need the following set as a minimum:
1193       * OPKG_OFFLINE_ROOT = absolute path to root dir
1194       * D                 = absolute path to root dir (for OE generated postinst)
1195       * PATH              = something safe (a restricted set of utilities)
1196       */
1197
1198      if (conf->offline_root) {
1199           if (conf->offline_root_path) {
1200             setenv("PATH", conf->offline_root_path, 1);
1201           } else {
1202             opkg_message(conf, OPKG_NOTICE, 
1203                 "(offline root mode: not running %s.%s)\n", pkg->name, script);
1204             return 0;
1205           }
1206           setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
1207           setenv("D", conf->offline_root, 1);
1208      }
1209
1210      /* XXX: FEATURE: When conf->offline_root is set, we should run the
1211         maintainer script within a chroot environment. */
1212
1213      /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages
1214         have scripts in pkg->tmp_unpack_dir. */
1215      if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) {
1216           if (pkg->dest == NULL) {
1217                fprintf(stderr, "%s: ERROR: installed package %s has a NULL dest\n",
1218                        __FUNCTION__, pkg->name);
1219                return EINVAL;
1220           }
1221           sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script);
1222      } else {
1223           if (pkg->tmp_unpack_dir == NULL) {
1224                fprintf(stderr, "%s: ERROR: uninstalled package %s has a NULL tmp_unpack_dir\n",
1225                        __FUNCTION__, pkg->name);
1226                return EINVAL;
1227           }
1228           sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script);
1229      }
1230
1231      opkg_message(conf, OPKG_INFO, "Running script %s\n", path);
1232
1233      setenv("PKG_ROOT",
1234             pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
1235
1236      if (! file_exists(path)) {
1237           free(path);
1238           return 0;
1239      }
1240
1241      sprintf_alloc(&cmd, "%s %s", path, args);
1242      free(path);
1243      {
1244           const char *argv[] = {"sh", "-c", cmd, NULL};
1245           err = xsystem(argv);
1246      }
1247      free(cmd);
1248
1249      if (err) {
1250           fprintf(stderr, "%s script returned status %d\n", script, err);
1251           return err;
1252      }
1253
1254      return 0;
1255 }
1256
1257 char *pkg_state_want_to_str(pkg_state_want_t sw)
1258 {
1259      int i;
1260
1261      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
1262           if (pkg_state_want_map[i].value == sw) {
1263                return xstrdup(pkg_state_want_map[i].str);
1264           }
1265      }
1266
1267      fprintf(stderr, "%s: ERROR: Illegal value for state_want: %d\n",
1268              __FUNCTION__, sw);
1269      return xstrdup("<STATE_WANT_UNKNOWN>");
1270 }
1271
1272 pkg_state_want_t pkg_state_want_from_str(char *str)
1273 {
1274      int i;
1275
1276      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
1277           if (strcmp(str, pkg_state_want_map[i].str) == 0) {
1278                return pkg_state_want_map[i].value;
1279           }
1280      }
1281
1282      fprintf(stderr, "%s: ERROR: Illegal value for state_want string: %s\n",
1283              __FUNCTION__, str);
1284      return SW_UNKNOWN;
1285 }
1286
1287 char *pkg_state_flag_to_str(pkg_state_flag_t sf)
1288 {
1289      int i;
1290      int len = 3; /* ok\000 is minimum */
1291      char *str = NULL;
1292
1293      /* clear the temporary flags before converting to string */
1294      sf &= SF_NONVOLATILE_FLAGS;
1295
1296      if (sf == 0) {
1297           return xstrdup("ok");
1298      } else {
1299
1300           for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1301                if (sf & pkg_state_flag_map[i].value) {
1302                     len += strlen(pkg_state_flag_map[i].str) + 1;
1303                }
1304           }
1305           str = xmalloc(len);
1306           str[0] = 0;
1307           for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1308                if (sf & pkg_state_flag_map[i].value) {
1309                     strcat(str, pkg_state_flag_map[i].str);
1310                     strcat(str, ",");
1311                }
1312           }
1313           len = strlen(str);
1314           str[len-1] = 0; /* squash last comma */
1315           return str;
1316      }
1317 }
1318
1319 pkg_state_flag_t pkg_state_flag_from_str(const char *str)
1320 {
1321      int i;
1322      int sf = SF_OK;
1323
1324      if (strcmp(str, "ok") == 0) {
1325           return SF_OK;
1326      }
1327      for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1328           const char *sfname = pkg_state_flag_map[i].str;
1329           int sfname_len = strlen(sfname);
1330           if (strncmp(str, sfname, sfname_len) == 0) {
1331                sf |= pkg_state_flag_map[i].value;
1332                str += sfname_len;
1333                if (str[0] == ',') {
1334                     str++;
1335                } else {
1336                     break;
1337                }
1338           }
1339      }
1340
1341      return sf;
1342 }
1343
1344 char *pkg_state_status_to_str(pkg_state_status_t ss)
1345 {
1346      int i;
1347
1348      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
1349           if (pkg_state_status_map[i].value == ss) {
1350                return xstrdup(pkg_state_status_map[i].str);
1351           }
1352      }
1353
1354      fprintf(stderr, "%s: ERROR: Illegal value for state_status: %d\n",
1355              __FUNCTION__, ss);
1356      return xstrdup("<STATE_STATUS_UNKNOWN>");
1357 }
1358
1359 pkg_state_status_t pkg_state_status_from_str(const char *str)
1360 {
1361      int i;
1362
1363      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
1364           if (strcmp(str, pkg_state_status_map[i].str) == 0) {
1365                return pkg_state_status_map[i].value;
1366           }
1367      }
1368
1369      fprintf(stderr, "%s: ERROR: Illegal value for state_status string: %s\n",
1370              __FUNCTION__, str);
1371      return SS_NOT_INSTALLED;
1372 }
1373
1374 int pkg_arch_supported(opkg_conf_t *conf, pkg_t *pkg)
1375 {
1376      nv_pair_list_elt_t *l;
1377
1378      if (!pkg->architecture)
1379           return 1;
1380
1381      list_for_each_entry(l , &conf->arch_list.head, node) {
1382           nv_pair_t *nv = (nv_pair_t *)l->data;
1383           if (strcmp(nv->name, pkg->architecture) == 0) {
1384                opkg_message(conf, OPKG_DEBUG, "arch %s (priority %s) supported for pkg %s\n", nv->name, nv->value, pkg->name);
1385                return 1;
1386           }
1387      }
1388
1389      opkg_message(conf, OPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
1390      return 0;
1391 }
1392
1393 int pkg_get_arch_priority(opkg_conf_t *conf, const char *archname)
1394 {
1395      nv_pair_list_elt_t *l;
1396
1397      list_for_each_entry(l , &conf->arch_list.head, node) {
1398           nv_pair_t *nv = (nv_pair_t *)l->data;
1399           if (strcmp(nv->name, archname) == 0) {
1400                int priority = strtol(nv->value, NULL, 0);
1401                return priority;
1402           }
1403      }
1404      return 0;
1405 }
1406
1407 int pkg_info_preinstall_check(opkg_conf_t *conf)
1408 {
1409      int i;
1410      hash_table_t *pkg_hash = &conf->pkg_hash;
1411      pkg_vec_t *available_pkgs = pkg_vec_alloc();
1412      pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1413
1414      opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: updating arch priority for each package\n");
1415      pkg_hash_fetch_available(pkg_hash, available_pkgs);
1416      /* update arch_priority for each package */
1417      for (i = 0; i < available_pkgs->len; i++) {
1418           pkg_t *pkg = available_pkgs->pkgs[i];
1419           int arch_priority = 1;
1420           if (!pkg)
1421                continue;
1422           // opkg_message(conf, OPKG_DEBUG2, " package %s version=%s arch=%p:", pkg->name, pkg->version, pkg->architecture);
1423           if (pkg->architecture) 
1424                arch_priority = pkg_get_arch_priority(conf, pkg->architecture);
1425           else 
1426                opkg_message(conf, OPKG_ERROR, "pkg_info_preinstall_check: no architecture for package %s\n", pkg->name);
1427           // opkg_message(conf, OPKG_DEBUG2, "%s arch_priority=%d\n", pkg->architecture, arch_priority);
1428           pkg->arch_priority = arch_priority;
1429      }
1430
1431      for (i = 0; i < available_pkgs->len; i++) {
1432           pkg_t *pkg = available_pkgs->pkgs[i];
1433           if (!pkg->arch_priority && (pkg->state_flag || (pkg->state_want != SW_UNKNOWN))) {
1434                /* clear flags and want for any uninstallable package */
1435                opkg_message(conf, OPKG_DEBUG, "Clearing state_want and state_flag for pkg=%s (arch_priority=%d flag=%d want=%d)\n", 
1436                             pkg->name, pkg->arch_priority, pkg->state_flag, pkg->state_want);
1437                pkg->state_want = SW_UNKNOWN;
1438                pkg->state_flag = 0;
1439           }
1440      }
1441      pkg_vec_free(available_pkgs);
1442
1443      /* update the file owner data structure */
1444      opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: update file owner list\n");
1445      pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
1446      for (i = 0; i < installed_pkgs->len; i++) {
1447           pkg_t *pkg = installed_pkgs->pkgs[i];
1448           str_list_t *installed_files = pkg_get_installed_files(conf, pkg); /* this causes installed_files to be cached */
1449           str_list_elt_t *iter, *niter;
1450           if (installed_files == NULL) {
1451                opkg_message(conf, OPKG_ERROR, "No installed files for pkg %s\n", pkg->name);
1452                break;
1453           }
1454           for (iter = str_list_first(installed_files), niter = str_list_next(installed_files, iter); 
1455                   iter; 
1456                   iter = niter, niter = str_list_next(installed_files, iter)) {
1457                char *installed_file = (char *) iter->data;
1458                // opkg_message(conf, OPKG_DEBUG2, "pkg %s: file=%s\n", pkg->name, installed_file);
1459                file_hash_set_file_owner(conf, installed_file, pkg);
1460           }
1461           pkg_free_installed_files(pkg);
1462      }
1463      pkg_vec_free(installed_pkgs);
1464
1465      return 0;
1466 }
1467
1468 struct pkg_write_filelist_data {
1469      opkg_conf_t *conf;
1470      pkg_t *pkg;
1471      FILE *stream;
1472 };
1473
1474 void pkg_write_filelist_helper(const char *key, void *entry_, void *data_)
1475 {
1476      struct pkg_write_filelist_data *data = data_;
1477      pkg_t *entry = entry_;
1478      if (entry == data->pkg) {
1479           fprintf(data->stream, "%s\n", key);
1480      }
1481 }
1482
1483 int pkg_write_filelist(opkg_conf_t *conf, pkg_t *pkg)
1484 {
1485      struct pkg_write_filelist_data data;
1486      char *list_file_name = NULL;
1487      int err = 0;
1488
1489      if (!pkg) {
1490           opkg_message(conf, OPKG_ERROR, "Null pkg\n");
1491           return -EINVAL;
1492      }
1493      opkg_message(conf, OPKG_INFO,
1494                   "    creating %s.list file\n", pkg->name);
1495      sprintf_alloc(&list_file_name, "%s/%s.list", pkg->dest->info_dir, pkg->name);
1496      if (!list_file_name) {
1497           opkg_message(conf, OPKG_ERROR, "Failed to alloc list_file_name\n");
1498           return -ENOMEM;
1499      }
1500      opkg_message(conf, OPKG_INFO,
1501                   "    creating %s file for pkg %s\n", list_file_name, pkg->name);
1502      data.stream = fopen(list_file_name, "w");
1503      if (!data.stream) {
1504           opkg_message(conf, OPKG_ERROR, "Could not open %s for writing: %s\n",
1505                        list_file_name, strerror(errno));
1506                        return errno;
1507      }
1508      data.pkg = pkg;
1509      data.conf = conf;
1510      hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data);
1511      fclose(data.stream);
1512      free(list_file_name);
1513
1514      pkg->state_flag &= ~SF_FILELIST_CHANGED;
1515
1516      return err;
1517 }
1518
1519 int pkg_write_changed_filelists(opkg_conf_t *conf)
1520 {
1521      pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1522      hash_table_t *pkg_hash = &conf->pkg_hash;
1523      int i;
1524      int err;
1525      if (conf->noaction)
1526           return 0;
1527
1528      opkg_message(conf, OPKG_INFO, "%s: saving changed filelists\n", __FUNCTION__);
1529      pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
1530      for (i = 0; i < installed_pkgs->len; i++) {
1531           pkg_t *pkg = installed_pkgs->pkgs[i];
1532           if (pkg->state_flag & SF_FILELIST_CHANGED) {
1533                opkg_message(conf, OPKG_DEBUG, "Calling pkg_write_filelist for pkg=%s from %s\n", pkg->name, __FUNCTION__);
1534                err = pkg_write_filelist(conf, pkg);
1535                if (err)
1536                     opkg_message(conf, OPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
1537           }
1538      }
1539      pkg_vec_free (installed_pkgs);
1540      return 0;
1541 }