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