Remove the assumption that pkg fields have been allocated and need free()ing.
[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 pkg_init_from_file(pkg_t *pkg, const char *filename)
319 {
320      int err;
321      char **raw, **raw_start;
322      FILE *control_file;
323
324      err = pkg_init(pkg);
325      if (err) { return err; }
326
327      pkg->local_filename = xstrdup(filename);
328     
329      control_file = tmpfile();
330      err = pkg_extract_control_file_to_stream(pkg, control_file);
331      if (err) { return err; }
332
333      rewind(control_file);
334      raw = raw_start = read_raw_pkgs_from_stream(control_file);
335      pkg_parse_raw(pkg, &raw, NULL, NULL);
336
337      fclose(control_file);
338
339      raw = raw_start;
340      while (*raw) {
341           free(*raw++);
342      }
343      free(raw_start);
344
345      return 0;
346 }
347
348 /* Merge any new information in newpkg into oldpkg */
349 /* XXX: CLEANUP: This function shouldn't actually modify anything in
350    newpkg, but should leave it usable. This rework is so that
351    pkg_hash_insert doesn't clobber the pkg that you pass into it. */
352 /* 
353  * uh, i thought that i had originally written this so that it took 
354  * two pkgs and returned a new one?  we can do that again... -sma
355  */
356 int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg, int set_status)
357 {
358      if (oldpkg == newpkg) {
359           return 0;
360      }
361
362      if (!oldpkg->src)
363           oldpkg->src = newpkg->src;
364      if (!oldpkg->dest)
365           oldpkg->dest = newpkg->dest;
366      if (!oldpkg->architecture)
367           oldpkg->architecture = xstrdup(newpkg->architecture);
368      if (!oldpkg->arch_priority)
369           oldpkg->arch_priority = newpkg->arch_priority;
370      if (!oldpkg->section)
371           oldpkg->section = xstrdup(newpkg->section);
372      if(!oldpkg->maintainer)
373           oldpkg->maintainer = xstrdup(newpkg->maintainer);
374      if(!oldpkg->description)
375           oldpkg->description = xstrdup(newpkg->description);
376      if (set_status) {
377           /* merge the state_flags from the new package */
378           oldpkg->state_want = newpkg->state_want;
379           oldpkg->state_status = newpkg->state_status;
380           oldpkg->state_flag = newpkg->state_flag;
381      } else {
382           if (oldpkg->state_want == SW_UNKNOWN)
383                oldpkg->state_want = newpkg->state_want;
384           if (oldpkg->state_status == SS_NOT_INSTALLED)
385                oldpkg->state_status = newpkg->state_status;
386           oldpkg->state_flag |= newpkg->state_flag;
387      }
388
389      if (!oldpkg->depends_str && !oldpkg->pre_depends_str && !oldpkg->recommends_str && !oldpkg->suggests_str) {
390           oldpkg->depends_str = newpkg->depends_str;
391           newpkg->depends_str = NULL;
392           oldpkg->depends_count = newpkg->depends_count;
393           newpkg->depends_count = 0;
394
395           oldpkg->depends = newpkg->depends;
396           newpkg->depends = NULL;
397
398           oldpkg->pre_depends_str = newpkg->pre_depends_str;
399           newpkg->pre_depends_str = NULL;
400           oldpkg->pre_depends_count = newpkg->pre_depends_count;
401           newpkg->pre_depends_count = 0;
402
403           oldpkg->recommends_str = newpkg->recommends_str;
404           newpkg->recommends_str = NULL;
405           oldpkg->recommends_count = newpkg->recommends_count;
406           newpkg->recommends_count = 0;
407
408           oldpkg->suggests_str = newpkg->suggests_str;
409           newpkg->suggests_str = NULL;
410           oldpkg->suggests_count = newpkg->suggests_count;
411           newpkg->suggests_count = 0;
412      }
413
414      if (!oldpkg->provides_str) {
415           oldpkg->provides_str = newpkg->provides_str;
416           newpkg->provides_str = NULL;
417           oldpkg->provides_count = newpkg->provides_count;
418           newpkg->provides_count = 0;
419
420           oldpkg->provides = newpkg->provides;
421           newpkg->provides = NULL;
422      }
423
424      if (!oldpkg->conflicts_str) {
425           oldpkg->conflicts_str = newpkg->conflicts_str;
426           newpkg->conflicts_str = NULL;
427           oldpkg->conflicts_count = newpkg->conflicts_count;
428           newpkg->conflicts_count = 0;
429
430           oldpkg->conflicts = newpkg->conflicts;
431           newpkg->conflicts = NULL;
432      }
433
434      if (!oldpkg->replaces_str) {
435           oldpkg->replaces_str = newpkg->replaces_str;
436           newpkg->replaces_str = NULL;
437           oldpkg->replaces_count = newpkg->replaces_count;
438           newpkg->replaces_count = 0;
439
440           oldpkg->replaces = newpkg->replaces;
441           newpkg->replaces = NULL;
442      }
443
444      if (!oldpkg->filename)
445           oldpkg->filename = xstrdup(newpkg->filename);
446      if (!oldpkg->local_filename)
447           oldpkg->local_filename = xstrdup(newpkg->local_filename);
448      if (!oldpkg->tmp_unpack_dir)
449           oldpkg->tmp_unpack_dir = xstrdup(newpkg->tmp_unpack_dir);
450      if (!oldpkg->md5sum)
451           oldpkg->md5sum = xstrdup(newpkg->md5sum);
452 #if defined HAVE_SHA256
453      if (!oldpkg->sha256sum)
454           oldpkg->sha256sum = xstrdup(newpkg->sha256sum);
455 #endif
456      if (!oldpkg->size)
457           oldpkg->size = xstrdup(newpkg->size);
458      if (!oldpkg->installed_size)
459           oldpkg->installed_size = xstrdup(newpkg->installed_size);
460      if (!oldpkg->priority)
461           oldpkg->priority = xstrdup(newpkg->priority);
462      if (!oldpkg->source)
463           oldpkg->source = xstrdup(newpkg->source);
464      if (nv_pair_list_empty(&oldpkg->conffiles)){
465           list_splice_init(&newpkg->conffiles.head, &oldpkg->conffiles.head);
466           conffile_list_init(&newpkg->conffiles);
467      }
468      if (!oldpkg->installed_files){
469           oldpkg->installed_files = newpkg->installed_files;
470           oldpkg->installed_files_ref_cnt = newpkg->installed_files_ref_cnt;
471           newpkg->installed_files = NULL;
472      }
473      if (!oldpkg->essential)
474           oldpkg->essential = newpkg->essential;
475
476      return 0;
477 }
478
479 abstract_pkg_t *abstract_pkg_new(void)
480 {
481      abstract_pkg_t * ab_pkg;
482
483      ab_pkg = xcalloc(1, sizeof(abstract_pkg_t));
484
485      if (ab_pkg == NULL) {
486           fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
487           return NULL;
488      }
489
490      if ( abstract_pkg_init(ab_pkg) < 0 ) 
491         return NULL;
492
493      return ab_pkg;
494 }
495
496 int abstract_pkg_init(abstract_pkg_t *ab_pkg)
497 {
498      ab_pkg->provided_by = abstract_pkg_vec_alloc();
499      if (ab_pkg->provided_by==NULL){
500         return -1;
501      }
502      ab_pkg->dependencies_checked = 0;
503      ab_pkg->state_status = SS_NOT_INSTALLED;
504
505      return 0;
506 }
507
508 void set_flags_from_control(opkg_conf_t *conf, pkg_t *pkg){
509      char * temp_str;
510      char **raw =NULL;
511      char **raw_start=NULL; 
512
513      size_t str_size = strlen(pkg->dest->info_dir)+strlen(pkg->name)+12;
514      temp_str = (char *) alloca (str_size);
515      memset(temp_str, 0 , str_size);
516      
517      if (temp_str == NULL ){
518         opkg_message(conf, OPKG_INFO, "Out of memory in  %s\n", __FUNCTION__);
519         return;
520      }
521      sprintf( temp_str,"%s/%s.control",pkg->dest->info_dir,pkg->name);
522    
523      raw = raw_start = read_raw_pkgs_from_file(temp_str);
524      if (raw == NULL ){
525         opkg_message(conf, OPKG_ERROR, "Unable to open the control file in  %s\n", __FUNCTION__);
526         return;
527      }
528
529      while(*raw){
530         if (!pkg_valorize_other_field(pkg, &raw ) == 0) {
531             opkg_message(conf, OPKG_DEBUG, "unable to read control file for %s. May be empty\n", pkg->name);
532         }
533      }
534      raw = raw_start;
535      while (*raw) {
536         if (raw!=NULL)
537           free(*raw++);
538      }
539
540      free(raw_start); 
541
542      return ;
543
544 }
545
546 void pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field)
547 {
548      int i;
549      int flag_provide_false = 0;
550
551      if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
552           goto UNKNOWN_FMT_FIELD;
553      }
554
555      switch (field[0])
556      {
557      case 'a':
558      case 'A':
559           if (strcasecmp(field, "Architecture") == 0) {
560                if (pkg->architecture) {
561                    fprintf(fp, "Architecture: %s\n", pkg->architecture);
562                }
563           } else if (strcasecmp(field, "Auto-Installed") == 0) {
564                 if (pkg->auto_installed)
565                     fprintf(fp, "Auto-Installed: yes\n");
566           } else {
567                goto UNKNOWN_FMT_FIELD;
568           }
569           break;
570      case 'c':
571      case 'C':
572           if (strcasecmp(field, "Conffiles") == 0) {
573                conffile_list_elt_t *iter;
574
575                if (nv_pair_list_empty(&pkg->conffiles))
576                     return;
577
578                fprintf(fp, "Conffiles:\n");
579                for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
580                     if (((conffile_t *)iter->data)->name && ((conffile_t *)iter->data)->value) {
581                          fprintf(fp, "%s %s\n", 
582                                  ((conffile_t *)iter->data)->name, 
583                                  ((conffile_t *)iter->data)->value);
584                     }
585                }
586           } else if (strcasecmp(field, "Conflicts") == 0) {
587                if (pkg->conflicts_count) {
588                     fprintf(fp, "Conflicts:");
589                     for(i = 0; i < pkg->conflicts_count; i++) {
590                         fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->conflicts_str[i]);
591                     }
592                     fprintf(fp, "\n");
593                }
594           } else {
595                goto UNKNOWN_FMT_FIELD;
596           }
597           break;
598      case 'd':
599      case 'D':
600           if (strcasecmp(field, "Depends") == 0) {
601                if (pkg->depends_count) {
602                     fprintf(fp, "Depends:");
603                     for(i = 0; i < pkg->depends_count; i++) {
604                         fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->depends_str[i]);
605                     }
606                     fprintf(fp, "\n");
607                }
608           } else if (strcasecmp(field, "Description") == 0) {
609                if (pkg->description) {
610                    fprintf(fp, "Description: %s\n", pkg->description);
611                }
612           } else {
613                goto UNKNOWN_FMT_FIELD;
614           }
615           break;
616      case 'e':
617      case 'E':
618           if (pkg->essential) {
619               fprintf(fp, "Essential: yes\n");
620           }
621           break;
622      case 'f':
623      case 'F':
624           if (pkg->filename) {
625               fprintf(fp, "Filename: %s\n", pkg->filename);
626           }
627           break;
628      case 'i':
629      case 'I':
630           if (strcasecmp(field, "Installed-Size") == 0) {
631                fprintf(fp, "Installed-Size: %s\n", pkg->installed_size);
632           } else if (strcasecmp(field, "Installed-Time") == 0 && pkg->installed_time) {
633                fprintf(fp, "Installed-Time: %lu\n", pkg->installed_time);
634           }
635           break;
636      case 'm':
637      case 'M':
638           if (strcasecmp(field, "Maintainer") == 0) {
639                if (pkg->maintainer) {
640                    fprintf(fp, "maintainer: %s\n", pkg->maintainer);
641                }
642           } else if (strcasecmp(field, "MD5sum") == 0) {
643                if (pkg->md5sum) {
644                    fprintf(fp, "MD5Sum: %s\n", pkg->md5sum);
645                }
646           } else {
647                goto UNKNOWN_FMT_FIELD;
648           }
649           break;
650      case 'p':
651      case 'P':
652           if (strcasecmp(field, "Package") == 0) {
653                fprintf(fp, "Package: %s\n", pkg->name);
654           } else if (strcasecmp(field, "Priority") == 0) {
655                fprintf(fp, "Priority: %s\n", pkg->priority);
656           } else if (strcasecmp(field, "Provides") == 0) {
657                if (pkg->provides_count) {
658                /* Here we check if the opkg_internal_use_only is used, and we discard it.*/
659                   for ( i=0; i < pkg->provides_count; i++ ){
660                       if (strstr(pkg->provides_str[i],"opkg_internal_use_only")!=NULL) {
661                          memset (pkg->provides_str[i],'\x0',strlen(pkg->provides_str[i])); /* Pigi clear my trick flag, just in case */
662                          flag_provide_false = 1;
663                       }
664                   }
665                   if ( !flag_provide_false ||                                             /* Pigi there is not my trick flag */
666                      ((flag_provide_false) &&  (pkg->provides_count > 1))){             /* Pigi There is, but we also have others Provides */
667                      fprintf(fp, "Provides:");
668                      for(i = 0; i < pkg->provides_count; i++) {
669                          if (strlen(pkg->provides_str[i])>0) {
670                             fprintf(fp, "%s %s", i == 1 ? "" : ",", pkg->provides_str[i]);
671                          }
672                      }
673                      fprintf(fp, "\n");
674                   }
675                }
676           } else {
677                goto UNKNOWN_FMT_FIELD;
678           }
679           break;
680      case 'r':
681      case 'R':
682           if (strcasecmp (field, "Replaces") == 0) {
683                if (pkg->replaces_count) {
684                     fprintf(fp, "Replaces:");
685                     for (i = 0; i < pkg->replaces_count; i++) {
686                         fprintf(fp, "%s %s", i == 0 ? "" : ",", pkg->replaces_str[i]);
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 *pkg_version_str_alloc(pkg_t *pkg)
982 {
983      char *complete_version;
984      char *epoch_str;
985      char *revision_str;
986
987      if (pkg->epoch) {
988           sprintf_alloc(&epoch_str, "%d:", pkg->epoch);
989      } else {
990           epoch_str = xstrdup("");
991      }
992
993      if (pkg->revision && strlen(pkg->revision)) {
994           sprintf_alloc(&revision_str, "-%s", pkg->revision);
995      } else {
996           revision_str = xstrdup("");
997      }
998
999
1000      sprintf_alloc(&complete_version, "%s%s%s",
1001                    epoch_str, pkg->version, revision_str);
1002
1003      free(epoch_str);
1004      free(revision_str);
1005
1006      return complete_version;
1007 }
1008
1009 str_list_t *pkg_get_installed_files(pkg_t *pkg)
1010 {
1011      int err;
1012      char *list_file_name = NULL;
1013      FILE *list_file = NULL;
1014      char *line;
1015      char *installed_file_name;
1016      int rootdirlen;
1017
1018      pkg->installed_files_ref_cnt++;
1019
1020      if (pkg->installed_files) {
1021           return pkg->installed_files;
1022      }
1023
1024      pkg->installed_files = str_list_alloc();
1025
1026      /* For uninstalled packages, get the file list directly from the package.
1027         For installed packages, look at the package.list file in the database.
1028      */
1029      if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
1030           if (pkg->local_filename == NULL) {
1031                return pkg->installed_files;
1032           }
1033           /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary
1034              file. In other words, change deb_extract so that it can
1035              simply return the file list as a char *[] rather than
1036              insisting on writing in to a FILE * as it does now. */
1037           list_file = tmpfile();
1038           err = pkg_extract_data_file_names_to_stream(pkg, list_file);
1039           if (err) {
1040                fclose(list_file);
1041                fprintf(stderr, "%s: Error extracting file list from %s: %s\n",
1042                        __FUNCTION__, pkg->local_filename, strerror(err));
1043                return pkg->installed_files;
1044           }
1045           rewind(list_file);
1046      } else {
1047           sprintf_alloc(&list_file_name, "%s/%s.list",
1048                         pkg->dest->info_dir, pkg->name);
1049           if (! file_exists(list_file_name)) {
1050                free(list_file_name);
1051                return pkg->installed_files;
1052           }
1053
1054           list_file = fopen(list_file_name, "r");
1055           if (list_file == NULL) {
1056                fprintf(stderr, "WARNING: Cannot open %s: %s\n",
1057                        list_file_name, strerror(errno));
1058                free(list_file_name);
1059                return pkg->installed_files;
1060           }
1061           free(list_file_name);
1062      }
1063
1064      rootdirlen = strlen( pkg->dest->root_dir );
1065      while (1) {
1066           char *file_name;
1067         
1068           line = file_read_line_alloc(list_file);
1069           if (line == NULL) {
1070                break;
1071           }
1072           str_chomp(line);
1073           file_name = line;
1074
1075           /* Take pains to avoid uglies like "/./" in the middle of file_name. */
1076           if( strncmp( pkg->dest->root_dir, 
1077                        file_name, 
1078                        rootdirlen ) ) {
1079                if (*file_name == '.') {
1080                     file_name++;
1081                }
1082                if (*file_name == '/') {
1083                     file_name++;
1084                }
1085
1086                /* Freed in pkg_free_installed_files */
1087                sprintf_alloc(&installed_file_name, "%s%s", pkg->dest->root_dir, file_name);
1088           } else {
1089                // already contains root_dir as header -> ABSOLUTE
1090                sprintf_alloc(&installed_file_name, "%s", file_name);
1091           }
1092           str_list_append(pkg->installed_files, installed_file_name);
1093           free(installed_file_name);
1094           free(line);
1095      }
1096
1097      fclose(list_file);
1098
1099      return pkg->installed_files;
1100 }
1101
1102 /* XXX: CLEANUP: This function and it's counterpart,
1103    (pkg_get_installed_files), do not match our init/deinit naming
1104    convention. Nor the alloc/free convention. But, then again, neither
1105    of these conventions currrently fit the way these two functions
1106    work. */
1107 int pkg_free_installed_files(pkg_t *pkg)
1108 {
1109      pkg->installed_files_ref_cnt--;
1110
1111      if (pkg->installed_files_ref_cnt > 0)
1112           return 0;
1113
1114      if (pkg->installed_files) {
1115          str_list_purge(pkg->installed_files);
1116      }
1117
1118      pkg->installed_files = NULL;
1119
1120      return 0;
1121 }
1122
1123 int pkg_remove_installed_files_list(opkg_conf_t *conf, pkg_t *pkg)
1124 {
1125      int err;
1126      char *list_file_name;
1127
1128      //I don't think pkg_free_installed_files should be called here. Jamey
1129      //pkg_free_installed_files(pkg);
1130
1131      sprintf_alloc(&list_file_name, "%s/%s.list",
1132                    pkg->dest->info_dir, pkg->name);
1133      if (!conf->noaction) {
1134           err = unlink(list_file_name);
1135           free(list_file_name);
1136
1137           if (err) {
1138                return errno;
1139           }
1140      }
1141      return 0;
1142 }
1143
1144 conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name)
1145 {
1146      conffile_list_elt_t *iter;
1147      conffile_t *conffile;
1148
1149      if (pkg == NULL) {
1150           return NULL;
1151      }
1152
1153      for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
1154           conffile = (conffile_t *)iter->data;
1155
1156           if (strcmp(conffile->name, file_name) == 0) {
1157                return conffile;
1158           }
1159      }
1160
1161      return NULL;
1162 }
1163
1164 int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
1165                    const char *script, const char *args)
1166 {
1167      int err;
1168      char *path;
1169      char *cmd;
1170
1171      if (conf->noaction)
1172              return 0;
1173
1174      /* XXX: CLEANUP: There must be a better way to handle maintainer
1175         scripts when running with offline_root mode and/or a dest other
1176         than '/'. I've been playing around with some clever chroot
1177         tricks and I might come up with something workable. */
1178      /*
1179       * Attempt to provide a restricted environment for offline operation
1180       * Need the following set as a minimum:
1181       * OPKG_OFFLINE_ROOT = absolute path to root dir
1182       * D                 = absolute path to root dir (for OE generated postinst)
1183       * PATH              = something safe (a restricted set of utilities)
1184       */
1185
1186      if (conf->offline_root) {
1187           if (conf->offline_root_path) {
1188             setenv("PATH", conf->offline_root_path, 1);
1189           } else {
1190             opkg_message(conf, OPKG_NOTICE, 
1191                 "(offline root mode: not running %s.%s)\n", pkg->name, script);
1192             return 0;
1193           }
1194           setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
1195           setenv("D", conf->offline_root, 1);
1196      }
1197
1198      /* XXX: FEATURE: When conf->offline_root is set, we should run the
1199         maintainer script within a chroot environment. */
1200
1201      /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages
1202         have scripts in pkg->tmp_unpack_dir. */
1203      if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) {
1204           if (pkg->dest == NULL) {
1205                fprintf(stderr, "%s: ERROR: installed package %s has a NULL dest\n",
1206                        __FUNCTION__, pkg->name);
1207                return EINVAL;
1208           }
1209           sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script);
1210      } else {
1211           if (pkg->tmp_unpack_dir == NULL) {
1212                fprintf(stderr, "%s: ERROR: uninstalled package %s has a NULL tmp_unpack_dir\n",
1213                        __FUNCTION__, pkg->name);
1214                return EINVAL;
1215           }
1216           sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script);
1217      }
1218
1219      opkg_message(conf, OPKG_INFO, "Running script %s\n", path);
1220
1221      setenv("PKG_ROOT",
1222             pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
1223
1224      if (! file_exists(path)) {
1225           free(path);
1226           return 0;
1227      }
1228
1229      sprintf_alloc(&cmd, "%s %s", path, args);
1230      free(path);
1231
1232      err = xsystem(cmd);
1233      free(cmd);
1234
1235      if (err) {
1236           fprintf(stderr, "%s script returned status %d\n", script, err);
1237           return err;
1238      }
1239
1240      return 0;
1241 }
1242
1243 char *pkg_state_want_to_str(pkg_state_want_t sw)
1244 {
1245      int i;
1246
1247      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
1248           if (pkg_state_want_map[i].value == sw) {
1249                return xstrdup(pkg_state_want_map[i].str);
1250           }
1251      }
1252
1253      fprintf(stderr, "%s: ERROR: Illegal value for state_want: %d\n",
1254              __FUNCTION__, sw);
1255      return xstrdup("<STATE_WANT_UNKNOWN>");
1256 }
1257
1258 pkg_state_want_t pkg_state_want_from_str(char *str)
1259 {
1260      int i;
1261
1262      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
1263           if (strcmp(str, pkg_state_want_map[i].str) == 0) {
1264                return pkg_state_want_map[i].value;
1265           }
1266      }
1267
1268      fprintf(stderr, "%s: ERROR: Illegal value for state_want string: %s\n",
1269              __FUNCTION__, str);
1270      return SW_UNKNOWN;
1271 }
1272
1273 char *pkg_state_flag_to_str(pkg_state_flag_t sf)
1274 {
1275      int i;
1276      int len = 3; /* ok\000 is minimum */
1277      char *str = NULL;
1278
1279      /* clear the temporary flags before converting to string */
1280      sf &= SF_NONVOLATILE_FLAGS;
1281
1282      if (sf == 0) {
1283           return xstrdup("ok");
1284      } else {
1285
1286           for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1287                if (sf & pkg_state_flag_map[i].value) {
1288                     len += strlen(pkg_state_flag_map[i].str) + 1;
1289                }
1290           }
1291           str = xmalloc(len);
1292           str[0] = 0;
1293           for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1294                if (sf & pkg_state_flag_map[i].value) {
1295                     strcat(str, pkg_state_flag_map[i].str);
1296                     strcat(str, ",");
1297                }
1298           }
1299           len = strlen(str);
1300           str[len-1] = 0; /* squash last comma */
1301           return str;
1302      }
1303 }
1304
1305 pkg_state_flag_t pkg_state_flag_from_str(const char *str)
1306 {
1307      int i;
1308      int sf = SF_OK;
1309
1310      if (strcmp(str, "ok") == 0) {
1311           return SF_OK;
1312      }
1313      for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1314           const char *sfname = pkg_state_flag_map[i].str;
1315           int sfname_len = strlen(sfname);
1316           if (strncmp(str, sfname, sfname_len) == 0) {
1317                sf |= pkg_state_flag_map[i].value;
1318                str += sfname_len;
1319                if (str[0] == ',') {
1320                     str++;
1321                } else {
1322                     break;
1323                }
1324           }
1325      }
1326
1327      return sf;
1328 }
1329
1330 char *pkg_state_status_to_str(pkg_state_status_t ss)
1331 {
1332      int i;
1333
1334      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
1335           if (pkg_state_status_map[i].value == ss) {
1336                return xstrdup(pkg_state_status_map[i].str);
1337           }
1338      }
1339
1340      fprintf(stderr, "%s: ERROR: Illegal value for state_status: %d\n",
1341              __FUNCTION__, ss);
1342      return xstrdup("<STATE_STATUS_UNKNOWN>");
1343 }
1344
1345 pkg_state_status_t pkg_state_status_from_str(const char *str)
1346 {
1347      int i;
1348
1349      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
1350           if (strcmp(str, pkg_state_status_map[i].str) == 0) {
1351                return pkg_state_status_map[i].value;
1352           }
1353      }
1354
1355      fprintf(stderr, "%s: ERROR: Illegal value for state_status string: %s\n",
1356              __FUNCTION__, str);
1357      return SS_NOT_INSTALLED;
1358 }
1359
1360 int pkg_arch_supported(opkg_conf_t *conf, pkg_t *pkg)
1361 {
1362      nv_pair_list_elt_t *l;
1363
1364      if (!pkg->architecture)
1365           return 1;
1366
1367      list_for_each_entry(l , &conf->arch_list.head, node) {
1368           nv_pair_t *nv = (nv_pair_t *)l->data;
1369           if (strcmp(nv->name, pkg->architecture) == 0) {
1370                opkg_message(conf, OPKG_DEBUG, "arch %s (priority %s) supported for pkg %s\n", nv->name, nv->value, pkg->name);
1371                return 1;
1372           }
1373      }
1374
1375      opkg_message(conf, OPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
1376      return 0;
1377 }
1378
1379 int pkg_get_arch_priority(opkg_conf_t *conf, const char *archname)
1380 {
1381      nv_pair_list_elt_t *l;
1382
1383      list_for_each_entry(l , &conf->arch_list.head, node) {
1384           nv_pair_t *nv = (nv_pair_t *)l->data;
1385           if (strcmp(nv->name, archname) == 0) {
1386                int priority = strtol(nv->value, NULL, 0);
1387                return priority;
1388           }
1389      }
1390      return 0;
1391 }
1392
1393 int pkg_info_preinstall_check(opkg_conf_t *conf)
1394 {
1395      int i;
1396      hash_table_t *pkg_hash = &conf->pkg_hash;
1397      pkg_vec_t *available_pkgs = pkg_vec_alloc();
1398      pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1399
1400      opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: updating arch priority for each package\n");
1401      pkg_hash_fetch_available(pkg_hash, available_pkgs);
1402      /* update arch_priority for each package */
1403      for (i = 0; i < available_pkgs->len; i++) {
1404           pkg_t *pkg = available_pkgs->pkgs[i];
1405           int arch_priority = 1;
1406           if (!pkg)
1407                continue;
1408           // opkg_message(conf, OPKG_DEBUG2, " package %s version=%s arch=%p:", pkg->name, pkg->version, pkg->architecture);
1409           if (pkg->architecture) 
1410                arch_priority = pkg_get_arch_priority(conf, pkg->architecture);
1411           else 
1412                opkg_message(conf, OPKG_ERROR, "pkg_info_preinstall_check: no architecture for package %s\n", pkg->name);
1413           // opkg_message(conf, OPKG_DEBUG2, "%s arch_priority=%d\n", pkg->architecture, arch_priority);
1414           pkg->arch_priority = arch_priority;
1415      }
1416
1417      for (i = 0; i < available_pkgs->len; i++) {
1418           pkg_t *pkg = available_pkgs->pkgs[i];
1419           if (!pkg->arch_priority && (pkg->state_flag || (pkg->state_want != SW_UNKNOWN))) {
1420                /* clear flags and want for any uninstallable package */
1421                opkg_message(conf, OPKG_DEBUG, "Clearing state_want and state_flag for pkg=%s (arch_priority=%d flag=%d want=%d)\n", 
1422                             pkg->name, pkg->arch_priority, pkg->state_flag, pkg->state_want);
1423                pkg->state_want = SW_UNKNOWN;
1424                pkg->state_flag = 0;
1425           }
1426      }
1427      pkg_vec_free(available_pkgs);
1428
1429      /* update the file owner data structure */
1430      opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: update file owner list\n");
1431      pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
1432      for (i = 0; i < installed_pkgs->len; i++) {
1433           pkg_t *pkg = installed_pkgs->pkgs[i];
1434           str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */
1435           str_list_elt_t *iter, *niter;
1436           if (installed_files == NULL) {
1437                opkg_message(conf, OPKG_ERROR, "No installed files for pkg %s\n", pkg->name);
1438                break;
1439           }
1440           for (iter = str_list_first(installed_files), niter = str_list_next(installed_files, iter); 
1441                   iter; 
1442                   iter = niter, niter = str_list_next(installed_files, iter)) {
1443                char *installed_file = (char *) iter->data;
1444                // opkg_message(conf, OPKG_DEBUG2, "pkg %s: file=%s\n", pkg->name, installed_file);
1445                file_hash_set_file_owner(conf, installed_file, pkg);
1446           }
1447           pkg_free_installed_files(pkg);
1448      }
1449      pkg_vec_free(installed_pkgs);
1450
1451      return 0;
1452 }
1453
1454 struct pkg_write_filelist_data {
1455      opkg_conf_t *conf;
1456      pkg_t *pkg;
1457      FILE *stream;
1458 };
1459
1460 void pkg_write_filelist_helper(const char *key, void *entry_, void *data_)
1461 {
1462      struct pkg_write_filelist_data *data = data_;
1463      pkg_t *entry = entry_;
1464      if (entry == data->pkg) {
1465           fprintf(data->stream, "%s\n", key);
1466      }
1467 }
1468
1469 int pkg_write_filelist(opkg_conf_t *conf, pkg_t *pkg)
1470 {
1471      struct pkg_write_filelist_data data;
1472      char *list_file_name = NULL;
1473      int err = 0;
1474
1475      if (!pkg) {
1476           opkg_message(conf, OPKG_ERROR, "Null pkg\n");
1477           return -EINVAL;
1478      }
1479      opkg_message(conf, OPKG_INFO,
1480                   "    creating %s.list file\n", pkg->name);
1481      sprintf_alloc(&list_file_name, "%s/%s.list", pkg->dest->info_dir, pkg->name);
1482      if (!list_file_name) {
1483           opkg_message(conf, OPKG_ERROR, "Failed to alloc list_file_name\n");
1484           return -ENOMEM;
1485      }
1486      opkg_message(conf, OPKG_INFO,
1487                   "    creating %s file for pkg %s\n", list_file_name, pkg->name);
1488      data.stream = fopen(list_file_name, "w");
1489      if (!data.stream) {
1490           opkg_message(conf, OPKG_ERROR, "Could not open %s for writing: %s\n",
1491                        list_file_name, strerror(errno));
1492                        return errno;
1493      }
1494      data.pkg = pkg;
1495      data.conf = conf;
1496      hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data);
1497      fclose(data.stream);
1498      free(list_file_name);
1499
1500      pkg->state_flag &= ~SF_FILELIST_CHANGED;
1501
1502      return err;
1503 }
1504
1505 int pkg_write_changed_filelists(opkg_conf_t *conf)
1506 {
1507      pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1508      hash_table_t *pkg_hash = &conf->pkg_hash;
1509      int i;
1510      int err;
1511      if (conf->noaction)
1512           return 0;
1513
1514      opkg_message(conf, OPKG_INFO, "%s: saving changed filelists\n", __FUNCTION__);
1515      pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
1516      for (i = 0; i < installed_pkgs->len; i++) {
1517           pkg_t *pkg = installed_pkgs->pkgs[i];
1518           if (pkg->state_flag & SF_FILELIST_CHANGED) {
1519                opkg_message(conf, OPKG_DEBUG, "Calling pkg_write_filelist for pkg=%s from %s\n", pkg->name, __FUNCTION__);
1520                err = pkg_write_filelist(conf, pkg);
1521                if (err)
1522                     opkg_message(conf, OPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
1523           }
1524      }
1525      pkg_vec_free (installed_pkgs);
1526      return 0;
1527 }