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