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