Removed a bunch of if(0) and dead code
[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 = xcalloc(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      opkg_configure_packages(conf, NULL);
572
573      write_status_files_if_changed(conf);
574
575      return err;
576 }
577
578 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv)
579 {
580      int i;
581      pkg_t *pkg;
582      int err;
583
584      global_conf = conf;
585      signal(SIGINT, sigint_handler);
586
587      if (argc) {
588           for (i=0; i < argc; i++) {
589                char *arg = argv[i];
590
591                err = opkg_prepare_url_for_install(conf, arg, &arg);
592                if (err != EINVAL && err != 0)
593                    return err;
594           }
595           pkg_info_preinstall_check(conf);
596
597           for (i=0; i < argc; i++) {
598                char *arg = argv[i];
599                if (conf->restrict_to_default_dest) {
600                     pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
601                                                                 argv[i],
602                                                                 conf->default_dest);
603                     if (pkg == NULL) {
604                          opkg_message(conf, OPKG_NOTICE,
605                                       "Package %s not installed in %s\n",
606                                       argv[i], conf->default_dest->name);
607                          continue;
608                     }
609                } else {
610                     pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
611                                                            argv[i]);
612                }
613                if (pkg)
614                     opkg_upgrade_pkg(conf, pkg);
615                else {
616                     opkg_install_by_name(conf, arg);
617                }
618           }
619      } else {
620           pkg_vec_t *installed = pkg_vec_alloc();
621
622           pkg_info_preinstall_check(conf);
623
624           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
625           for (i = 0; i < installed->len; i++) {
626                pkg = installed->pkgs[i];
627                opkg_upgrade_pkg(conf, pkg);
628           }
629           pkg_vec_free(installed);
630      }
631
632      opkg_configure_packages(conf, NULL);
633
634      write_status_files_if_changed(conf);
635
636      return 0;
637 }
638
639 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv)
640 {
641      int i, err;
642      char *arg;
643      pkg_t *pkg;
644
645      pkg_info_preinstall_check(conf);
646      for (i = 0; i < argc; i++) {
647           arg = argv[i];
648
649           pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, arg, &err);
650           if (pkg == NULL) {
651                opkg_message(conf, OPKG_ERROR,
652                             "Cannot find package %s.\n"
653                             "Check the spelling or perhaps run 'opkg update'\n",
654                             arg);
655                continue;
656           }
657
658           err = opkg_download_pkg(conf, pkg, ".");
659
660           if (err) {
661                opkg_message(conf, OPKG_ERROR,
662                             "Failed to download %s\n", pkg->name);
663           } else {
664                opkg_message(conf, OPKG_NOTICE,
665                             "Downloaded %s as %s\n",
666                             pkg->name, pkg->local_filename);
667           }
668      }
669
670      return 0;
671 }
672
673
674 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv)
675 {
676      int i;
677      pkg_vec_t *available;
678      pkg_t *pkg;
679      char *pkg_name = NULL;
680
681      if (argc > 0) {
682           pkg_name = argv[0];
683      }
684      available = pkg_vec_alloc();
685      pkg_hash_fetch_available(&conf->pkg_hash, available);
686      pkg_vec_sort(available, pkg_compare_names);
687      for (i=0; i < available->len; i++) {
688           pkg = available->pkgs[i];
689           /* if we have package name or pattern and pkg does not match, then skip it */
690           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
691                continue;
692           print_pkg(pkg);
693      }
694      pkg_vec_free(available);
695
696      return 0;
697 }
698
699
700 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
701 {
702      int i ;
703      pkg_vec_t *available;
704      pkg_t *pkg;
705      char *pkg_name = NULL;
706
707      if (argc > 0) {
708           pkg_name = argv[0];
709      }
710      available = pkg_vec_alloc();
711      pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
712      pkg_vec_sort(available, pkg_compare_names);
713      for (i=0; i < available->len; i++) {
714           pkg = available->pkgs[i];
715           /* if we have package name or pattern and pkg does not match, then skip it */
716           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
717                continue;
718           print_pkg(pkg);
719      }
720
721      pkg_vec_free(available);
722
723      return 0;
724 }
725
726 static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv) 
727 {
728     struct active_list *head = prepare_upgrade_list(conf);
729     struct active_list *node=NULL;
730     pkg_t *_old_pkg, *_new_pkg;
731     char *old_v, *new_v;
732     for (node = active_list_next(head, head); node;node = active_list_next(head,node)) {
733         _old_pkg = list_entry(node, pkg_t, list);
734         _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, _old_pkg->name, NULL);
735         old_v = pkg_version_str_alloc(_old_pkg);
736         new_v = pkg_version_str_alloc(_new_pkg);
737         printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
738         free(old_v);
739         free(new_v);
740     }
741     active_list_head_delete(head);
742     return 0;
743 }
744
745 static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int installed_only)
746 {
747      int i;
748      pkg_vec_t *available;
749      pkg_t *pkg;
750      char *pkg_name = NULL;
751
752      if (argc > 0) {
753           pkg_name = argv[0];
754      }
755
756      available = pkg_vec_alloc();
757      if (installed_only)
758           pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
759      else
760           pkg_hash_fetch_available(&conf->pkg_hash, available);
761
762      for (i=0; i < available->len; i++) {
763           pkg = available->pkgs[i];
764           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
765                continue;
766           }
767
768           pkg_formatted_info(stdout, pkg);
769
770           if (conf->verbosity > 1) {
771                conffile_list_elt_t *iter;
772                for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
773                     conffile_t *cf = (conffile_t *)iter->data;
774                     int modified = conffile_has_been_modified(conf, cf);
775                     if (cf->value)
776                         opkg_message(conf, OPKG_NOTICE,
777                                 "conffile=%s md5sum=%s modified=%d\n",
778                                  cf->name, cf->value, modified);
779                }
780           }
781      }
782      pkg_vec_free(available);
783
784      return 0;
785 }
786
787 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv)
788 {
789      return opkg_info_status_cmd(conf, argc, argv, 0);
790 }
791
792 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv)
793 {
794      return opkg_info_status_cmd(conf, argc, argv, 1);
795 }
796
797 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv)
798 {
799      
800      int err;
801      if (argc > 0) {
802           char *pkg_name = NULL;
803
804           pkg_name = argv[0];
805
806           err = opkg_configure_packages (conf, pkg_name);
807      
808      } else {
809           err = opkg_configure_packages (conf, NULL);
810      }
811
812      write_status_files_if_changed(conf);
813
814      return err;
815 }
816
817 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv)
818 {
819      int i, err;
820      char *globpattern;
821      glob_t globbuf;
822     
823      sprintf_alloc(&globpattern, "%s/*" OPKG_PKG_EXTENSION, conf->pending_dir);
824      err = glob(globpattern, 0, NULL, &globbuf);
825      free(globpattern);
826      if (err) {
827           return 0;
828      }
829
830      opkg_message(conf, OPKG_NOTICE,
831                   "The following packages in %s will now be installed.\n",
832                   conf->pending_dir);
833      for (i = 0; i < globbuf.gl_pathc; i++) {
834           opkg_message(conf, OPKG_NOTICE,
835                        "%s%s", i == 0 ? "" : " ", globbuf.gl_pathv[i]);
836      }
837      opkg_message(conf, OPKG_NOTICE, "\n");
838      for (i = 0; i < globbuf.gl_pathc; i++) {
839           err = opkg_install_from_file(conf, globbuf.gl_pathv[i]);
840           if (err == 0) {
841                err = unlink(globbuf.gl_pathv[i]);
842                if (err) {
843                     opkg_message(conf, OPKG_ERROR,
844                                  "%s: ERROR: failed to unlink %s: %s\n",
845                                  __FUNCTION__, globbuf.gl_pathv[i], strerror(err));
846                     return err;
847                }
848           }
849      }
850      globfree(&globbuf);
851
852      return err;
853 }
854
855 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv)
856 {
857      int i,a,done;
858      pkg_t *pkg;
859      pkg_t *pkg_to_remove;
860      pkg_vec_t *available;
861      char *pkg_name = NULL;
862      global_conf = conf;
863      signal(SIGINT, sigint_handler);
864
865 // ENH: Add the "no pkg removed" just in case.
866
867     done = 0;
868
869      pkg_info_preinstall_check(conf);
870      if ( argc > 0 ) {
871         available = pkg_vec_alloc();
872         pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
873         for (i=0; i < argc; i++) {
874            pkg_name = xcalloc(1, strlen(argv[i])+2);
875            strcpy(pkg_name,argv[i]);
876            for (a=0; a < available->len; a++) {
877                pkg = available->pkgs[a];
878                if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
879                   continue;
880                }
881                if (conf->restrict_to_default_dest) {
882                     pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
883                                                                 pkg->name,
884                                                                 conf->default_dest);
885                } else {
886                     pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
887                }
888         
889                if (pkg_to_remove == NULL) {
890                     opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
891                     continue;
892                }
893                if (pkg->state_status == SS_NOT_INSTALLED) {    // Added the control, so every already removed package could be skipped
894                     opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
895                     continue;
896                }
897                opkg_remove_pkg(conf, pkg_to_remove,0);
898                done = 1;
899            }
900            free (pkg_name);
901         }
902         pkg_vec_free(available);
903      } else {
904           pkg_vec_t *installed_pkgs = pkg_vec_alloc();
905           int i;
906           int flagged_pkg_count = 0;
907           int removed;
908
909           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed_pkgs);
910
911           for (i = 0; i < installed_pkgs->len; i++) {
912                pkg_t *pkg = installed_pkgs->pkgs[i];
913                if (pkg->state_flag & SF_USER) {
914                     flagged_pkg_count++;
915                } else {
916                     if (!pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL))
917                          opkg_message(conf, OPKG_NOTICE, "Non-user leaf package: %s\n", pkg->name);
918                }
919           }
920           if (!flagged_pkg_count) {
921                opkg_message(conf, OPKG_NOTICE, "No packages flagged as installed by user, \n"
922                             "so refusing to uninstall unflagged non-leaf packages\n");
923                return 0;
924           }
925
926           /* find packages not flagged SF_USER (i.e., installed to
927            * satisfy a dependence) and not having any dependents, and
928            * remove them */
929           do {
930                removed = 0;
931                for (i = 0; i < installed_pkgs->len; i++) {
932                     pkg_t *pkg = installed_pkgs->pkgs[i];
933                     if (!(pkg->state_flag & SF_USER)
934                         && !pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL)) {
935                          removed++;
936                          opkg_message(conf, OPKG_NOTICE, "Removing non-user leaf package %s\n");
937                          opkg_remove_pkg(conf, pkg,0);
938                          done = 1;
939                     }
940                }
941           } while (removed);
942           pkg_vec_free(installed_pkgs);
943      }
944
945      if ( done == 0 ) 
946         opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
947
948      write_status_files_if_changed(conf);
949      return 0;
950 }
951
952 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv)
953 {
954      int i;
955      pkg_t *pkg;
956
957      global_conf = conf;
958      signal(SIGINT, sigint_handler);
959
960      pkg_info_preinstall_check(conf);
961
962      for (i=0; i < argc; i++) {
963           if (conf->restrict_to_default_dest) {
964                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
965                                                            argv[i],
966                                                            conf->default_dest);
967           } else {
968                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
969           }
970
971           if (pkg == NULL) {
972                opkg_message(conf, OPKG_ERROR,
973                             "Package %s is not installed.\n", argv[i]);
974                continue;
975           }
976           opkg_purge_pkg(conf, pkg);
977      }
978
979      write_status_files_if_changed(conf);
980      return 0;
981 }
982
983 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
984 {
985      int i;
986      pkg_t *pkg;
987      const char *flags = argv[0];
988     
989      global_conf = conf;
990      signal(SIGINT, sigint_handler);
991
992      for (i=1; i < argc; i++) {
993           if (conf->restrict_to_default_dest) {
994                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
995                                                            argv[i],
996                                                            conf->default_dest);
997           } else {
998                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
999           }
1000
1001           if (pkg == NULL) {
1002                opkg_message(conf, OPKG_ERROR,
1003                             "Package %s is not installed.\n", argv[i]);
1004                continue;
1005           }
1006           if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
1007               ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
1008               pkg->state_flag = pkg_state_flag_from_str(flags);
1009           }
1010 /* pb_ asked this feature 03292004 */
1011 /* Actually I will use only this two, but this is an open for various status */
1012           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
1013               pkg->state_status = pkg_state_status_from_str(flags);
1014           }
1015           opkg_state_changed++;
1016           opkg_message(conf, OPKG_NOTICE,
1017                        "Setting flags for package %s to %s\n",
1018                        pkg->name, flags);
1019      }
1020
1021      write_status_files_if_changed(conf);
1022      return 0;
1023 }
1024
1025 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
1026 {
1027      pkg_t *pkg;
1028      str_list_t *files;
1029      str_list_elt_t *iter;
1030      char *pkg_version;
1031
1032      if (argc < 1) {
1033           return EINVAL;
1034      }
1035
1036      pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
1037                                             argv[0]);
1038      if (pkg == NULL) {
1039           opkg_message(conf, OPKG_ERROR,
1040                        "Package %s not installed.\n", argv[0]);
1041           return 0;
1042      }
1043
1044      files = pkg_get_installed_files(pkg);
1045      pkg_version = pkg_version_str_alloc(pkg);
1046
1047      printf("Package %s (%s) is installed on %s and has the following files:\n",
1048                 pkg->name, pkg_version, pkg->dest->name);
1049
1050      for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
1051           printf("%s\n", (char *)iter->data);
1052
1053      free(pkg_version);
1054      pkg_free_installed_files(pkg);
1055
1056      return 0;
1057 }
1058
1059 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
1060 {
1061
1062      if (argc > 0) {
1063           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1064           const char *rel_str = "depends on";
1065           int i;
1066      
1067           pkg_info_preinstall_check(conf);
1068
1069           if (conf->query_all)
1070                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1071           else
1072                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1073           for (i = 0; i < argc; i++) {
1074                const char *target = argv[i];
1075                int j;
1076
1077                opkg_message(conf, OPKG_ERROR, "target=%s\n", target);
1078
1079                for (j = 0; j < available_pkgs->len; j++) {
1080                     pkg_t *pkg = available_pkgs->pkgs[j];
1081                     if (fnmatch(target, pkg->name, 0) == 0) {
1082                          int k;
1083                          int count = pkg->depends_count + pkg->pre_depends_count;
1084                          opkg_message(conf, OPKG_ERROR, "What %s (arch=%s) %s\n",
1085                                       target, pkg->architecture, rel_str);
1086                          for (k = 0; k < count; k++) {
1087                               compound_depend_t *cdepend = &pkg->depends[k];
1088                               int l;
1089                               for (l = 0; l < cdepend->possibility_count; l++) {
1090                                    depend_t *possibility = cdepend->possibilities[l];
1091                                    opkg_message(conf, OPKG_ERROR, "    %s", possibility->pkg->name);
1092                                    if (conf->verbosity > 0) {
1093                                         // char *ver = abstract_pkg_version_str_alloc(possibility->pkg); 
1094                                         opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
1095                                         if (possibility->version) {
1096                                              char *typestr = NULL;
1097                                              switch (possibility->constraint) {
1098                                              case NONE: typestr = "none"; break;
1099                                              case EARLIER: typestr = "<"; break;
1100                                              case EARLIER_EQUAL: typestr = "<="; break;
1101                                              case EQUAL: typestr = "="; break;
1102                                              case LATER_EQUAL: typestr = ">="; break;
1103                                              case LATER: typestr = ">"; break;
1104                                              }
1105                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1106                                         }
1107                                         // free(ver);
1108                                    }
1109                                    opkg_message(conf, OPKG_ERROR, "\n");
1110                               }
1111                          }
1112                     }
1113                }
1114           }
1115           pkg_vec_free(available_pkgs);
1116      }
1117      return 0;
1118 }
1119
1120 enum what_field_type {
1121   WHATDEPENDS,
1122   WHATCONFLICTS,
1123   WHATPROVIDES,
1124   WHATREPLACES,
1125   WHATRECOMMENDS,
1126   WHATSUGGESTS
1127 };
1128
1129 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int recursive, int argc, char **argv)
1130 {
1131
1132      if (argc > 0) {
1133           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1134           const char *rel_str = NULL;
1135           int i;
1136           int changed;
1137
1138           switch (what_field_type) {
1139           case WHATDEPENDS: rel_str = "depends on"; break;
1140           case WHATCONFLICTS: rel_str = "conflicts with"; break;
1141           case WHATSUGGESTS: rel_str = "suggests"; break;
1142           case WHATRECOMMENDS: rel_str = "recommends"; break;
1143           case WHATPROVIDES: rel_str = "provides"; break;
1144           case WHATREPLACES: rel_str = "replaces"; break;
1145           }
1146      
1147           if (conf->query_all)
1148                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1149           else
1150                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1151
1152           /* mark the root set */
1153           pkg_vec_clear_marks(available_pkgs);
1154           opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1155           for (i = 0; i < argc; i++) {
1156                const char *dependee_pattern = argv[i];
1157                pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1158           }
1159           for (i = 0; i < available_pkgs->len; i++) {
1160                pkg_t *pkg = available_pkgs->pkgs[i];
1161                if (pkg->state_flag & SF_MARKED) {
1162                     /* mark the parent (abstract) package */
1163                     pkg_mark_provides(pkg);
1164                     opkg_message(conf, OPKG_NOTICE, "  %s\n", pkg->name);
1165                }
1166           }
1167
1168           opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1169           do {
1170                int j;
1171                changed = 0;
1172
1173                for (j = 0; j < available_pkgs->len; j++) {
1174                     pkg_t *pkg = available_pkgs->pkgs[j];
1175                     int k;
1176                     int count = ((what_field_type == WHATCONFLICTS)
1177                                  ? pkg->conflicts_count
1178                                  : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1179                     /* skip this package if it is already marked */
1180                     if (pkg->parent->state_flag & SF_MARKED) {
1181                          continue;
1182                     }
1183                     for (k = 0; k < count; k++) {
1184                          compound_depend_t *cdepend = 
1185                               (what_field_type == WHATCONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1186                          int l;
1187                          for (l = 0; l < cdepend->possibility_count; l++) {
1188                               depend_t *possibility = cdepend->possibilities[l];
1189                               if (possibility->pkg->state_flag & SF_MARKED) {
1190                                    /* mark the depending package so we won't visit it again */
1191                                    pkg->state_flag |= SF_MARKED;
1192                                    pkg_mark_provides(pkg);
1193                                    changed++;
1194
1195                                    opkg_message(conf, OPKG_NOTICE, "    %s", pkg->name);
1196                                    if (conf->verbosity > 0) {
1197                                         char *ver = pkg_version_str_alloc(pkg); 
1198                                         opkg_message(conf, OPKG_NOTICE, " %s", ver);
1199                                         opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1200                                         if (possibility->version) {
1201                                              char *typestr = NULL;
1202                                              switch (possibility->constraint) {
1203                                              case NONE: typestr = "none"; break;
1204                                              case EARLIER: typestr = "<"; break;
1205                                              case EARLIER_EQUAL: typestr = "<="; break;
1206                                              case EQUAL: typestr = "="; break;
1207                                              case LATER_EQUAL: typestr = ">="; break;
1208                                              case LATER: typestr = ">"; break;
1209                                              }
1210                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1211                                         }
1212                                         free(ver);
1213                                         if (!pkg_dependence_satisfiable(conf, possibility))
1214                                              opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1215                                    }
1216                                    opkg_message(conf, OPKG_NOTICE, "\n");
1217                                    goto next_package;
1218                               }
1219                          }
1220                     }
1221                next_package:
1222                     ;
1223                }
1224           } while (changed && recursive);
1225           pkg_vec_free(available_pkgs);
1226      }
1227
1228      return 0;
1229 }
1230
1231 static int pkg_mark_provides(pkg_t *pkg)
1232 {
1233      int provides_count = pkg->provides_count;
1234      abstract_pkg_t **provides = pkg->provides;
1235      int i;
1236      pkg->parent->state_flag |= SF_MARKED;
1237      for (i = 0; i < provides_count; i++) {
1238           provides[i]->state_flag |= SF_MARKED;
1239      }
1240      return 0;
1241 }
1242
1243 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1244 {
1245      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 1, argc, argv);
1246 }
1247 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1248 {
1249      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 0, argc, argv);
1250 }
1251
1252 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1253 {
1254      return opkg_what_depends_conflicts_cmd(conf, WHATSUGGESTS, 0, argc, argv);
1255 }
1256
1257 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1258 {
1259      return opkg_what_depends_conflicts_cmd(conf, WHATRECOMMENDS, 0, argc, argv);
1260 }
1261
1262 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1263 {
1264      return opkg_what_depends_conflicts_cmd(conf, WHATCONFLICTS, 0, argc, argv);
1265 }
1266
1267 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1268 {
1269
1270      if (argc > 0) {
1271           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1272           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1273           int i;
1274      
1275           pkg_info_preinstall_check(conf);
1276
1277           if (conf->query_all)
1278                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1279           else
1280                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1281           for (i = 0; i < argc; i++) {
1282                const char *target = argv[i];
1283                int j;
1284
1285                opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1286                             rel_str, target);
1287                for (j = 0; j < available_pkgs->len; j++) {
1288                     pkg_t *pkg = available_pkgs->pkgs[j];
1289                     int k;
1290                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1291                     for (k = 0; k < count; k++) {
1292                          abstract_pkg_t *apkg = 
1293                               ((what_field_type == WHATPROVIDES) 
1294                                ? pkg->provides[k]
1295                                : pkg->replaces[k]);
1296                          if (fnmatch(target, apkg->name, 0) == 0) {
1297                               opkg_message(conf, OPKG_ERROR, "    %s", pkg->name);
1298                               if (strcmp(target, apkg->name) != 0)
1299                                    opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1300                               opkg_message(conf, OPKG_ERROR, "\n");
1301                          }
1302                     }
1303                }
1304           }
1305           pkg_vec_free(available_pkgs);
1306      }
1307      return 0;
1308 }
1309
1310 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1311 {
1312      return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1313 }
1314
1315 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1316 {
1317      return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1318 }
1319
1320 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1321 {
1322      int i;
1323
1324      pkg_vec_t *installed;
1325      pkg_t *pkg;
1326      str_list_t *installed_files;
1327      str_list_elt_t *iter;
1328      char *installed_file;
1329
1330      if (argc < 1) {
1331           return EINVAL;
1332      }
1333  
1334      installed = pkg_vec_alloc();
1335      pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1336      pkg_vec_sort(installed, pkg_compare_names);
1337
1338      for (i=0; i < installed->len; i++) {
1339           pkg = installed->pkgs[i];
1340
1341           installed_files = pkg_get_installed_files(pkg);
1342
1343           for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1344                installed_file = (char *)iter->data;
1345                if (fnmatch(argv[0], installed_file, 0)==0)
1346                     print_pkg(pkg);
1347           }
1348
1349           pkg_free_installed_files(pkg);
1350      }
1351
1352      pkg_vec_free(installed);
1353
1354      return 0;
1355 }
1356
1357 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1358 {
1359      if (argc == 3) {
1360           /* this is a bit gross */
1361           struct pkg p1, p2;
1362           parseVersion(&p1, argv[0]); 
1363           parseVersion(&p2, argv[2]); 
1364           return pkg_version_satisfied(&p1, &p2, argv[1]);
1365      } else {
1366           opkg_message(conf, OPKG_ERROR,
1367                        "opkg compare_versions <v1> <op> <v2>\n"
1368                        "<op> is one of <= >= << >> =\n");
1369           return -1;
1370      }
1371 }
1372
1373 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1374 {
1375      nv_pair_list_elt_t *l;
1376
1377      list_for_each_entry(l, &conf->arch_list.head, node) {
1378           nv_pair_t *nv = (nv_pair_t *)l->data;
1379           printf("arch %s %s\n", nv->name, nv->value);
1380      }
1381      return 0;
1382 }