887b217d6f8d15c7b21f4454ca4583ce453c0180
[oweals/opkg-lede.git] / libopkg / 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 if (strcasecmp(field, "Auto-Installed") == 0) {
562                 /* Auto-Installed flag */
563                 if (pkg->auto_installed) {
564                     char * s = "Auto-Installed: yes\n";
565                     temp = (char *)realloc(temp, strlen(s) + 1);
566                     strcpy (temp, s);
567                 }
568           } else {
569                goto UNKNOWN_FMT_FIELD;
570           }
571           break;
572      case 'c':
573      case 'C':
574           if (strcasecmp(field, "Conffiles") == 0) {
575                /* Conffiles */
576                conffile_list_elt_t *iter;
577                char confstr[LINE_LEN];
578
579                if (pkg->conffiles.head == NULL) {
580                     return temp;
581                }
582
583                len = 14 ;
584                for (iter = pkg->conffiles.head; iter; iter = iter->next) {
585                     if (iter->data->name && iter->data->value) {
586                        len = len + (strlen(iter->data->name)+strlen(iter->data->value)+5);
587                     }
588                }
589                temp = (char *)realloc(temp,len);
590                if ( temp == NULL ){
591                   fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
592                   return NULL;
593                }
594                temp[0]='\0';
595                strncpy(temp, "Conffiles:\n", 12);
596                for (iter = pkg->conffiles.head; iter; iter = iter->next) {
597                     if (iter->data->name && iter->data->value) {
598                          snprintf(confstr, LINE_LEN, "%s %s\n", iter->data->name, iter->data->value);
599                          strncat(temp, confstr, strlen(confstr));           
600                     }
601                }
602           } else if (strcasecmp(field, "Conflicts") == 0) {
603                int i;
604
605                if (pkg->conflicts_count) {
606                     char conflictstr[LINE_LEN];
607                     len = 14 ;
608                     for(i = 0; i < pkg->conflicts_count; i++) {
609                         len = len + (strlen(pkg->conflicts_str[i])+5);
610                     }
611                     temp = (char *)realloc(temp,len);
612                     if ( temp == NULL ){
613                        fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
614                        return NULL;
615                     }
616                     temp[0]='\0';
617                     strncpy(temp, "Conflicts:", 11);
618                     for(i = 0; i < pkg->conflicts_count; i++) {
619                         snprintf(conflictstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->conflicts_str[i]);
620                         strncat(temp, conflictstr, strlen(conflictstr));           
621                     }
622                     strncat(temp, "\n", strlen("\n")); 
623                }
624           } else {
625                goto UNKNOWN_FMT_FIELD;
626           }
627           break;
628      case 'd':
629      case 'D':
630           if (strcasecmp(field, "Depends") == 0) {
631                /* Depends */
632                int i;
633
634                if (pkg->depends_count) {
635                     char depstr[LINE_LEN];
636                     len = 14 ;
637                     for(i = 0; i < pkg->depends_count; i++) {
638                         len = len + (strlen(pkg->depends_str[i])+4);
639                     }
640                     temp = (char *)realloc(temp,len);
641                     if ( temp == NULL ){
642                        fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
643                        return NULL;
644                     }
645                     temp[0]='\0';
646                     strncpy(temp, "Depends:", 10);
647                     for(i = 0; i < pkg->depends_count; i++) {
648                         snprintf(depstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->depends_str[i]);
649                         strncat(temp, depstr, strlen(depstr));           
650                     }
651                     strncat(temp, "\n", strlen("\n")); 
652                }
653           } else if (strcasecmp(field, "Description") == 0) {
654                /* Description */
655                if (pkg->description) {
656                    temp = (char *)realloc(temp,strlen(pkg->description)+16);
657                    if ( temp == NULL ){
658                       fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
659                       return NULL;
660                    }
661                    temp[0]='\0';
662                    snprintf(temp, (strlen(pkg->description)+16), "Description: %s\n", pkg->description);
663                }
664           } else {
665                goto UNKNOWN_FMT_FIELD;
666           }
667       break;
668      case 'e':
669      case 'E': {
670           /* Essential */
671           if (pkg->essential) {
672               temp = (char *)realloc(temp,16);
673               if ( temp == NULL ){
674                  fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
675                  return NULL;
676               }
677               temp[0]='\0';
678               snprintf(temp, (16), "Essential: yes\n");
679           }
680      }
681           break;
682      case 'f':
683      case 'F': {
684           /* Filename */
685           if (pkg->filename) {
686               temp = (char *)realloc(temp,strlen(pkg->filename)+12);
687               if ( temp == NULL ){
688                   fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
689                   return NULL;
690               }
691               temp[0]='\0';
692               snprintf(temp, (strlen(pkg->filename)+12), "Filename: %s\n", pkg->filename);
693           }
694      }
695           break;
696      case 'i':
697      case 'I': {
698           if (strcasecmp(field, "Installed-Size") == 0) {
699                /* Installed-Size */
700                temp = (char *)realloc(temp,strlen(pkg->installed_size)+17);
701                if ( temp == NULL ){
702                    fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
703                    return NULL;
704                }
705                temp[0]='\0';
706                snprintf(temp, (strlen(pkg->installed_size)+17), "Installed-Size: %s\n", pkg->installed_size);
707           } else if (strcasecmp(field, "Installed-Time") == 0 && pkg->installed_time) {
708                temp = (char *)realloc(temp,29);
709                if ( temp == NULL ){
710                   fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
711                   return NULL;
712                }
713                temp[0]='\0';
714                snprintf(temp, 29, "Installed-Time: %lu\n", pkg->installed_time);
715           }
716      }
717           break;
718      case 'm':
719      case 'M': {
720           /* Maintainer | MD5sum */
721           if (strcasecmp(field, "Maintainer") == 0) {
722                /* Maintainer */
723                if (pkg->maintainer) {
724                    temp = (char *)realloc(temp,strlen(pkg->maintainer)+14);
725                    if ( temp == NULL ){
726                       fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
727                       return NULL;
728                    }
729                    temp[0]='\0';
730                    snprintf(temp, (strlen(pkg->maintainer)+14), "maintainer: %s\n", pkg->maintainer);
731                }
732           } else if (strcasecmp(field, "MD5sum") == 0) {
733                /* MD5sum */
734                if (pkg->md5sum) {
735                    temp = (char *)realloc(temp,strlen(pkg->md5sum)+11);
736                    if ( temp == NULL ){
737                       fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
738                       return NULL;
739                    }
740                    temp[0]='\0';
741                    snprintf(temp, (strlen(pkg->md5sum)+11), "MD5Sum: %s\n", pkg->md5sum);
742                }
743           } else {
744                goto UNKNOWN_FMT_FIELD;
745           }
746      }
747           break;
748      case 'p':
749      case 'P': {
750           if (strcasecmp(field, "Package") == 0) {
751                /* Package */
752                temp = (char *)realloc(temp,strlen(pkg->name)+11);
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->name)+11), "Package: %s\n", pkg->name);
759           } else if (strcasecmp(field, "Priority") == 0) {
760                /* Priority */
761                temp = (char *)realloc(temp,strlen(pkg->priority)+12);
762                if ( temp == NULL ){
763                   fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
764                   return NULL;
765                }
766                temp[0]='\0';
767                snprintf(temp, (strlen(pkg->priority)+12), "Priority: %s\n", pkg->priority);
768           } else if (strcasecmp(field, "Provides") == 0) {
769                /* Provides */
770                int i;
771
772                if (pkg->provides_count) {
773                /* Here we check if the opkg_internal_use_only is used, and we discard it.*/
774                   for ( i=0; i < pkg->provides_count; i++ ){
775                       if (strstr(pkg->provides_str[i],"opkg_internal_use_only")!=NULL) {
776                          memset (pkg->provides_str[i],'\x0',strlen(pkg->provides_str[i])); /* Pigi clear my trick flag, just in case */
777                          flag_provide_false = 1;
778                       }
779                   }
780                   if ( !flag_provide_false ||                                             /* Pigi there is not my trick flag */
781                      ((flag_provide_false) &&  (pkg->provides_count > 1))){             /* Pigi There is, but we also have others Provides */
782                      char provstr[LINE_LEN];
783                      len = 15;
784                      for(i = 0; i < pkg->provides_count; i++) {
785                          len = len + (strlen(pkg->provides_str[i])+5);
786                      }
787                      temp = (char *)realloc(temp,len);
788                      if ( temp == NULL ){
789                         fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
790                         return NULL;
791                      }
792                      temp[0]='\0';
793                      strncpy(temp, "Provides:", 12);
794                      for(i = 0; i < pkg->provides_count; i++) {
795                          if (strlen(pkg->provides_str[i])>0){;
796                             snprintf(provstr, LINE_LEN, "%s %s", i == 1 ? "" : ",", pkg->provides_str[i]);
797                             strncat(temp, provstr, strlen(provstr));           
798                          }
799                      }
800                      strncat(temp, "\n", strlen("\n")); 
801                   }
802                }
803           } else {
804                goto UNKNOWN_FMT_FIELD;
805           }
806      }
807           break;
808      case 'r':
809      case 'R': {
810           int i;
811           /* Replaces | Recommends*/
812           if (strcasecmp (field, "Replaces") == 0) {
813                if (pkg->replaces_count) {
814                     char replstr[LINE_LEN];
815                     len = 14;
816                     for (i = 0; i < pkg->replaces_count; i++) {
817                         len = len + (strlen(pkg->replaces_str[i])+5);
818                     }
819                     temp = (char *)realloc(temp,len);
820                     if ( temp == NULL ){
821                        fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
822                        return NULL;
823                     }
824                     temp[0]='\0';
825                     strncpy(temp, "Replaces:", 12);
826                     for (i = 0; i < pkg->replaces_count; i++) {
827                         snprintf(replstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->replaces_str[i]);
828                         strncat(temp, replstr, strlen(replstr));           
829                     }
830                     strncat(temp, "\n", strlen("\n")); 
831                }
832           } else if (strcasecmp (field, "Recommends") == 0) {
833                if (pkg->recommends_count) {
834                     char recstr[LINE_LEN];
835                     len = 15;
836                     for(i = 0; i < pkg->recommends_count; i++) {
837                          len = len + (strlen( pkg->recommends_str[i])+5);
838                     }
839                     temp = (char *)realloc(temp,len);
840                    if ( temp == NULL ){
841                       fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
842                       return NULL;
843                    }
844                     temp[0]='\0';
845                     strncpy(temp, "Recommends:", 13);
846                     for(i = 0; i < pkg->recommends_count; i++) {
847                         snprintf(recstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->recommends_str[i]);
848                         strncat(temp, recstr, strlen(recstr));           
849                     }
850                     strncat(temp, "\n", strlen("\n")); 
851                }
852           } else {
853                goto UNKNOWN_FMT_FIELD;
854           }
855      }
856           break;
857      case 's':
858      case 'S': {
859           /* Section | Size | Source | Status | Suggests */
860           if (strcasecmp(field, "Section") == 0) {
861                /* Section */
862                if (pkg->section) {
863                    temp = (char *)realloc(temp,strlen(pkg->section)+11);
864                    if ( temp == NULL ){
865                       fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
866                       return NULL;
867                    }
868                    temp[0]='\0';
869                    snprintf(temp, (strlen(pkg->section)+11), "Section: %s\n", pkg->section);
870                }
871           } else if (strcasecmp(field, "Size") == 0) {
872                /* Size */
873                if (pkg->size) {
874                    temp = (char *)realloc(temp,strlen(pkg->size)+8);
875                    if ( temp == NULL ){
876                       fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
877                       return NULL;
878                    }
879                    temp[0]='\0';
880                    snprintf(temp, (strlen(pkg->size)+8), "Size: %s\n", pkg->size);
881                }
882           } else if (strcasecmp(field, "Source") == 0) {
883                /* Source */
884                if (pkg->source) {
885                    temp = (char *)realloc(temp,strlen(pkg->source)+10);
886                    if ( temp == NULL ){
887                       fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
888                       return NULL;
889                    }
890                    temp[0]='\0';
891                    snprintf(temp, (strlen(pkg->source)+10), "Source: %s\n", pkg->source);
892                }
893           } else if (strcasecmp(field, "Status") == 0) {
894                /* Status */
895                /* Benjamin Pineau note: we should avoid direct usage of 
896                 * strlen(arg) without keeping "arg" for later free()
897                 */
898                char *pflag=pkg_state_flag_to_str(pkg->state_flag);
899                char *pstat=pkg_state_status_to_str(pkg->state_status);
900                char *pwant=pkg_state_want_to_str(pkg->state_want);
901
902                size_t sum_of_sizes = (size_t) ( strlen(pwant)+ strlen(pflag)+ strlen(pstat) + 12 );
903                temp = (char *)realloc(temp,sum_of_sizes);
904                if ( temp == NULL ){
905                    fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
906                    return NULL;
907                 }
908                 temp[0]='\0';
909                 snprintf(temp, sum_of_sizes , "Status: %s %s %s\n", pwant, pflag, pstat);
910                 free(pflag);
911                 free(pwant);
912                if(pstat) /* pfstat can be NULL if ENOMEM */
913                    free(pstat);
914           } else if (strcasecmp(field, "Suggests") == 0) {
915                if (pkg->suggests_count) {
916                     int i;
917                     char sugstr[LINE_LEN];
918                     len = 13;
919                     for(i = 0; i < pkg->suggests_count; i++) {
920                         len = len + (strlen(pkg->suggests_str[i])+5);
921                     }
922                     temp = (char *)realloc(temp,len);
923                     if ( temp == NULL ){
924                        fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
925                        return NULL;
926                     }
927                     temp[0]='\0';
928                     strncpy(temp, "Suggests:", 10);
929                     for(i = 0; i < pkg->suggests_count; i++) {
930                         snprintf(sugstr, LINE_LEN, "%s %s", i == 0 ? "" : ",", pkg->suggests_str[i]);
931                         strncat(temp, sugstr, strlen(sugstr));           
932                     }
933                     strncat(temp, "\n", strlen("\n")); 
934                }
935           } else {
936                goto UNKNOWN_FMT_FIELD;
937           }
938      }
939           break;
940      case 'v':
941      case 'V': {
942           /* Version */
943           char *version = pkg_version_str_alloc(pkg);
944           temp = (char *)realloc(temp,strlen(version)+14);
945           if ( temp == NULL ){
946               fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
947               return NULL;
948           }
949           temp[0]='\0';
950           snprintf(temp, (strlen(version)+12), "Version: %s\n", version);
951           free(version);
952      }
953           break;
954      default:
955           goto UNKNOWN_FMT_FIELD;
956      }
957
958      if ( strlen(temp)<2 ) {
959           temp[0]='\0';
960      }
961      return temp;
962
963  UNKNOWN_FMT_FIELD:
964      fprintf(stderr, "%s: ERROR: Unknown field name: %s\n", __FUNCTION__, field);
965      if ( strlen(temp)<2 ) {
966           temp[0]='\0';
967      }
968
969      return temp;
970 }
971
972 void pkg_print_info(pkg_t *pkg, FILE *file)
973 {
974      char * buff;
975      if (pkg == NULL) {
976         return;
977      }
978
979      buff = pkg_formatted_info(pkg);
980      if ( buff == NULL ) 
981          return;
982      if (strlen(buff)>2){
983          fwrite(buff, 1, strlen(buff), file);
984      } 
985      free(buff);
986 }
987
988 void pkg_print_status(pkg_t * pkg, FILE * file)
989 {
990      if (pkg == NULL) {
991           return;
992      }
993
994      /* XXX: QUESTION: Do we actually want more fields here? The
995         original idea was to save space by installing only what was
996         needed for actual computation, (package, version, status,
997         essential, conffiles). The assumption is that all other fields
998         can be found in th available file.
999
1000         But, someone proposed the idea to make it possible to
1001         reconstruct a .ipk from an installed package, (ie. for beaming
1002         from one handheld to another). So, maybe we actually want a few
1003         more fields here, (depends, suggests, etc.), so that that would
1004         be guaranteed to work even in the absence of more information
1005         from the available file.
1006
1007         28-MAR-03: kergoth and I discussed this yesterday.  We think
1008         the essential info needs to be here for all installed packages
1009         because they may not appear in the Packages files on various
1010         feeds.  Furthermore, one should be able to install from URL or
1011         local storage without requiring a Packages file from any feed.
1012         -Jamey
1013      */
1014      pkg_print_field(pkg, file, "Package");
1015      pkg_print_field(pkg, file, "Version");
1016      pkg_print_field(pkg, file, "Depends");
1017      pkg_print_field(pkg, file, "Recommends");
1018      pkg_print_field(pkg, file, "Suggests");
1019      pkg_print_field(pkg, file, "Provides");
1020      pkg_print_field(pkg, file, "Replaces");
1021      pkg_print_field(pkg, file, "Conflicts");
1022      pkg_print_field(pkg, file, "Status");
1023      pkg_print_field(pkg, file, "Essential"); /* @@@@ should be removed in future release. */
1024      pkg_print_field(pkg, file, "Architecture");
1025      pkg_print_field(pkg, file, "Conffiles");
1026      pkg_print_field(pkg, file, "Installed-Time");
1027      pkg_print_field(pkg, file, "Auto-Installed");
1028      fputs("\n", file);
1029 }
1030
1031 void pkg_print_field(pkg_t *pkg, FILE *file, const char *field)
1032 {
1033      char *buff;
1034      if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) {
1035        fprintf(stderr, "%s: ERROR: Unknown field name: %s\n",
1036              __FUNCTION__, field);
1037      }
1038      buff = pkg_formatted_field(pkg, field);
1039      if (strlen(buff)>2) {
1040        fprintf(file, "%s", buff);
1041        fflush(file);
1042      }
1043      free(buff);
1044      return;
1045 }
1046
1047 /*
1048  * libdpkg - Debian packaging suite library routines
1049  * vercmp.c - comparison of version numbers
1050  *
1051  * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
1052  */
1053 int pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg)
1054 {
1055      int r;
1056
1057      if (pkg->epoch > ref_pkg->epoch) {
1058           return 1;
1059      }
1060
1061      if (pkg->epoch < ref_pkg->epoch) {
1062           return -1;
1063      }
1064
1065      r = verrevcmp(pkg->version, ref_pkg->version);
1066      if (r) {
1067           return r;
1068      }
1069
1070 #ifdef USE_DEBVERSION
1071      r = verrevcmp(pkg->revision, ref_pkg->revision);
1072      if (r) {
1073           return r;
1074      }
1075
1076      r = verrevcmp(pkg->familiar_revision, ref_pkg->familiar_revision);
1077 #endif
1078
1079      return r;
1080 }
1081
1082 /* assume ascii; warning: evaluates x multiple times! */
1083 #define order(x) ((x) == '~' ? -1 \
1084                 : isdigit((x)) ? 0 \
1085                 : !(x) ? 0 \
1086                 : isalpha((x)) ? (x) \
1087                 : (x) + 256)
1088
1089 static int verrevcmp(const char *val, const char *ref) {
1090   if (!val) val= "";
1091   if (!ref) ref= "";
1092
1093   while (*val || *ref) {
1094     int first_diff= 0;
1095
1096     while ( (*val && !isdigit(*val)) || (*ref && !isdigit(*ref)) ) {
1097       int vc= order(*val), rc= order(*ref);
1098       if (vc != rc) return vc - rc;
1099       val++; ref++;
1100     }
1101
1102     while ( *val == '0' ) val++;
1103     while ( *ref == '0' ) ref++;
1104     while (isdigit(*val) && isdigit(*ref)) {
1105       if (!first_diff) first_diff= *val - *ref;
1106       val++; ref++;
1107     }
1108     if (isdigit(*val)) return 1;
1109     if (isdigit(*ref)) return -1;
1110     if (first_diff) return first_diff;
1111   }
1112   return 0;
1113 }
1114
1115 int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op)
1116 {
1117      int r;
1118
1119      r = pkg_compare_versions(it, ref);
1120
1121      if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) {
1122           return r <= 0;
1123      }
1124
1125      if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) {
1126           return r >= 0;
1127      }
1128
1129      if (strcmp(op, "<<") == 0) {
1130           return r < 0;
1131      }
1132
1133      if (strcmp(op, ">>") == 0) {
1134           return r > 0;
1135      }
1136
1137      if (strcmp(op, "=") == 0) {
1138           return r == 0;
1139      }
1140
1141      fprintf(stderr, "unknown operator: %s", op);
1142      return 0;
1143 }
1144
1145 int pkg_name_version_and_architecture_compare(void *p1, void *p2)
1146 {
1147      const pkg_t *a = *(const pkg_t **)p1;
1148      const pkg_t *b = *(const pkg_t **)p2;
1149      int namecmp;
1150      int vercmp;
1151      if (!a->name || !b->name) {
1152        fprintf(stderr, "pkg_name_version_and_architecture_compare: a=%p a->name=%p b=%p b->name=%p\n",
1153                a, a->name, b, b->name);
1154        return 0;
1155      }
1156        
1157      namecmp = strcmp(a->name, b->name);
1158      if (namecmp)
1159           return namecmp;
1160      vercmp = pkg_compare_versions(a, b);
1161      if (vercmp)
1162           return vercmp;
1163      if (!a->arch_priority || !b->arch_priority) {
1164        fprintf(stderr, "pkg_name_version_and_architecture_compare: a=%p a->arch_priority=%i b=%p b->arch_priority=%i\n",
1165                a, a->arch_priority, b, b->arch_priority);
1166        return 0;
1167      }
1168      if (a->arch_priority > b->arch_priority)
1169           return 1;
1170      if (a->arch_priority < b->arch_priority)
1171           return -1;
1172      return 0;
1173 }
1174
1175 int abstract_pkg_name_compare(void *p1, void *p2)
1176 {
1177      const abstract_pkg_t *a = *(const abstract_pkg_t **)p1;
1178      const abstract_pkg_t *b = *(const abstract_pkg_t **)p2;
1179      if (!a->name || !b->name) {
1180        fprintf(stderr, "abstract_pkg_name_compare: a=%p a->name=%p b=%p b->name=%p\n",
1181                a, a->name, b, b->name);
1182        return 0;
1183      }
1184      return strcmp(a->name, b->name);
1185 }
1186
1187
1188 char *pkg_version_str_alloc(pkg_t *pkg)
1189 {
1190      char *complete_version;
1191      char *epoch_str;
1192 #ifdef USE_DEBVERSION
1193      char *revision_str;
1194      char *familiar_revision_str;
1195 #endif
1196
1197      if (pkg->epoch) {
1198           sprintf_alloc(&epoch_str, "%d:", pkg->epoch);
1199      } else {
1200           epoch_str = strdup("");
1201      }
1202
1203 #ifdef USE_DEBVERSION
1204      if (pkg->revision && strlen(pkg->revision)) {
1205           sprintf_alloc(&revision_str, "-%s", pkg->revision);
1206      } else {
1207           revision_str = strdup("");
1208      }
1209
1210      if (pkg->familiar_revision && strlen(pkg->familiar_revision)) {
1211           sprintf_alloc(&familiar_revision_str, "-fam%s", pkg->familiar_revision);
1212      } else {
1213           familiar_revision_str = strdup("");
1214      }
1215 #endif
1216
1217 #ifdef USE_DEBVERSION
1218      sprintf_alloc(&complete_version, "%s%s%s%s",
1219                    epoch_str, pkg->version, revision_str, familiar_revision_str);
1220 #else
1221      sprintf_alloc(&complete_version, "%s%s",
1222                    epoch_str, pkg->version);
1223 #endif
1224
1225      free(epoch_str);
1226 #ifdef USE_DEBVERSION
1227      free(revision_str);
1228      free(familiar_revision_str);
1229 #endif
1230
1231      return complete_version;
1232 }
1233
1234 str_list_t *pkg_get_installed_files(pkg_t *pkg)
1235 {
1236      int err;
1237      char *list_file_name = NULL;
1238      FILE *list_file = NULL;
1239      char *line;
1240      char *installed_file_name;
1241      int rootdirlen;
1242
1243      pkg->installed_files_ref_cnt++;
1244
1245      if (pkg->installed_files) {
1246           return pkg->installed_files;
1247      }
1248
1249      pkg->installed_files = str_list_alloc();
1250      if (pkg->installed_files == NULL) {
1251           fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
1252           return NULL;
1253      }
1254
1255      /* For uninstalled packages, get the file list firectly from the package.
1256         For installed packages, look at the package.list file in the database.
1257      */
1258      if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
1259           if (pkg->local_filename == NULL) {
1260                return pkg->installed_files;
1261           }
1262           /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary
1263              file. In other words, change deb_extract so that it can
1264              simply return the file list as a char *[] rather than
1265              insisting on writing in to a FILE * as it does now. */
1266           list_file = tmpfile();
1267           err = pkg_extract_data_file_names_to_stream(pkg, list_file);
1268           if (err) {
1269                fclose(list_file);
1270                fprintf(stderr, "%s: Error extracting file list from %s: %s\n",
1271                        __FUNCTION__, pkg->local_filename, strerror(err));
1272                return pkg->installed_files;
1273           }
1274           rewind(list_file);
1275      } else {
1276           sprintf_alloc(&list_file_name, "%s/%s.list",
1277                         pkg->dest->info_dir, pkg->name);
1278           if (! file_exists(list_file_name)) {
1279                free(list_file_name);
1280                return pkg->installed_files;
1281           }
1282
1283           list_file = fopen(list_file_name, "r");
1284           if (list_file == NULL) {
1285                fprintf(stderr, "WARNING: Cannot open %s: %s\n",
1286                        list_file_name, strerror(errno));
1287                free(list_file_name);
1288                return pkg->installed_files;
1289           }
1290           free(list_file_name);
1291      }
1292
1293      rootdirlen = strlen( pkg->dest->root_dir );
1294      while (1) {
1295           char *file_name;
1296         
1297           line = file_read_line_alloc(list_file);
1298           if (line == NULL) {
1299                break;
1300           }
1301           str_chomp(line);
1302           file_name = line;
1303
1304           /* Take pains to avoid uglies like "/./" in the middle of file_name. */
1305           if( strncmp( pkg->dest->root_dir, 
1306                        file_name, 
1307                        rootdirlen ) ) {
1308                if (*file_name == '.') {
1309                     file_name++;
1310                }
1311                if (*file_name == '/') {
1312                     file_name++;
1313                }
1314
1315                /* Freed in pkg_free_installed_files */
1316                sprintf_alloc(&installed_file_name, "%s%s", pkg->dest->root_dir, file_name);
1317           } else {
1318                // already contains root_dir as header -> ABSOLUTE
1319                sprintf_alloc(&installed_file_name, "%s", file_name);
1320           }
1321           str_list_append(pkg->installed_files, installed_file_name);
1322           free(line);
1323      }
1324
1325      fclose(list_file);
1326
1327      return pkg->installed_files;
1328 }
1329
1330 /* XXX: CLEANUP: This function and it's counterpart,
1331    (pkg_get_installed_files), do not match our init/deinit naming
1332    convention. Nor the alloc/free convention. But, then again, neither
1333    of these conventions currrently fit the way these two functions
1334    work. */
1335 int pkg_free_installed_files(pkg_t *pkg)
1336 {
1337      str_list_elt_t *iter;
1338
1339      pkg->installed_files_ref_cnt--;
1340      if (pkg->installed_files_ref_cnt > 0) {
1341           return 0;
1342      }
1343
1344      if (pkg->installed_files) {
1345
1346           for (iter = pkg->installed_files->head; iter; iter = iter->next) {
1347                /* malloced in pkg_get_installed_files */
1348                free (iter->data);
1349                iter->data = NULL;
1350           }
1351
1352           str_list_deinit(pkg->installed_files);
1353      }
1354
1355      pkg->installed_files = NULL;
1356
1357      return 0;
1358 }
1359
1360 int pkg_remove_installed_files_list(opkg_conf_t *conf, pkg_t *pkg)
1361 {
1362      int err;
1363      char *list_file_name;
1364
1365      //I don't think pkg_free_installed_files should be called here. Jamey
1366      //pkg_free_installed_files(pkg);
1367
1368      sprintf_alloc(&list_file_name, "%s/%s.list",
1369                    pkg->dest->info_dir, pkg->name);
1370      if (!conf->noaction) {
1371           err = unlink(list_file_name);
1372           free(list_file_name);
1373
1374           if (err) {
1375                return errno;
1376           }
1377      }
1378      return 0;
1379 }
1380
1381 conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name)
1382 {
1383      conffile_list_elt_t *iter;
1384      conffile_t *conffile;
1385
1386      if (pkg == NULL) {
1387           return NULL;
1388      }
1389
1390      for (iter = pkg->conffiles.head; iter; iter = iter->next) {
1391           conffile = iter->data;
1392
1393           if (strcmp(conffile->name, file_name) == 0) {
1394                return conffile;
1395           }
1396      }
1397
1398      return NULL;
1399 }
1400
1401 int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
1402                    const char *script, const char *args)
1403 {
1404      int err;
1405      char *path;
1406      char *cmd;
1407
1408      /* XXX: FEATURE: When conf->offline_root is set, we should run the
1409         maintainer script within a chroot environment. */
1410
1411      /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages
1412         have scripts in pkg->tmp_unpack_dir. */
1413      if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) {
1414           if (pkg->dest == NULL) {
1415                fprintf(stderr, "%s: ERROR: installed package %s has a NULL dest\n",
1416                        __FUNCTION__, pkg->name);
1417                return EINVAL;
1418           }
1419           sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script);
1420      } else {
1421           if (pkg->tmp_unpack_dir == NULL) {
1422                fprintf(stderr, "%s: ERROR: uninstalled package %s has a NULL tmp_unpack_dir\n",
1423                        __FUNCTION__, pkg->name);
1424                return EINVAL;
1425           }
1426           sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script);
1427      }
1428
1429      opkg_message(conf, OPKG_INFO, "Running script %s\n", path);
1430      if (conf->noaction) return 0;
1431
1432      /* XXX: CLEANUP: There must be a better way to handle maintainer
1433         scripts when running with offline_root mode and/or a dest other
1434         than '/'. I've been playing around with some clever chroot
1435         tricks and I might come up with something workable. */
1436      if (conf->offline_root) {
1437           setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
1438      }
1439
1440      setenv("PKG_ROOT",
1441             pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
1442
1443      if (! file_exists(path)) {
1444           free(path);
1445           return 0;
1446      }
1447
1448      if (conf->offline_root) {
1449           fprintf(stderr, "(offline root mode: not running %s.%s)\n", pkg->name, script);
1450           free(path);
1451           return 0;
1452      }
1453
1454      sprintf_alloc(&cmd, "%s %s", path, args);
1455      free(path);
1456
1457      err = xsystem(cmd);
1458      free(cmd);
1459
1460      if (err) {
1461           fprintf(stderr, "%s script returned status %d\n", script, err);
1462           return err;
1463      }
1464
1465      return 0;
1466 }
1467
1468 char *pkg_state_want_to_str(pkg_state_want_t sw)
1469 {
1470      int i;
1471
1472      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
1473           if (pkg_state_want_map[i].value == sw) {
1474                return strdup(pkg_state_want_map[i].str);
1475           }
1476      }
1477
1478      fprintf(stderr, "%s: ERROR: Illegal value for state_want: %d\n",
1479              __FUNCTION__, sw);
1480      return strdup("<STATE_WANT_UNKNOWN>");
1481 }
1482
1483 pkg_state_want_t pkg_state_want_from_str(char *str)
1484 {
1485      int i;
1486
1487      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
1488           if (strcmp(str, pkg_state_want_map[i].str) == 0) {
1489                return pkg_state_want_map[i].value;
1490           }
1491      }
1492
1493      fprintf(stderr, "%s: ERROR: Illegal value for state_want string: %s\n",
1494              __FUNCTION__, str);
1495      return SW_UNKNOWN;
1496 }
1497
1498 char *pkg_state_flag_to_str(pkg_state_flag_t sf)
1499 {
1500      int i;
1501      int len = 3; /* ok\000 is minimum */
1502      char *str = NULL;
1503
1504      /* clear the temporary flags before converting to string */
1505      sf &= SF_NONVOLATILE_FLAGS;
1506
1507      if (sf == 0) {
1508           return strdup("ok");
1509      } else {
1510
1511           for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1512                if (sf & pkg_state_flag_map[i].value) {
1513                     len += strlen(pkg_state_flag_map[i].str) + 1;
1514                }
1515           }
1516           str = malloc(len);
1517           if ( str == NULL ) {
1518               fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
1519               return NULL;
1520           }
1521           str[0] = 0;
1522           for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1523                if (sf & pkg_state_flag_map[i].value) {
1524                     strcat(str, pkg_state_flag_map[i].str);
1525                     strcat(str, ",");
1526                }
1527           }
1528           len = strlen(str);
1529           str[len-1] = 0; /* squash last comma */
1530           return str;
1531      }
1532 }
1533
1534 pkg_state_flag_t pkg_state_flag_from_str(const char *str)
1535 {
1536      int i;
1537      int sf = SF_OK;
1538
1539      if (strcmp(str, "ok") == 0) {
1540           return SF_OK;
1541      }
1542      for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1543           const char *sfname = pkg_state_flag_map[i].str;
1544           int sfname_len = strlen(sfname);
1545           if (strncmp(str, sfname, sfname_len) == 0) {
1546                sf |= pkg_state_flag_map[i].value;
1547                str += sfname_len;
1548                if (str[0] == ',') {
1549                     str++;
1550                } else {
1551                     break;
1552                }
1553           }
1554      }
1555
1556      return sf;
1557 }
1558
1559 char *pkg_state_status_to_str(pkg_state_status_t ss)
1560 {
1561      int i;
1562
1563      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
1564           if (pkg_state_status_map[i].value == ss) {
1565                return strdup(pkg_state_status_map[i].str);
1566           }
1567      }
1568
1569      fprintf(stderr, "%s: ERROR: Illegal value for state_status: %d\n",
1570              __FUNCTION__, ss);
1571      return strdup("<STATE_STATUS_UNKNOWN>");
1572 }
1573
1574 pkg_state_status_t pkg_state_status_from_str(const char *str)
1575 {
1576      int i;
1577
1578      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
1579           if (strcmp(str, pkg_state_status_map[i].str) == 0) {
1580                return pkg_state_status_map[i].value;
1581           }
1582      }
1583
1584      fprintf(stderr, "%s: ERROR: Illegal value for state_status string: %s\n",
1585              __FUNCTION__, str);
1586      return SS_NOT_INSTALLED;
1587 }
1588
1589 int pkg_arch_supported(opkg_conf_t *conf, pkg_t *pkg)
1590 {
1591      nv_pair_list_elt_t *l;
1592
1593      if (!pkg->architecture)
1594           return 1;
1595
1596      l = conf->arch_list.head;
1597
1598      while (l) {
1599           nv_pair_t *nv = l->data;
1600           if (strcmp(nv->name, pkg->architecture) == 0) {
1601                opkg_message(conf, OPKG_DEBUG, "arch %s (priority %s) supported for pkg %s\n", nv->name, nv->value, pkg->name);
1602                return 1;
1603           }
1604           l = l->next;
1605      }
1606
1607      opkg_message(conf, OPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
1608      return 0;
1609 }
1610
1611 int pkg_get_arch_priority(opkg_conf_t *conf, const char *archname)
1612 {
1613      nv_pair_list_elt_t *l;
1614
1615      l = conf->arch_list.head;
1616
1617      while (l) {
1618           nv_pair_t *nv = l->data;
1619           if (strcmp(nv->name, archname) == 0) {
1620                int priority = strtol(nv->value, NULL, 0);
1621                return priority;
1622           }
1623           l = l->next;
1624      }
1625      return 0;
1626 }
1627
1628 int pkg_info_preinstall_check(opkg_conf_t *conf)
1629 {
1630      int i;
1631      hash_table_t *pkg_hash = &conf->pkg_hash;
1632      pkg_vec_t *available_pkgs = pkg_vec_alloc();
1633      pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1634
1635      opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: updating arch priority for each package\n");
1636      pkg_hash_fetch_available(pkg_hash, available_pkgs);
1637      /* update arch_priority for each package */
1638      for (i = 0; i < available_pkgs->len; i++) {
1639           pkg_t *pkg = available_pkgs->pkgs[i];
1640           int arch_priority = 1;
1641           if (!pkg)
1642                continue;
1643           // opkg_message(conf, OPKG_DEBUG2, " package %s version=%s arch=%p:", pkg->name, pkg->version, pkg->architecture);
1644           if (pkg->architecture) 
1645                arch_priority = pkg_get_arch_priority(conf, pkg->architecture);
1646           else 
1647                opkg_message(conf, OPKG_ERROR, "pkg_info_preinstall_check: no architecture for package %s\n", pkg->name);
1648           // opkg_message(conf, OPKG_DEBUG2, "%s arch_priority=%d\n", pkg->architecture, arch_priority);
1649           pkg->arch_priority = arch_priority;
1650      }
1651
1652      for (i = 0; i < available_pkgs->len; i++) {
1653           pkg_t *pkg = available_pkgs->pkgs[i];
1654           if (!pkg->arch_priority && (pkg->state_flag || (pkg->state_want != SW_UNKNOWN))) {
1655                /* clear flags and want for any uninstallable package */
1656                opkg_message(conf, OPKG_NOTICE, "Clearing state_want and state_flag for pkg=%s (arch_priority=%d flag=%d want=%d)\n", 
1657                             pkg->name, pkg->arch_priority, pkg->state_flag, pkg->state_want);
1658                pkg->state_want = SW_UNKNOWN;
1659                pkg->state_flag = 0;
1660           }
1661      }
1662      pkg_vec_free(available_pkgs);
1663
1664      /* update the file owner data structure */
1665      opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: update file owner list\n");
1666      pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
1667      for (i = 0; i < installed_pkgs->len; i++) {
1668           pkg_t *pkg = installed_pkgs->pkgs[i];
1669           str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */
1670           str_list_elt_t *iter;
1671           if (installed_files == NULL) {
1672                opkg_message(conf, OPKG_ERROR, "No installed files for pkg %s\n", pkg->name);
1673                break;
1674           }
1675           for (iter = installed_files->head; iter; iter = iter->next) {
1676                char *installed_file = iter->data;
1677                // opkg_message(conf, OPKG_DEBUG2, "pkg %s: file=%s\n", pkg->name, installed_file);
1678                file_hash_set_file_owner(conf, installed_file, pkg);
1679           }
1680      }
1681      pkg_vec_free(installed_pkgs);
1682
1683      return 0;
1684 }
1685
1686 struct pkg_write_filelist_data {
1687      opkg_conf_t *conf;
1688      pkg_t *pkg;
1689      FILE *stream;
1690 };
1691
1692 void pkg_write_filelist_helper(const char *key, void *entry_, void *data_)
1693 {
1694      struct pkg_write_filelist_data *data = data_;
1695      pkg_t *entry = entry_;
1696      if (entry == data->pkg) {
1697           fprintf(data->stream, "%s\n", key);
1698      }
1699 }
1700
1701 int pkg_write_filelist(opkg_conf_t *conf, pkg_t *pkg)
1702 {
1703      struct pkg_write_filelist_data data;
1704      char *list_file_name = NULL;
1705      int err = 0;
1706
1707      if (!pkg) {
1708           opkg_message(conf, OPKG_ERROR, "Null pkg\n");
1709           return -EINVAL;
1710      }
1711      opkg_message(conf, OPKG_INFO,
1712                   "    creating %s.list file\n", pkg->name);
1713      sprintf_alloc(&list_file_name, "%s/%s.list", pkg->dest->info_dir, pkg->name);
1714      if (!list_file_name) {
1715           opkg_message(conf, OPKG_ERROR, "Failed to alloc list_file_name\n");
1716           return -ENOMEM;
1717      }
1718      opkg_message(conf, OPKG_INFO,
1719                   "    creating %s file for pkg %s\n", list_file_name, pkg->name);
1720      data.stream = fopen(list_file_name, "w");
1721      if (!data.stream) {
1722           opkg_message(conf, OPKG_ERROR, "Could not open %s for writing: %s\n",
1723                        list_file_name, strerror(errno));
1724                        return errno;
1725      }
1726      data.pkg = pkg;
1727      data.conf = conf;
1728      hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data);
1729      fclose(data.stream);
1730      free(list_file_name);
1731
1732      return err;
1733 }
1734
1735 int pkg_write_changed_filelists(opkg_conf_t *conf)
1736 {
1737      pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1738      hash_table_t *pkg_hash = &conf->pkg_hash;
1739      int i;
1740      int err;
1741      if (conf->noaction)
1742           return 0;
1743
1744      opkg_message(conf, OPKG_INFO, "%s: saving changed filelists\n", __FUNCTION__);
1745      pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
1746      for (i = 0; i < installed_pkgs->len; i++) {
1747           pkg_t *pkg = installed_pkgs->pkgs[i];
1748           if (pkg->state_flag & SF_FILELIST_CHANGED) {
1749                opkg_message(conf, OPKG_DEBUG, "Calling pkg_write_filelist for pkg=%s from %s\n", pkg->name, __FUNCTION__);
1750                err = pkg_write_filelist(conf, pkg);
1751                if (err)
1752                     opkg_message(conf, OPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
1753           }
1754      }
1755      return 0;
1756 }