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