opkg: include opkg_state.h in libopkg_include_HEADERS
[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 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 int verrevcmp(const char *val, const char *ref)
1083 {
1084      int vc, rc;
1085      long vl, rl;
1086      const char *vp, *rp;
1087      const char *vsep, *rsep;
1088     
1089      if (!val) val= "";
1090      if (!ref) ref= "";
1091      for (;;) {
1092           vp= val;  while (*vp && !isdigit(*vp)) vp++;
1093           rp= ref;  while (*rp && !isdigit(*rp)) rp++;
1094           for (;;) {
1095                vc= (val == vp) ? 0 : *val++;
1096                rc= (ref == rp) ? 0 : *ref++;
1097                if (!rc && !vc) break;
1098                if (vc && !isalpha(vc)) vc += 256; /* assumes ASCII character set */
1099                if (rc && !isalpha(rc)) rc += 256;
1100                if (vc != rc) return vc - rc;
1101           }
1102           val= vp;
1103           ref= rp;
1104           vl=0;  if (isdigit(*vp)) vl= strtol(val,(char**)&val,10);
1105           rl=0;  if (isdigit(*rp)) rl= strtol(ref,(char**)&ref,10);
1106           if (vl != rl) return vl - rl;
1107
1108           vc = *val;
1109           rc = *ref;
1110           vsep = strchr(".-", vc);
1111           rsep = strchr(".-", rc);
1112           if (vsep && !rsep) return -1;
1113           if (!vsep && rsep) return +1;
1114
1115           if (!*val && !*ref) return 0;
1116           if (!*val) return -1;
1117           if (!*ref) return +1;
1118      }
1119 }
1120
1121 int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op)
1122 {
1123      int r;
1124
1125      r = pkg_compare_versions(it, ref);
1126
1127      if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) {
1128           return r <= 0;
1129      }
1130
1131      if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) {
1132           return r >= 0;
1133      }
1134
1135      if (strcmp(op, "<<") == 0) {
1136           return r < 0;
1137      }
1138
1139      if (strcmp(op, ">>") == 0) {
1140           return r > 0;
1141      }
1142
1143      if (strcmp(op, "=") == 0) {
1144           return r == 0;
1145      }
1146
1147      fprintf(stderr, "unknown operator: %s", op);
1148      return 0;
1149 }
1150
1151 int pkg_name_version_and_architecture_compare(void *p1, void *p2)
1152 {
1153      const pkg_t *a = *(const pkg_t **)p1;
1154      const pkg_t *b = *(const pkg_t **)p2;
1155      int namecmp;
1156      int vercmp;
1157      if (!a->name || !b->name) {
1158        fprintf(stderr, "pkg_name_version_and_architecture_compare: a=%p a->name=%p b=%p b->name=%p\n",
1159                a, a->name, b, b->name);
1160        return 0;
1161      }
1162        
1163      namecmp = strcmp(a->name, b->name);
1164      if (namecmp)
1165           return namecmp;
1166      vercmp = pkg_compare_versions(a, b);
1167      if (vercmp)
1168           return vercmp;
1169      if (!a->arch_priority || !b->arch_priority) {
1170        fprintf(stderr, "pkg_name_version_and_architecture_compare: a=%p a->arch_priority=%i b=%p b->arch_priority=%i\n",
1171                a, a->arch_priority, b, b->arch_priority);
1172        return 0;
1173      }
1174      if (a->arch_priority > b->arch_priority)
1175           return 1;
1176      if (a->arch_priority < b->arch_priority)
1177           return -1;
1178      return 0;
1179 }
1180
1181 int abstract_pkg_name_compare(void *p1, void *p2)
1182 {
1183      const abstract_pkg_t *a = *(const abstract_pkg_t **)p1;
1184      const abstract_pkg_t *b = *(const abstract_pkg_t **)p2;
1185      if (!a->name || !b->name) {
1186        fprintf(stderr, "abstract_pkg_name_compare: a=%p a->name=%p b=%p b->name=%p\n",
1187                a, a->name, b, b->name);
1188        return 0;
1189      }
1190      return strcmp(a->name, b->name);
1191 }
1192
1193
1194 char *pkg_version_str_alloc(pkg_t *pkg)
1195 {
1196      char *complete_version;
1197      char *epoch_str;
1198 #ifdef USE_DEBVERSION
1199      char *revision_str;
1200      char *familiar_revision_str;
1201 #endif
1202
1203      if (pkg->epoch) {
1204           sprintf_alloc(&epoch_str, "%d:", pkg->epoch);
1205      } else {
1206           epoch_str = strdup("");
1207      }
1208
1209 #ifdef USE_DEBVERSION
1210      if (pkg->revision && strlen(pkg->revision)) {
1211           sprintf_alloc(&revision_str, "-%s", pkg->revision);
1212      } else {
1213           revision_str = strdup("");
1214      }
1215
1216      if (pkg->familiar_revision && strlen(pkg->familiar_revision)) {
1217           sprintf_alloc(&familiar_revision_str, "-fam%s", pkg->familiar_revision);
1218      } else {
1219           familiar_revision_str = strdup("");
1220      }
1221 #endif
1222
1223 #ifdef USE_DEBVERSION
1224      sprintf_alloc(&complete_version, "%s%s%s%s",
1225                    epoch_str, pkg->version, revision_str, familiar_revision_str);
1226 #else
1227      sprintf_alloc(&complete_version, "%s%s",
1228                    epoch_str, pkg->version);
1229 #endif
1230
1231      free(epoch_str);
1232 #ifdef USE_DEBVERSION
1233      free(revision_str);
1234      free(familiar_revision_str);
1235 #endif
1236
1237      return complete_version;
1238 }
1239
1240 str_list_t *pkg_get_installed_files(pkg_t *pkg)
1241 {
1242      int err;
1243      char *list_file_name = NULL;
1244      FILE *list_file = NULL;
1245      char *line;
1246      char *installed_file_name;
1247      int rootdirlen;
1248
1249      pkg->installed_files_ref_cnt++;
1250
1251      if (pkg->installed_files) {
1252           return pkg->installed_files;
1253      }
1254
1255      pkg->installed_files = str_list_alloc();
1256      if (pkg->installed_files == NULL) {
1257           fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
1258           return NULL;
1259      }
1260
1261      /* For uninstalled packages, get the file list firectly from the package.
1262         For installed packages, look at the package.list file in the database.
1263      */
1264      if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) {
1265           if (pkg->local_filename == NULL) {
1266                return pkg->installed_files;
1267           }
1268           /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary
1269              file. In other words, change deb_extract so that it can
1270              simply return the file list as a char *[] rather than
1271              insisting on writing in to a FILE * as it does now. */
1272           list_file = tmpfile();
1273           err = pkg_extract_data_file_names_to_stream(pkg, list_file);
1274           if (err) {
1275                fclose(list_file);
1276                fprintf(stderr, "%s: Error extracting file list from %s: %s\n",
1277                        __FUNCTION__, pkg->local_filename, strerror(err));
1278                return pkg->installed_files;
1279           }
1280           rewind(list_file);
1281      } else {
1282           sprintf_alloc(&list_file_name, "%s/%s.list",
1283                         pkg->dest->info_dir, pkg->name);
1284           if (! file_exists(list_file_name)) {
1285                free(list_file_name);
1286                return pkg->installed_files;
1287           }
1288
1289           list_file = fopen(list_file_name, "r");
1290           if (list_file == NULL) {
1291                fprintf(stderr, "WARNING: Cannot open %s: %s\n",
1292                        list_file_name, strerror(errno));
1293                free(list_file_name);
1294                return pkg->installed_files;
1295           }
1296           free(list_file_name);
1297      }
1298
1299      rootdirlen = strlen( pkg->dest->root_dir );
1300      while (1) {
1301           char *file_name;
1302         
1303           line = file_read_line_alloc(list_file);
1304           if (line == NULL) {
1305                break;
1306           }
1307           str_chomp(line);
1308           file_name = line;
1309
1310           /* Take pains to avoid uglies like "/./" in the middle of file_name. */
1311           if( strncmp( pkg->dest->root_dir, 
1312                        file_name, 
1313                        rootdirlen ) ) {
1314                if (*file_name == '.') {
1315                     file_name++;
1316                }
1317                if (*file_name == '/') {
1318                     file_name++;
1319                }
1320
1321                /* Freed in pkg_free_installed_files */
1322                sprintf_alloc(&installed_file_name, "%s%s", pkg->dest->root_dir, file_name);
1323           } else {
1324                // already contains root_dir as header -> ABSOLUTE
1325                sprintf_alloc(&installed_file_name, "%s", file_name);
1326           }
1327           str_list_append(pkg->installed_files, installed_file_name);
1328           free(line);
1329      }
1330
1331      fclose(list_file);
1332
1333      return pkg->installed_files;
1334 }
1335
1336 /* XXX: CLEANUP: This function and it's counterpart,
1337    (pkg_get_installed_files), do not match our init/deinit naming
1338    convention. Nor the alloc/free convention. But, then again, neither
1339    of these conventions currrently fit the way these two functions
1340    work. */
1341 int pkg_free_installed_files(pkg_t *pkg)
1342 {
1343      str_list_elt_t *iter;
1344
1345      pkg->installed_files_ref_cnt--;
1346      if (pkg->installed_files_ref_cnt > 0) {
1347           return 0;
1348      }
1349
1350      if (pkg->installed_files) {
1351
1352           for (iter = pkg->installed_files->head; iter; iter = iter->next) {
1353                /* malloced in pkg_get_installed_files */
1354                free (iter->data);
1355                iter->data = NULL;
1356           }
1357
1358           str_list_deinit(pkg->installed_files);
1359      }
1360
1361      pkg->installed_files = NULL;
1362
1363      return 0;
1364 }
1365
1366 int pkg_remove_installed_files_list(opkg_conf_t *conf, pkg_t *pkg)
1367 {
1368      int err;
1369      char *list_file_name;
1370
1371      //I don't think pkg_free_installed_files should be called here. Jamey
1372      //pkg_free_installed_files(pkg);
1373
1374      sprintf_alloc(&list_file_name, "%s/%s.list",
1375                    pkg->dest->info_dir, pkg->name);
1376      if (!conf->noaction) {
1377           err = unlink(list_file_name);
1378           free(list_file_name);
1379
1380           if (err) {
1381                return errno;
1382           }
1383      }
1384      return 0;
1385 }
1386
1387 conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name)
1388 {
1389      conffile_list_elt_t *iter;
1390      conffile_t *conffile;
1391
1392      if (pkg == NULL) {
1393           return NULL;
1394      }
1395
1396      for (iter = pkg->conffiles.head; iter; iter = iter->next) {
1397           conffile = iter->data;
1398
1399           if (strcmp(conffile->name, file_name) == 0) {
1400                return conffile;
1401           }
1402      }
1403
1404      return NULL;
1405 }
1406
1407 int pkg_run_script(opkg_conf_t *conf, pkg_t *pkg,
1408                    const char *script, const char *args)
1409 {
1410      int err;
1411      char *path;
1412      char *cmd;
1413
1414      /* XXX: FEATURE: When conf->offline_root is set, we should run the
1415         maintainer script within a chroot environment. */
1416
1417      /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages
1418         have scripts in pkg->tmp_unpack_dir. */
1419      if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) {
1420           if (pkg->dest == NULL) {
1421                fprintf(stderr, "%s: ERROR: installed package %s has a NULL dest\n",
1422                        __FUNCTION__, pkg->name);
1423                return EINVAL;
1424           }
1425           sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script);
1426      } else {
1427           if (pkg->tmp_unpack_dir == NULL) {
1428                fprintf(stderr, "%s: ERROR: uninstalled package %s has a NULL tmp_unpack_dir\n",
1429                        __FUNCTION__, pkg->name);
1430                return EINVAL;
1431           }
1432           sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script);
1433      }
1434
1435      opkg_message(conf, OPKG_INFO, "Running script %s\n", path);
1436      if (conf->noaction) return 0;
1437
1438      /* XXX: CLEANUP: There must be a better way to handle maintainer
1439         scripts when running with offline_root mode and/or a dest other
1440         than '/'. I've been playing around with some clever chroot
1441         tricks and I might come up with something workable. */
1442      if (conf->offline_root) {
1443           setenv("OPKG_OFFLINE_ROOT", conf->offline_root, 1);
1444      }
1445
1446      setenv("PKG_ROOT",
1447             pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1);
1448
1449      if (! file_exists(path)) {
1450           free(path);
1451           return 0;
1452      }
1453
1454      if (conf->offline_root) {
1455           fprintf(stderr, "(offline root mode: not running %s.%s)\n", pkg->name, script);
1456           free(path);
1457           return 0;
1458      }
1459
1460      sprintf_alloc(&cmd, "%s %s", path, args);
1461      free(path);
1462
1463      err = xsystem(cmd);
1464      free(cmd);
1465
1466      if (err) {
1467           fprintf(stderr, "%s script returned status %d\n", script, err);
1468           return err;
1469      }
1470
1471      return 0;
1472 }
1473
1474 char *pkg_state_want_to_str(pkg_state_want_t sw)
1475 {
1476      int i;
1477
1478      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
1479           if (pkg_state_want_map[i].value == sw) {
1480                return strdup(pkg_state_want_map[i].str);
1481           }
1482      }
1483
1484      fprintf(stderr, "%s: ERROR: Illegal value for state_want: %d\n",
1485              __FUNCTION__, sw);
1486      return strdup("<STATE_WANT_UNKNOWN>");
1487 }
1488
1489 pkg_state_want_t pkg_state_want_from_str(char *str)
1490 {
1491      int i;
1492
1493      for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) {
1494           if (strcmp(str, pkg_state_want_map[i].str) == 0) {
1495                return pkg_state_want_map[i].value;
1496           }
1497      }
1498
1499      fprintf(stderr, "%s: ERROR: Illegal value for state_want string: %s\n",
1500              __FUNCTION__, str);
1501      return SW_UNKNOWN;
1502 }
1503
1504 char *pkg_state_flag_to_str(pkg_state_flag_t sf)
1505 {
1506      int i;
1507      int len = 3; /* ok\000 is minimum */
1508      char *str = NULL;
1509
1510      /* clear the temporary flags before converting to string */
1511      sf &= SF_NONVOLATILE_FLAGS;
1512
1513      if (sf == 0) {
1514           return strdup("ok");
1515      } else {
1516
1517           for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1518                if (sf & pkg_state_flag_map[i].value) {
1519                     len += strlen(pkg_state_flag_map[i].str) + 1;
1520                }
1521           }
1522           str = malloc(len);
1523           if ( str == NULL ) {
1524               fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
1525               return NULL;
1526           }
1527           str[0] = 0;
1528           for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1529                if (sf & pkg_state_flag_map[i].value) {
1530                     strcat(str, pkg_state_flag_map[i].str);
1531                     strcat(str, ",");
1532                }
1533           }
1534           len = strlen(str);
1535           str[len-1] = 0; /* squash last comma */
1536           return str;
1537      }
1538 }
1539
1540 pkg_state_flag_t pkg_state_flag_from_str(const char *str)
1541 {
1542      int i;
1543      int sf = SF_OK;
1544
1545      if (strcmp(str, "ok") == 0) {
1546           return SF_OK;
1547      }
1548      for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) {
1549           const char *sfname = pkg_state_flag_map[i].str;
1550           int sfname_len = strlen(sfname);
1551           if (strncmp(str, sfname, sfname_len) == 0) {
1552                sf |= pkg_state_flag_map[i].value;
1553                str += sfname_len;
1554                if (str[0] == ',') {
1555                     str++;
1556                } else {
1557                     break;
1558                }
1559           }
1560      }
1561
1562      return sf;
1563 }
1564
1565 char *pkg_state_status_to_str(pkg_state_status_t ss)
1566 {
1567      int i;
1568
1569      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
1570           if (pkg_state_status_map[i].value == ss) {
1571                return strdup(pkg_state_status_map[i].str);
1572           }
1573      }
1574
1575      fprintf(stderr, "%s: ERROR: Illegal value for state_status: %d\n",
1576              __FUNCTION__, ss);
1577      return strdup("<STATE_STATUS_UNKNOWN>");
1578 }
1579
1580 pkg_state_status_t pkg_state_status_from_str(const char *str)
1581 {
1582      int i;
1583
1584      for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) {
1585           if (strcmp(str, pkg_state_status_map[i].str) == 0) {
1586                return pkg_state_status_map[i].value;
1587           }
1588      }
1589
1590      fprintf(stderr, "%s: ERROR: Illegal value for state_status string: %s\n",
1591              __FUNCTION__, str);
1592      return SS_NOT_INSTALLED;
1593 }
1594
1595 int pkg_arch_supported(opkg_conf_t *conf, pkg_t *pkg)
1596 {
1597      nv_pair_list_elt_t *l;
1598
1599      if (!pkg->architecture)
1600           return 1;
1601
1602      l = conf->arch_list.head;
1603
1604      while (l) {
1605           nv_pair_t *nv = l->data;
1606           if (strcmp(nv->name, pkg->architecture) == 0) {
1607                opkg_message(conf, OPKG_DEBUG, "arch %s (priority %s) supported for pkg %s\n", nv->name, nv->value, pkg->name);
1608                return 1;
1609           }
1610           l = l->next;
1611      }
1612
1613      opkg_message(conf, OPKG_DEBUG, "arch %s unsupported for pkg %s\n", pkg->architecture, pkg->name);
1614      return 0;
1615 }
1616
1617 int pkg_get_arch_priority(opkg_conf_t *conf, const char *archname)
1618 {
1619      nv_pair_list_elt_t *l;
1620
1621      l = conf->arch_list.head;
1622
1623      while (l) {
1624           nv_pair_t *nv = l->data;
1625           if (strcmp(nv->name, archname) == 0) {
1626                int priority = strtol(nv->value, NULL, 0);
1627                return priority;
1628           }
1629           l = l->next;
1630      }
1631      return 0;
1632 }
1633
1634 int pkg_info_preinstall_check(opkg_conf_t *conf)
1635 {
1636      int i;
1637      hash_table_t *pkg_hash = &conf->pkg_hash;
1638      pkg_vec_t *available_pkgs = pkg_vec_alloc();
1639      pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1640
1641      opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: updating arch priority for each package\n");
1642      pkg_hash_fetch_available(pkg_hash, available_pkgs);
1643      /* update arch_priority for each package */
1644      for (i = 0; i < available_pkgs->len; i++) {
1645           pkg_t *pkg = available_pkgs->pkgs[i];
1646           int arch_priority = 1;
1647           if (!pkg)
1648                continue;
1649           // opkg_message(conf, OPKG_DEBUG2, " package %s version=%s arch=%p:", pkg->name, pkg->version, pkg->architecture);
1650           if (pkg->architecture) 
1651                arch_priority = pkg_get_arch_priority(conf, pkg->architecture);
1652           else 
1653                opkg_message(conf, OPKG_ERROR, "pkg_info_preinstall_check: no architecture for package %s\n", pkg->name);
1654           // opkg_message(conf, OPKG_DEBUG2, "%s arch_priority=%d\n", pkg->architecture, arch_priority);
1655           pkg->arch_priority = arch_priority;
1656      }
1657
1658      for (i = 0; i < available_pkgs->len; i++) {
1659           pkg_t *pkg = available_pkgs->pkgs[i];
1660           if (!pkg->arch_priority && (pkg->state_flag || (pkg->state_want != SW_UNKNOWN))) {
1661                /* clear flags and want for any uninstallable package */
1662                opkg_message(conf, OPKG_NOTICE, "Clearing state_want and state_flag for pkg=%s (arch_priority=%d flag=%d want=%d)\n", 
1663                             pkg->name, pkg->arch_priority, pkg->state_flag, pkg->state_want);
1664                pkg->state_want = SW_UNKNOWN;
1665                pkg->state_flag = 0;
1666           }
1667      }
1668      pkg_vec_free(available_pkgs);
1669
1670      /* update the file owner data structure */
1671      opkg_message(conf, OPKG_INFO, "pkg_info_preinstall_check: update file owner list\n");
1672      pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
1673      for (i = 0; i < installed_pkgs->len; i++) {
1674           pkg_t *pkg = installed_pkgs->pkgs[i];
1675           str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */
1676           str_list_elt_t *iter;
1677           if (installed_files == NULL) {
1678                opkg_message(conf, OPKG_ERROR, "No installed files for pkg %s\n", pkg->name);
1679                break;
1680           }
1681           for (iter = installed_files->head; iter; iter = iter->next) {
1682                char *installed_file = iter->data;
1683                // opkg_message(conf, OPKG_DEBUG2, "pkg %s: file=%s\n", pkg->name, installed_file);
1684                file_hash_set_file_owner(conf, installed_file, pkg);
1685           }
1686      }
1687      pkg_vec_free(installed_pkgs);
1688
1689      return 0;
1690 }
1691
1692 struct pkg_write_filelist_data {
1693      opkg_conf_t *conf;
1694      pkg_t *pkg;
1695      FILE *stream;
1696 };
1697
1698 void pkg_write_filelist_helper(const char *key, void *entry_, void *data_)
1699 {
1700      struct pkg_write_filelist_data *data = data_;
1701      pkg_t *entry = entry_;
1702      if (entry == data->pkg) {
1703           fprintf(data->stream, "%s\n", key);
1704      }
1705 }
1706
1707 int pkg_write_filelist(opkg_conf_t *conf, pkg_t *pkg)
1708 {
1709      struct pkg_write_filelist_data data;
1710      char *list_file_name = NULL;
1711      int err = 0;
1712
1713      if (!pkg) {
1714           opkg_message(conf, OPKG_ERROR, "Null pkg\n");
1715           return -EINVAL;
1716      }
1717      opkg_message(conf, OPKG_INFO,
1718                   "    creating %s.list file\n", pkg->name);
1719      sprintf_alloc(&list_file_name, "%s/%s.list", pkg->dest->info_dir, pkg->name);
1720      if (!list_file_name) {
1721           opkg_message(conf, OPKG_ERROR, "Failed to alloc list_file_name\n");
1722           return -ENOMEM;
1723      }
1724      opkg_message(conf, OPKG_INFO,
1725                   "    creating %s file for pkg %s\n", list_file_name, pkg->name);
1726      data.stream = fopen(list_file_name, "w");
1727      if (!data.stream) {
1728           opkg_message(conf, OPKG_ERROR, "Could not open %s for writing: %s\n",
1729                        list_file_name, strerror(errno));
1730                        return errno;
1731      }
1732      data.pkg = pkg;
1733      data.conf = conf;
1734      hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data);
1735      fclose(data.stream);
1736      free(list_file_name);
1737
1738      return err;
1739 }
1740
1741 int pkg_write_changed_filelists(opkg_conf_t *conf)
1742 {
1743      pkg_vec_t *installed_pkgs = pkg_vec_alloc();
1744      hash_table_t *pkg_hash = &conf->pkg_hash;
1745      int i;
1746      int err;
1747      if (conf->noaction)
1748           return 0;
1749
1750      opkg_message(conf, OPKG_INFO, "%s: saving changed filelists\n", __FUNCTION__);
1751      pkg_hash_fetch_all_installed(pkg_hash, installed_pkgs);
1752      for (i = 0; i < installed_pkgs->len; i++) {
1753           pkg_t *pkg = installed_pkgs->pkgs[i];
1754           if (pkg->state_flag & SF_FILELIST_CHANGED) {
1755                opkg_message(conf, OPKG_DEBUG, "Calling pkg_write_filelist for pkg=%s from %s\n", pkg->name, __FUNCTION__);
1756                err = pkg_write_filelist(conf, pkg);
1757                if (err)
1758                     opkg_message(conf, OPKG_NOTICE, "pkg_write_filelist pkg=%s returned %d\n", pkg->name, err);
1759           }
1760      }
1761      return 0;
1762 }