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