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