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