fix a buffer overflow bug that cause
[oweals/opkg-lede.git] / libopkg / opkg_cmd.c
1 /* opkg_cmd.c - the opkg package management system
2
3    Carl D. Worth
4
5    Copyright (C) 2001 University of Southern California
6
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2, or (at
10    your option) any later version.
11
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 */
17
18
19 #include "includes.h"
20 #include <dirent.h>
21 #include <glob.h>
22
23 #include "opkg_conf.h"
24 #include "opkg_cmd.h"
25 #include "opkg_message.h"
26 #include "pkg.h"
27 #include "pkg_dest.h"
28 #include "pkg_parse.h"
29 #include "sprintf_alloc.h"
30 #include "pkg.h"
31 #include "file_util.h"
32 #include "str_util.h"
33 #include "libbb/libbb.h"
34 #include "opkg_utils.h"
35 #include "opkg_defines.h"
36
37 #include <fnmatch.h>
38
39
40 #include "opkg_download.h"
41 #include "opkg_install.h"
42 #include "opkg_upgrade.h"
43 #include "opkg_remove.h"
44 #include "opkg_configure.h"
45 #include "opkg_message.h"
46
47 #include "libopkg.h"
48 static void *p_userdata = NULL;
49
50 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv);
51 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv);
52 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv);
53 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv);
54 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv);
55 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv);
56 static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv);
57 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv);
58 static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv);
59 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv);
60 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv);
61 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv);
62 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv);
63 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv);
64 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv);
65 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv);
66 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv);
67 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv);
68 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv);
69 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv);
70 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv);
71 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv);
72 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv);
73 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv);
74 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv);
75 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv);
76 static int pkg_mark_provides(pkg_t *pkg);
77
78 /* XXX: CLEANUP: The usage strings should be incorporated into this
79    array for easier maintenance */
80 static opkg_cmd_t cmds[] = {
81      {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd}, 
82      {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd},
83      {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd},
84      {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd},
85      {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd},
86      {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd},
87      {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd},
88      {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd},
89      {"install_pending", 0, (opkg_cmd_fun_t)opkg_install_pending_cmd},
90      {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd},
91      {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd},
92      {"purge", 1, (opkg_cmd_fun_t)opkg_purge_cmd},
93      {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd},
94      {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd},
95      {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd},
96      {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd},
97      {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
98      {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
99      {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
100      {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
101      {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
102      {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
103      {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd},
104      {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd},
105      {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd},
106      {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd},
107      {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd},
108      {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd},
109      {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd},
110      {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd},
111 };
112
113 int opkg_state_changed;
114 static void write_status_files_if_changed(opkg_conf_t *conf)
115 {
116      if (opkg_state_changed && !conf->noaction) {
117           opkg_message(conf, OPKG_INFO,
118                        "  writing status file\n");
119           opkg_conf_write_status_files(conf);
120           pkg_write_changed_filelists(conf);
121      } else { 
122           opkg_message(conf, OPKG_DEBUG, "Nothing to be done\n");
123      }
124 }
125
126
127 static int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
128
129 opkg_cmd_t *opkg_cmd_find(const char *name)
130 {
131      int i;
132      opkg_cmd_t *cmd;
133
134      for (i=0; i < num_cmds; i++) {
135           cmd = &cmds[i];
136           if (strcmp(name, cmd->name) == 0) {
137                return cmd;
138           }
139      }
140
141      return NULL;
142 }
143
144 void opkg_print_error_list (opkg_conf_t *conf)
145 {
146   if ( error_list ) {
147      reverse_error_list(&error_list);
148
149      printf ("Collected errors:\n");
150      /* Here we print the errors collected and free the list */
151      while (error_list != NULL) {
152            printf (" * %s", error_list->errmsg);
153            error_list = error_list->next;
154
155      }
156      free_error_list();
157   }
158
159 }
160
161 int opkg_cmd_exec(opkg_cmd_t *cmd, opkg_conf_t *conf, int argc, const char **argv, void *userdata)
162 {
163         int result;
164         p_userdata = userdata;
165       
166
167         result = (cmd->fun)(conf, argc, argv);
168
169         if ( result != 0 && !error_list) {
170            opkg_message(conf, OPKG_NOTICE, "An error ocurred, return value: %d.\n", result);
171         }
172
173         opkg_print_error_list (conf);
174
175         p_userdata = NULL;
176         return result;
177 }
178
179 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
180 {
181      char *tmp;
182      int err;
183      int failures;
184      char *lists_dir;
185      pkg_src_list_elt_t *iter;
186      pkg_src_t *src;
187
188  
189     sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir);
190  
191     if (! file_is_dir(lists_dir)) {
192           if (file_exists(lists_dir)) {
193                opkg_message(conf, OPKG_ERROR,
194                             "%s: ERROR: %s exists, but is not a directory\n",
195                             __FUNCTION__, lists_dir);
196                free(lists_dir);
197                return EINVAL;
198           }
199           err = file_mkdir_hier(lists_dir, 0755);
200           if (err) {
201                opkg_message(conf, OPKG_ERROR,
202                             "%s: ERROR: failed to make directory %s: %s\n",
203                             __FUNCTION__, lists_dir, strerror(errno));
204                free(lists_dir);
205                return EINVAL;
206           }     
207      } 
208
209      failures = 0;
210
211
212      tmp = strdup ("/tmp/opkg.XXXXXX");
213
214      if (mkdtemp (tmp) == NULL) {
215          perror ("mkdtemp");
216          failures++;
217      }
218
219
220      for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) {
221           char *url, *list_file_name;
222
223           src = (pkg_src_t *)iter->data;
224
225           if (src->extra_data)  /* debian style? */
226               sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, 
227                             src->gzip ? "Packages.gz" : "Packages");
228           else
229               sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
230
231           sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
232           if (src->gzip) {
233               char *tmp_file_name;
234               FILE *in, *out;
235               
236               sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
237               err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
238               if (err == 0) {
239                    opkg_message (conf, OPKG_NOTICE, "Inflating %s\n", url);
240                    in = fopen (tmp_file_name, "r");
241                    out = fopen (list_file_name, "w");
242                    if (in && out)
243                         unzip (in, out);
244                    else
245                         err = 1;
246                    if (in)
247                         fclose (in);
248                    if (out)
249                         fclose (out);
250                    unlink (tmp_file_name);
251               }
252           } else
253               err = opkg_download(conf, url, list_file_name, NULL, NULL);
254           if (err) {
255                failures++;
256           } else {
257                opkg_message(conf, OPKG_NOTICE,
258                             "Updated list of available packages in %s\n",
259                             list_file_name);
260           }
261           free(url);
262
263 #ifdef HAVE_GPGME
264           if (conf->check_signature) {
265               /* download detached signitures to verify the package lists */
266               /* get the url for the sig file */
267               if (src->extra_data)      /* debian style? */
268                   sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data,
269                           "Packages.sig");
270               else
271                   sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig");
272
273               /* create temporary file for it */
274               char *tmp_file_name;
275
276               sprintf_alloc (&tmp_file_name, "%s/%s", tmp, "Packages.sig");
277
278               err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
279               if (err) {
280                   failures++;
281                   opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
282               } else {
283                   int err;
284                   err = opkg_verify_file (conf, list_file_name, tmp_file_name);
285                   if (err == 0)
286                       opkg_message (conf, OPKG_NOTICE, "Signature check passed\n");
287                   else
288                       opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
289               }
290               unlink (tmp_file_name);
291               free (tmp_file_name);
292               free (url);
293           }
294 #else
295           // Do nothing
296 #endif
297           free(list_file_name);
298      }
299      rmdir (tmp);
300      free (tmp);
301      free(lists_dir);
302
303      return failures;
304 }
305
306
307 struct opkg_intercept
308 {
309     char *oldpath;
310     char *statedir;
311 };
312
313 typedef struct opkg_intercept *opkg_intercept_t;
314
315 static opkg_intercept_t opkg_prep_intercepts(opkg_conf_t *conf)
316 {
317     opkg_intercept_t ctx;
318     char *oldpath;
319     char *newpath;
320     int gen;
321
322     ctx = calloc (1, sizeof (*ctx));
323     oldpath = getenv ("PATH");
324     if (oldpath) {
325         ctx->oldpath = strdup (oldpath);
326     } else {
327         ctx->oldpath = 0;
328     }
329
330
331     sprintf_alloc (&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
332     setenv ("PATH", newpath, 1);
333     free (newpath);
334     
335     gen = 0;
336  retry:
337     sprintf_alloc (&ctx->statedir, "/tmp/opkg-intercept-%d-%d", getpid (), gen);
338     if (mkdir (ctx->statedir, 0770) < 0) {
339         if (errno == EEXIST) {
340             free (ctx->statedir);
341             gen++;
342             goto retry;
343         }
344         perror (ctx->statedir);
345         return NULL;
346     }
347     setenv ("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
348     return ctx;
349 }
350
351 static int opkg_finalize_intercepts(opkg_intercept_t ctx)
352 {
353     char *cmd;
354     DIR *dir;
355     int err = 0;
356
357     if (ctx->oldpath) {
358         setenv ("PATH", ctx->oldpath, 1);
359         free (ctx->oldpath);
360     } else {
361         unsetenv("PATH"); 
362     }
363
364     dir = opendir (ctx->statedir);
365     if (dir) {
366         struct dirent *de;
367         while (de = readdir (dir), de != NULL) {
368             char *path;
369             
370             if (de->d_name[0] == '.')
371                 continue;
372             
373             sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name);
374             if (access (path, X_OK) == 0) {
375                 if (system (path)) {
376                     err = errno;
377                     perror (de->d_name);
378                 }
379             }
380             free (path);
381         }
382     } else
383         perror (ctx->statedir);
384         
385     sprintf_alloc (&cmd, "rm -rf %s", ctx->statedir);
386     err = system (cmd);
387     free (cmd);
388
389     free (ctx->statedir);
390     free (ctx);
391
392     return err;
393 }
394
395 /* For package pkg do the following: If it is already visited, return. If not,
396    add it in visited list and recurse to its deps. Finally, add it to ordered 
397    list.
398    pkg_vec all contains all available packages in repos.
399    pkg_vec visited contains packages already visited by this function, and is 
400    used to end recursion and avoid an infinite loop on graph cycles.
401    pkg_vec ordered will finally contain the ordered set of packages.
402 */
403 static int opkg_recurse_pkgs_in_order(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *all,
404                                pkg_vec_t *visited, pkg_vec_t *ordered)
405 {
406     int j,k,l,m;
407     int count;
408     pkg_t *dep;
409     compound_depend_t * compound_depend;
410     depend_t ** possible_satisfiers;
411     abstract_pkg_t *abpkg;
412     abstract_pkg_t **dependents;
413
414     /* If it's just an available package, that is, not installed and not even
415        unpacked, skip it */
416     /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED 
417        would do here. However, if there is an intermediate node (pkg) that is 
418        configured and installed between two unpacked packages, the latter 
419        won't be properly reordered, unless all installed/unpacked pkgs are
420        checked */
421     if (pkg->state_status == SS_NOT_INSTALLED) 
422         return 0;
423
424     /* If the  package has already been visited (by this function), skip it */
425     for(j = 0; j < visited->len; j++) 
426         if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) {
427             opkg_message(conf, OPKG_INFO,
428                          "  pkg: %s already visited\n", pkg->name);
429             return 0;
430         }
431     
432     pkg_vec_insert(visited, pkg);
433
434     count = pkg->pre_depends_count + pkg->depends_count + \
435         pkg->recommends_count + pkg->suggests_count;
436
437     opkg_message(conf, OPKG_INFO,
438                  "  pkg: %s\n", pkg->name);
439
440     /* Iterate over all the dependencies of pkg. For each one, find a package 
441        that is either installed or unpacked and satisfies this dependency.
442        (there should only be one such package per dependency installed or 
443        unpacked). Then recurse to the dependency package */
444     for (j=0; j < count ; j++) {
445         compound_depend = &pkg->depends[j];
446         possible_satisfiers = compound_depend->possibilities;
447         for (k=0; k < compound_depend->possibility_count ; k++) {
448             abpkg = possible_satisfiers[k]->pkg;
449             dependents = abpkg->provided_by->pkgs;
450             l = 0;
451             if (dependents != NULL)
452                 while (dependents [l] != NULL && l < abpkg->provided_by->len) {
453                     opkg_message(conf, OPKG_INFO,
454                                  "  Descending on pkg: %s\n", 
455                                  dependents [l]->name);
456     
457                     /* find whether dependent l is installed or unpacked,
458                      * and then find which package in the list satisfies it */
459                     for(m = 0; m < all->len; m++) {
460                         dep = all->pkgs[m];
461                         if ( dep->state_status != SS_NOT_INSTALLED)
462                             if ( ! strcmp(dep->name, dependents[l]->name)) {
463                                 opkg_recurse_pkgs_in_order(conf, dep, all, 
464                                                            visited, ordered);
465                                 /* Stop the outer loop */
466                                 l = abpkg->provided_by->len;
467                                 /* break from the inner loop */
468                                 break;
469                             }
470                     }
471                     l++;
472                 }
473         }
474     }
475
476     /* When all recursions from this node down, are over, and all 
477        dependencies have been added in proper order in the ordered array, add
478        also the package pkg to ordered array */
479     pkg_vec_insert(ordered, pkg);
480
481     return 0;
482
483 }
484
485 static int opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
486 {
487     pkg_vec_t *all, *ordered, *visited;
488      int i;
489      pkg_t *pkg;
490      opkg_intercept_t ic;
491      int r, err = 0;
492
493      opkg_message(conf, OPKG_INFO,
494                   "Configuring unpacked packages\n");
495      fflush( stdout );
496
497      all = pkg_vec_alloc();
498
499      pkg_hash_fetch_available(&conf->pkg_hash, all);
500
501      /* Reorder pkgs in order to be configured according to the Depends: tag
502         order */
503      opkg_message(conf, OPKG_INFO,
504                   "Reordering packages before configuring them...\n");
505      ordered = pkg_vec_alloc();
506      visited = pkg_vec_alloc();
507      for(i = 0; i < all->len; i++) {
508          pkg = all->pkgs[i];
509          opkg_recurse_pkgs_in_order(conf, pkg, all, visited, ordered);
510      }
511
512
513      ic = opkg_prep_intercepts (conf);
514     
515      for(i = 0; i < all->len; i++) {
516           pkg = all->pkgs[i];
517
518           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
519                continue;
520
521           if (pkg->state_status == SS_UNPACKED) {
522                opkg_message(conf, OPKG_NOTICE,
523                             "Configuring %s\n", pkg->name);
524                fflush( stdout );
525                r = opkg_configure(conf, pkg);
526                if (r == 0) {
527                     pkg->state_status = SS_INSTALLED;
528                     pkg->parent->state_status = SS_INSTALLED;
529                     pkg->state_flag &= ~SF_PREFER;
530                } else {
531                     if (!err)
532                         err = r;
533                }
534           }
535      }
536
537      r = opkg_finalize_intercepts (ic);
538      if (r && !err)
539          err = r;
540
541      pkg_vec_free(all);
542      pkg_vec_free(ordered);
543      pkg_vec_free(visited);
544
545      return err;
546 }
547
548 static opkg_conf_t *global_conf;
549
550 static void sigint_handler(int sig)
551 {
552      signal(sig, SIG_DFL);
553      opkg_message(NULL, OPKG_NOTICE,
554                   "opkg: interrupted. writing out status database\n");
555      write_status_files_if_changed(global_conf);
556      exit(128 + sig);
557 }
558
559 static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv)
560 {
561      int i;
562      char *arg;
563      int err=0;
564
565      global_conf = conf;
566      signal(SIGINT, sigint_handler);
567
568      /*
569       * Now scan through package names and install
570       */
571      for (i=0; i < argc; i++) {
572           arg = argv[i];
573
574           opkg_message(conf, OPKG_DEBUG2, "Debug install_cmd: %s  \n",arg );
575           err = opkg_prepare_url_for_install(conf, arg, &argv[i]);
576           if (err != EINVAL && err != 0)
577               return err;
578      }
579      pkg_info_preinstall_check(conf);
580
581      for (i=0; i < argc; i++) {
582           arg = argv[i];
583           err = opkg_install_by_name(conf, arg);
584           if (err == OPKG_PKG_HAS_NO_CANDIDATE) {
585                opkg_message(conf, OPKG_ERROR,
586                             "Cannot find package %s.\n",
587                             arg);
588           }
589      }
590
591      /* recheck to verify that all dependences are satisfied */
592      if (0) opkg_satisfy_all_dependences(conf);
593
594      opkg_configure_packages(conf, NULL);
595
596      write_status_files_if_changed(conf);
597
598      return err;
599 }
600
601 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv)
602 {
603      int i;
604      pkg_t *pkg;
605      int err;
606
607      global_conf = conf;
608      signal(SIGINT, sigint_handler);
609
610      if (argc) {
611           for (i=0; i < argc; i++) {
612                char *arg = argv[i];
613
614                err = opkg_prepare_url_for_install(conf, arg, &arg);
615                if (err != EINVAL && err != 0)
616                    return err;
617           }
618           pkg_info_preinstall_check(conf);
619
620           for (i=0; i < argc; i++) {
621                char *arg = argv[i];
622                if (conf->restrict_to_default_dest) {
623                     pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
624                                                                 argv[i],
625                                                                 conf->default_dest);
626                     if (pkg == NULL) {
627                          opkg_message(conf, OPKG_NOTICE,
628                                       "Package %s not installed in %s\n",
629                                       argv[i], conf->default_dest->name);
630                          continue;
631                     }
632                } else {
633                     pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
634                                                            argv[i]);
635                }
636                if (pkg)
637                     opkg_upgrade_pkg(conf, pkg);
638                else {
639                     opkg_install_by_name(conf, arg);
640                }
641           }
642      } else {
643           pkg_vec_t *installed = pkg_vec_alloc();
644
645           pkg_info_preinstall_check(conf);
646
647           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
648           for (i = 0; i < installed->len; i++) {
649                pkg = installed->pkgs[i];
650                opkg_upgrade_pkg(conf, pkg);
651           }
652           pkg_vec_free(installed);
653      }
654
655      /* recheck to verify that all dependences are satisfied */
656      if (0) opkg_satisfy_all_dependences(conf);
657
658      opkg_configure_packages(conf, NULL);
659
660      write_status_files_if_changed(conf);
661
662      return 0;
663 }
664
665 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv)
666 {
667      int i, err;
668      char *arg;
669      pkg_t *pkg;
670
671      pkg_info_preinstall_check(conf);
672      for (i = 0; i < argc; i++) {
673           arg = argv[i];
674
675           pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, arg, &err);
676           if (pkg == NULL) {
677                opkg_message(conf, OPKG_ERROR,
678                             "Cannot find package %s.\n"
679                             "Check the spelling or perhaps run 'opkg update'\n",
680                             arg);
681                continue;
682           }
683
684           err = opkg_download_pkg(conf, pkg, ".");
685
686           if (err) {
687                opkg_message(conf, OPKG_ERROR,
688                             "Failed to download %s\n", pkg->name);
689           } else {
690                opkg_message(conf, OPKG_NOTICE,
691                             "Downloaded %s as %s\n",
692                             pkg->name, pkg->local_filename);
693           }
694      }
695
696      return 0;
697 }
698
699
700 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv)
701 {
702      int i ;
703      pkg_vec_t *available;
704      pkg_t *pkg;
705      char desc_short[OPKG_LIST_DESCRIPTION_LENGTH];
706      char *newline;
707      char *pkg_name = NULL;
708      char *version_str;
709
710      if (argc > 0) {
711           pkg_name = argv[0];
712      }
713      available = pkg_vec_alloc();
714      pkg_hash_fetch_available(&conf->pkg_hash, available);
715      pkg_vec_sort(available, pkg_compare_names);
716      for (i=0; i < available->len; i++) {
717           pkg = available->pkgs[i];
718           /* if we have package name or pattern and pkg does not match, then skip it */
719           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
720                continue;
721           if (pkg->description) {
722                strncpy(desc_short, pkg->description, OPKG_LIST_DESCRIPTION_LENGTH);
723           } else {
724                desc_short[0] = '\0';
725           }
726           desc_short[OPKG_LIST_DESCRIPTION_LENGTH - 1] = '\0';
727           newline = strchr(desc_short, '\n');
728           if (newline) {
729                *newline = '\0';
730           }
731           if (opkg_cb_list) {
732                 version_str = pkg_version_str_alloc(pkg);
733                 opkg_cb_list(pkg->name,desc_short,
734                                              version_str,
735                                          pkg->state_status,
736                                          p_userdata);
737                 free(version_str);
738           }
739      }
740      pkg_vec_free(available);
741
742      return 0;
743 }
744
745
746 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
747 {
748      int i ;
749      pkg_vec_t *available;
750      pkg_t *pkg;
751      char desc_short[OPKG_LIST_DESCRIPTION_LENGTH];
752      char *newline;
753      char *pkg_name = NULL;
754      char *version_str;
755
756      if (argc > 0) {
757           pkg_name = argv[0];
758      }
759      available = pkg_vec_alloc();
760      pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
761      pkg_vec_sort(available, pkg_compare_names);
762      for (i=0; i < available->len; i++) {
763           pkg = available->pkgs[i];
764           /* if we have package name or pattern and pkg does not match, then skip it */
765           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
766                continue;
767           if (pkg->description) {
768                strncpy(desc_short, pkg->description, OPKG_LIST_DESCRIPTION_LENGTH);
769           } else {
770                desc_short[0] = '\0';
771           }
772           desc_short[OPKG_LIST_DESCRIPTION_LENGTH - 1] = '\0';
773           newline = strchr(desc_short, '\n');
774           if (newline) {
775                *newline = '\0';
776           }
777           if (opkg_cb_list) {
778                 version_str = pkg_version_str_alloc(pkg);
779                 opkg_cb_list(pkg->name,desc_short,
780                                              version_str,
781                                          pkg->state_status,
782                                          p_userdata);
783                 free(version_str);
784           }
785      }
786
787      return 0;
788 }
789
790 static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv) 
791 {
792     struct active_list *head = prepare_upgrade_list(conf);
793     struct active_list *node=NULL;
794     pkg_t *_old_pkg, *_new_pkg;
795     char *old_v, *new_v;
796     for (node = active_list_next(head, head); node;node = active_list_next(head,node)) {
797         _old_pkg = list_entry(node, pkg_t, list);
798         _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, _old_pkg->name, NULL);
799         old_v = pkg_version_str_alloc(_old_pkg);
800         new_v = pkg_version_str_alloc(_new_pkg);
801         if (opkg_cb_list)
802             opkg_cb_list(_old_pkg->name, new_v, old_v, _old_pkg->state_status, p_userdata);
803         free(old_v);
804         free(new_v);
805     }
806     active_list_head_delete(head);
807     return 0;
808 }
809
810 static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int installed_only)
811 {
812      int i;
813      pkg_vec_t *available;
814      pkg_t *pkg;
815      char *pkg_name = NULL;
816      char **pkg_fields = NULL;
817      int n_fields = 0;
818      char *buff = NULL; 
819
820      if (argc > 0) {
821           pkg_name = argv[0];
822      }
823      if (argc > 1) {
824           pkg_fields = &argv[1];
825           n_fields = argc - 1;
826      }
827
828      available = pkg_vec_alloc();
829      if (installed_only)
830           pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
831      else
832           pkg_hash_fetch_available(&conf->pkg_hash, available);
833      for (i=0; i < available->len; i++) {
834           pkg = available->pkgs[i];
835           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
836                continue;
837           }
838
839           buff = pkg_formatted_info(pkg);
840           if ( buff ) {
841                if (opkg_cb_status) opkg_cb_status(pkg->name,
842                                                   pkg->state_status,
843                                                   buff,
844                                                   p_userdata);
845 /* 
846    We should not forget that actually the pointer is allocated. 
847    We need to free it :)  ( Thanks florian for seeing the error )
848 */
849                free(buff);
850                buff = NULL;
851           }
852           if (conf->verbosity > 1) {
853                conffile_list_elt_t *iter;
854                for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
855                     conffile_t *cf = (conffile_t *)iter->data;
856                     int modified = conffile_has_been_modified(conf, cf);
857                     opkg_message(conf, OPKG_NOTICE, "conffile=%s md5sum=%s modified=%d\n",
858                                  cf->name, cf->value, modified);
859                }
860           }
861      }
862      pkg_vec_free(available);
863
864      return 0;
865 }
866
867 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv)
868 {
869      return opkg_info_status_cmd(conf, argc, argv, 0);
870 }
871
872 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv)
873 {
874      return opkg_info_status_cmd(conf, argc, argv, 1);
875 }
876
877 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv)
878 {
879      
880      int err;
881      if (argc > 0) {
882           char *pkg_name = NULL;
883
884           pkg_name = argv[0];
885
886           err = opkg_configure_packages (conf, pkg_name);
887      
888      } else {
889           err = opkg_configure_packages (conf, NULL);
890      }
891
892      write_status_files_if_changed(conf);
893
894      return err;
895 }
896
897 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv)
898 {
899      int i, err;
900      char *globpattern;
901      glob_t globbuf;
902     
903      sprintf_alloc(&globpattern, "%s/*" OPKG_PKG_EXTENSION, conf->pending_dir);
904      err = glob(globpattern, 0, NULL, &globbuf);
905      free(globpattern);
906      if (err) {
907           return 0;
908      }
909
910      opkg_message(conf, OPKG_NOTICE,
911                   "The following packages in %s will now be installed.\n",
912                   conf->pending_dir);
913      for (i = 0; i < globbuf.gl_pathc; i++) {
914           opkg_message(conf, OPKG_NOTICE,
915                        "%s%s", i == 0 ? "" : " ", globbuf.gl_pathv[i]);
916      }
917      opkg_message(conf, OPKG_NOTICE, "\n");
918      for (i = 0; i < globbuf.gl_pathc; i++) {
919           err = opkg_install_from_file(conf, globbuf.gl_pathv[i]);
920           if (err == 0) {
921                err = unlink(globbuf.gl_pathv[i]);
922                if (err) {
923                     opkg_message(conf, OPKG_ERROR,
924                                  "%s: ERROR: failed to unlink %s: %s\n",
925                                  __FUNCTION__, globbuf.gl_pathv[i], strerror(err));
926                     return err;
927                }
928           }
929      }
930      globfree(&globbuf);
931
932      return err;
933 }
934
935 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv)
936 {
937      int i,a,done;
938      pkg_t *pkg;
939      pkg_t *pkg_to_remove;
940      pkg_vec_t *available;
941      char *pkg_name = NULL;
942      global_conf = conf;
943      signal(SIGINT, sigint_handler);
944
945 // ENH: Add the "no pkg removed" just in case.
946
947     done = 0;
948
949      pkg_info_preinstall_check(conf);
950      if ( argc > 0 ) {
951         available = pkg_vec_alloc();
952         pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
953         for (i=0; i < argc; i++) {
954            pkg_name = calloc(1, strlen(argv[i])+2);
955            strcpy(pkg_name,argv[i]);
956            for (a=0; a < available->len; a++) {
957                pkg = available->pkgs[a];
958                if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
959                   continue;
960                }
961                if (conf->restrict_to_default_dest) {
962                     pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
963                                                                 pkg->name,
964                                                                 conf->default_dest);
965                } else {
966                     pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
967                }
968         
969                if (pkg == NULL) {
970                     opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
971                     continue;
972                }
973                if (pkg->state_status == SS_NOT_INSTALLED) {    // Added the control, so every already removed package could be skipped
974                     opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
975                     continue;
976                }
977                opkg_remove_pkg(conf, pkg_to_remove,0);
978                done = 1;
979            }
980            free (pkg_name);
981         }
982         pkg_vec_free(available);
983      } else {
984           pkg_vec_t *installed_pkgs = pkg_vec_alloc();
985           int i;
986           int flagged_pkg_count = 0;
987           int removed;
988
989           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed_pkgs);
990
991           for (i = 0; i < installed_pkgs->len; i++) {
992                pkg_t *pkg = installed_pkgs->pkgs[i];
993                if (pkg->state_flag & SF_USER) {
994                     flagged_pkg_count++;
995                } else {
996                     if (!pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL))
997                          opkg_message(conf, OPKG_NOTICE, "Non-user leaf package: %s\n", pkg->name);
998                }
999           }
1000           if (!flagged_pkg_count) {
1001                opkg_message(conf, OPKG_NOTICE, "No packages flagged as installed by user, \n"
1002                             "so refusing to uninstall unflagged non-leaf packages\n");
1003                return 0;
1004           }
1005
1006           /* find packages not flagged SF_USER (i.e., installed to
1007            * satisfy a dependence) and not having any dependents, and
1008            * remove them */
1009           do {
1010                removed = 0;
1011                for (i = 0; i < installed_pkgs->len; i++) {
1012                     pkg_t *pkg = installed_pkgs->pkgs[i];
1013                     if (!(pkg->state_flag & SF_USER)
1014                         && !pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL)) {
1015                          removed++;
1016                          opkg_message(conf, OPKG_NOTICE, "Removing non-user leaf package %s\n");
1017                          opkg_remove_pkg(conf, pkg,0);
1018                          done = 1;
1019                     }
1020                }
1021           } while (removed);
1022           pkg_vec_free(installed_pkgs);
1023      }
1024
1025      if ( done == 0 ) 
1026         opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
1027
1028      write_status_files_if_changed(conf);
1029      return 0;
1030 }
1031
1032 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv)
1033 {
1034      int i;
1035      pkg_t *pkg;
1036
1037      global_conf = conf;
1038      signal(SIGINT, sigint_handler);
1039
1040      pkg_info_preinstall_check(conf);
1041
1042      for (i=0; i < argc; i++) {
1043           if (conf->restrict_to_default_dest) {
1044                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
1045                                                            argv[i],
1046                                                            conf->default_dest);
1047           } else {
1048                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
1049           }
1050
1051           if (pkg == NULL) {
1052                opkg_message(conf, OPKG_ERROR,
1053                             "Package %s is not installed.\n", argv[i]);
1054                continue;
1055           }
1056           opkg_purge_pkg(conf, pkg);
1057      }
1058
1059      write_status_files_if_changed(conf);
1060      return 0;
1061 }
1062
1063 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
1064 {
1065      int i;
1066      pkg_t *pkg;
1067      const char *flags = argv[0];
1068     
1069      global_conf = conf;
1070      signal(SIGINT, sigint_handler);
1071
1072      for (i=1; i < argc; i++) {
1073           if (conf->restrict_to_default_dest) {
1074                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
1075                                                            argv[i],
1076                                                            conf->default_dest);
1077           } else {
1078                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
1079           }
1080
1081           if (pkg == NULL) {
1082                opkg_message(conf, OPKG_ERROR,
1083                             "Package %s is not installed.\n", argv[i]);
1084                continue;
1085           }
1086           if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
1087               ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
1088               pkg->state_flag = pkg_state_flag_from_str(flags);
1089           }
1090 /* pb_ asked this feature 03292004 */
1091 /* Actually I will use only this two, but this is an open for various status */
1092           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
1093               pkg->state_status = pkg_state_status_from_str(flags);
1094           }
1095           opkg_state_changed++;
1096           opkg_message(conf, OPKG_NOTICE,
1097                        "Setting flags for package %s to %s\n",
1098                        pkg->name, flags);
1099      }
1100
1101      write_status_files_if_changed(conf);
1102      return 0;
1103 }
1104
1105 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
1106 {
1107      pkg_t *pkg;
1108      str_list_t *installed_files;
1109      str_list_elt_t *iter;
1110      char *pkg_version;
1111      size_t buff_len = 8192;
1112      size_t used_len;
1113      char *buff ;
1114
1115      buff = (char *)calloc(1, buff_len);
1116      if ( buff == NULL ) {
1117         fprintf( stderr,"%s: Unable to allocate memory \n",__FUNCTION__);
1118         return ENOMEM;
1119      }
1120  
1121      if (argc < 1) {
1122           return EINVAL;
1123      }
1124
1125      pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
1126                                             argv[0]);
1127      if (pkg == NULL) {
1128           opkg_message(conf, OPKG_ERROR,
1129                        "Package %s not installed.\n", argv[0]);
1130           return 0;
1131      }
1132
1133      installed_files = pkg_get_installed_files(pkg);
1134      pkg_version = pkg_version_str_alloc(pkg);
1135
1136      if (buff) {
1137      try_again:
1138           used_len = snprintf(buff, buff_len, "Package %s (%s) is installed on %s and has the following files:\n",
1139                               pkg->name, pkg_version, pkg->dest->name) + 1;
1140           if (used_len > buff_len) {
1141                buff_len *= 2;
1142                buff = realloc (buff, buff_len);
1143                goto try_again;
1144           }
1145           for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1146                used_len += strlen (iter->data) + 1;
1147                while (buff_len <= used_len) {
1148                     buff_len *= 2;
1149                     buff = realloc (buff, buff_len);
1150                }
1151                strncat(buff, iter->data, buff_len);
1152                strncat(buff, "\n", buff_len);
1153           } 
1154           if (opkg_cb_list) opkg_cb_list(pkg->name,
1155                                          buff,
1156                                          pkg_version_str_alloc(pkg),
1157                                          pkg->state_status,
1158                                          p_userdata);
1159           free(buff);
1160      }
1161
1162      free(pkg_version);
1163      pkg_free_installed_files(pkg);
1164
1165      return 0;
1166 }
1167
1168 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
1169 {
1170
1171      if (argc > 0) {
1172           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1173           const char *rel_str = "depends on";
1174           int i;
1175      
1176           pkg_info_preinstall_check(conf);
1177
1178           if (conf->query_all)
1179                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1180           else
1181                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1182           for (i = 0; i < argc; i++) {
1183                const char *target = argv[i];
1184                int j;
1185
1186                opkg_message(conf, OPKG_ERROR, "target=%s\n", target);
1187
1188                for (j = 0; j < available_pkgs->len; j++) {
1189                     pkg_t *pkg = available_pkgs->pkgs[j];
1190                     if (fnmatch(target, pkg->name, 0) == 0) {
1191                          int k;
1192                          int count = pkg->depends_count + pkg->pre_depends_count;
1193                          opkg_message(conf, OPKG_ERROR, "What %s (arch=%s) %s\n",
1194                                       target, pkg->architecture, rel_str);
1195                          for (k = 0; k < count; k++) {
1196                               compound_depend_t *cdepend = &pkg->depends[k];
1197                               int l;
1198                               for (l = 0; l < cdepend->possibility_count; l++) {
1199                                    depend_t *possibility = cdepend->possibilities[l];
1200                                    opkg_message(conf, OPKG_ERROR, "    %s", possibility->pkg->name);
1201                                    if (conf->verbosity > 0) {
1202                                         // char *ver = abstract_pkg_version_str_alloc(possibility->pkg); 
1203                                         opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
1204                                         if (possibility->version) {
1205                                              char *typestr = NULL;
1206                                              switch (possibility->constraint) {
1207                                              case NONE: typestr = "none"; break;
1208                                              case EARLIER: typestr = "<"; break;
1209                                              case EARLIER_EQUAL: typestr = "<="; break;
1210                                              case EQUAL: typestr = "="; break;
1211                                              case LATER_EQUAL: typestr = ">="; break;
1212                                              case LATER: typestr = ">"; break;
1213                                              }
1214                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1215                                         }
1216                                         // free(ver);
1217                                    }
1218                                    opkg_message(conf, OPKG_ERROR, "\n");
1219                               }
1220                          }
1221                     }
1222                }
1223           }
1224           pkg_vec_free(available_pkgs);
1225      }
1226      return 0;
1227 }
1228
1229 enum what_field_type {
1230   WHATDEPENDS,
1231   WHATCONFLICTS,
1232   WHATPROVIDES,
1233   WHATREPLACES,
1234   WHATRECOMMENDS,
1235   WHATSUGGESTS
1236 };
1237
1238 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int recursive, int argc, char **argv)
1239 {
1240
1241      if (argc > 0) {
1242           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1243           const char *rel_str = NULL;
1244           int i;
1245           int changed;
1246
1247           switch (what_field_type) {
1248           case WHATDEPENDS: rel_str = "depends on"; break;
1249           case WHATCONFLICTS: rel_str = "conflicts with"; break;
1250           case WHATSUGGESTS: rel_str = "suggests"; break;
1251           case WHATRECOMMENDS: rel_str = "recommends"; break;
1252           case WHATPROVIDES: rel_str = "provides"; break;
1253           case WHATREPLACES: rel_str = "replaces"; break;
1254           }
1255      
1256           if (conf->query_all)
1257                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1258           else
1259                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1260
1261           /* mark the root set */
1262           pkg_vec_clear_marks(available_pkgs);
1263           opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1264           for (i = 0; i < argc; i++) {
1265                const char *dependee_pattern = argv[i];
1266                pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1267           }
1268           for (i = 0; i < available_pkgs->len; i++) {
1269                pkg_t *pkg = available_pkgs->pkgs[i];
1270                if (pkg->state_flag & SF_MARKED) {
1271                     /* mark the parent (abstract) package */
1272                     pkg_mark_provides(pkg);
1273                     opkg_message(conf, OPKG_NOTICE, "  %s\n", pkg->name);
1274                }
1275           }
1276
1277           opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1278           do {
1279                int j;
1280                changed = 0;
1281
1282                for (j = 0; j < available_pkgs->len; j++) {
1283                     pkg_t *pkg = available_pkgs->pkgs[j];
1284                     int k;
1285                     int count = ((what_field_type == WHATCONFLICTS)
1286                                  ? pkg->conflicts_count
1287                                  : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1288                     /* skip this package if it is already marked */
1289                     if (pkg->parent->state_flag & SF_MARKED) {
1290                          continue;
1291                     }
1292                     for (k = 0; k < count; k++) {
1293                          compound_depend_t *cdepend = 
1294                               (what_field_type == WHATCONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1295                          int l;
1296                          for (l = 0; l < cdepend->possibility_count; l++) {
1297                               depend_t *possibility = cdepend->possibilities[l];
1298                               if (possibility->pkg->state_flag & SF_MARKED) {
1299                                    /* mark the depending package so we won't visit it again */
1300                                    pkg->state_flag |= SF_MARKED;
1301                                    pkg_mark_provides(pkg);
1302                                    changed++;
1303
1304                                    opkg_message(conf, OPKG_NOTICE, "    %s", pkg->name);
1305                                    if (conf->verbosity > 0) {
1306                                         char *ver = pkg_version_str_alloc(pkg); 
1307                                         opkg_message(conf, OPKG_NOTICE, " %s", ver);
1308                                         opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1309                                         if (possibility->version) {
1310                                              char *typestr = NULL;
1311                                              switch (possibility->constraint) {
1312                                              case NONE: typestr = "none"; break;
1313                                              case EARLIER: typestr = "<"; break;
1314                                              case EARLIER_EQUAL: typestr = "<="; break;
1315                                              case EQUAL: typestr = "="; break;
1316                                              case LATER_EQUAL: typestr = ">="; break;
1317                                              case LATER: typestr = ">"; break;
1318                                              }
1319                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1320                                         }
1321                                         free(ver);
1322                                         if (!pkg_dependence_satisfiable(conf, possibility))
1323                                              opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1324                                    }
1325                                    opkg_message(conf, OPKG_NOTICE, "\n");
1326                                    goto next_package;
1327                               }
1328                          }
1329                     }
1330                next_package:
1331                     ;
1332                }
1333           } while (changed && recursive);
1334           pkg_vec_free(available_pkgs);
1335      }
1336
1337      return 0;
1338 }
1339
1340 static int pkg_mark_provides(pkg_t *pkg)
1341 {
1342      int provides_count = pkg->provides_count;
1343      abstract_pkg_t **provides = pkg->provides;
1344      int i;
1345      pkg->parent->state_flag |= SF_MARKED;
1346      for (i = 0; i < provides_count; i++) {
1347           provides[i]->state_flag |= SF_MARKED;
1348      }
1349      return 0;
1350 }
1351
1352 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1353 {
1354      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 1, argc, argv);
1355 }
1356 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1357 {
1358      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 0, argc, argv);
1359 }
1360
1361 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1362 {
1363      return opkg_what_depends_conflicts_cmd(conf, WHATSUGGESTS, 0, argc, argv);
1364 }
1365
1366 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1367 {
1368      return opkg_what_depends_conflicts_cmd(conf, WHATRECOMMENDS, 0, argc, argv);
1369 }
1370
1371 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1372 {
1373      return opkg_what_depends_conflicts_cmd(conf, WHATCONFLICTS, 0, argc, argv);
1374 }
1375
1376 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1377 {
1378
1379      if (argc > 0) {
1380           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1381           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1382           int i;
1383      
1384           pkg_info_preinstall_check(conf);
1385
1386           if (conf->query_all)
1387                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1388           else
1389                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1390           for (i = 0; i < argc; i++) {
1391                const char *target = argv[i];
1392                int j;
1393
1394                opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1395                             rel_str, target);
1396                for (j = 0; j < available_pkgs->len; j++) {
1397                     pkg_t *pkg = available_pkgs->pkgs[j];
1398                     int k;
1399                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1400                     for (k = 0; k < count; k++) {
1401                          abstract_pkg_t *apkg = 
1402                               ((what_field_type == WHATPROVIDES) 
1403                                ? pkg->provides[k]
1404                                : pkg->replaces[k]);
1405                          if (fnmatch(target, apkg->name, 0) == 0) {
1406                               opkg_message(conf, OPKG_ERROR, "    %s", pkg->name);
1407                               if (strcmp(target, apkg->name) != 0)
1408                                    opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1409                               opkg_message(conf, OPKG_ERROR, "\n");
1410                          }
1411                     }
1412                }
1413           }
1414           pkg_vec_free(available_pkgs);
1415      }
1416      return 0;
1417 }
1418
1419 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1420 {
1421      return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1422 }
1423
1424 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1425 {
1426      return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1427 }
1428
1429 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1430 {
1431      int i;
1432
1433      pkg_vec_t *installed;
1434      pkg_t *pkg;
1435      str_list_t *installed_files;
1436      str_list_elt_t *iter;
1437      char *installed_file;
1438
1439      if (argc < 1) {
1440           return EINVAL;
1441      }
1442  
1443      installed = pkg_vec_alloc();
1444      pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1445      pkg_vec_sort(installed, pkg_compare_names);
1446
1447      for (i=0; i < installed->len; i++) {
1448           pkg = installed->pkgs[i];
1449
1450           installed_files = pkg_get_installed_files(pkg);
1451
1452           for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1453                installed_file = (char *)iter->data;
1454                if (fnmatch(argv[0], installed_file, 0)==0)  {
1455                         if (opkg_cb_list) opkg_cb_list(pkg->name, 
1456                                                        installed_file, 
1457                                                        pkg_version_str_alloc(pkg), 
1458                                                        pkg->state_status, p_userdata);
1459                }                
1460           }
1461
1462           pkg_free_installed_files(pkg);
1463      }
1464
1465      pkg_vec_free(installed);
1466
1467      return 0;
1468 }
1469
1470 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1471 {
1472      if (argc == 3) {
1473           /* this is a bit gross */
1474           struct pkg p1, p2;
1475           parseVersion(&p1, argv[0]); 
1476           parseVersion(&p2, argv[2]); 
1477           return pkg_version_satisfied(&p1, &p2, argv[1]);
1478      } else {
1479           opkg_message(conf, OPKG_ERROR,
1480                        "opkg compare_versions <v1> <op> <v2>\n"
1481                        "<op> is one of <= >= << >> =\n");
1482           return -1;
1483      }
1484 }
1485
1486 #ifndef HOST_CPU_STR
1487 #define HOST_CPU_STR__(X) #X
1488 #define HOST_CPU_STR_(X) HOST_CPU_STR__(X)
1489 #define HOST_CPU_STR HOST_CPU_STR_(HOST_CPU_FOO)
1490 #endif
1491
1492 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1493 {
1494      nv_pair_list_elt_t *l;
1495
1496      list_for_each_entry(l, &conf->arch_list.head, node) {
1497           nv_pair_t *nv = (nv_pair_t *)l->data;
1498           printf("arch %s %s\n", nv->name, nv->value);
1499      }
1500      return 0;
1501 }
1502
1503