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