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