Clean up some _cmd functions, in particular remove use of print callbacks.
[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      char *pkg_info; 
767
768      if (argc > 0) {
769           pkg_name = argv[0];
770      }
771
772      available = pkg_vec_alloc();
773      if (installed_only)
774           pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
775      else
776           pkg_hash_fetch_available(&conf->pkg_hash, available);
777
778      for (i=0; i < available->len; i++) {
779           pkg = available->pkgs[i];
780           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
781                continue;
782           }
783
784           pkg_info = pkg_formatted_info(pkg);
785           if (pkg_info == NULL)
786                   break;
787
788           printf("%s\n", pkg_info);
789           free(pkg_info);
790
791           if (conf->verbosity > 1) {
792                conffile_list_elt_t *iter;
793                for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
794                     conffile_t *cf = (conffile_t *)iter->data;
795                     int modified = conffile_has_been_modified(conf, cf);
796                     opkg_message(conf, OPKG_NOTICE, "conffile=%s md5sum=%s modified=%d\n",
797                                  cf->name, cf->value, modified);
798                }
799           }
800      }
801      pkg_vec_free(available);
802
803      return 0;
804 }
805
806 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv)
807 {
808      return opkg_info_status_cmd(conf, argc, argv, 0);
809 }
810
811 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv)
812 {
813      return opkg_info_status_cmd(conf, argc, argv, 1);
814 }
815
816 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv)
817 {
818      
819      int err;
820      if (argc > 0) {
821           char *pkg_name = NULL;
822
823           pkg_name = argv[0];
824
825           err = opkg_configure_packages (conf, pkg_name);
826      
827      } else {
828           err = opkg_configure_packages (conf, NULL);
829      }
830
831      write_status_files_if_changed(conf);
832
833      return err;
834 }
835
836 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv)
837 {
838      int i, err;
839      char *globpattern;
840      glob_t globbuf;
841     
842      sprintf_alloc(&globpattern, "%s/*" OPKG_PKG_EXTENSION, conf->pending_dir);
843      err = glob(globpattern, 0, NULL, &globbuf);
844      free(globpattern);
845      if (err) {
846           return 0;
847      }
848
849      opkg_message(conf, OPKG_NOTICE,
850                   "The following packages in %s will now be installed.\n",
851                   conf->pending_dir);
852      for (i = 0; i < globbuf.gl_pathc; i++) {
853           opkg_message(conf, OPKG_NOTICE,
854                        "%s%s", i == 0 ? "" : " ", globbuf.gl_pathv[i]);
855      }
856      opkg_message(conf, OPKG_NOTICE, "\n");
857      for (i = 0; i < globbuf.gl_pathc; i++) {
858           err = opkg_install_from_file(conf, globbuf.gl_pathv[i]);
859           if (err == 0) {
860                err = unlink(globbuf.gl_pathv[i]);
861                if (err) {
862                     opkg_message(conf, OPKG_ERROR,
863                                  "%s: ERROR: failed to unlink %s: %s\n",
864                                  __FUNCTION__, globbuf.gl_pathv[i], strerror(err));
865                     return err;
866                }
867           }
868      }
869      globfree(&globbuf);
870
871      return err;
872 }
873
874 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv)
875 {
876      int i,a,done;
877      pkg_t *pkg;
878      pkg_t *pkg_to_remove;
879      pkg_vec_t *available;
880      char *pkg_name = NULL;
881      global_conf = conf;
882      signal(SIGINT, sigint_handler);
883
884 // ENH: Add the "no pkg removed" just in case.
885
886     done = 0;
887
888      pkg_info_preinstall_check(conf);
889      if ( argc > 0 ) {
890         available = pkg_vec_alloc();
891         pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
892         for (i=0; i < argc; i++) {
893            pkg_name = calloc(1, strlen(argv[i])+2);
894            strcpy(pkg_name,argv[i]);
895            for (a=0; a < available->len; a++) {
896                pkg = available->pkgs[a];
897                if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
898                   continue;
899                }
900                if (conf->restrict_to_default_dest) {
901                     pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
902                                                                 pkg->name,
903                                                                 conf->default_dest);
904                } else {
905                     pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
906                }
907         
908                if (pkg_to_remove == NULL) {
909                     opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
910                     continue;
911                }
912                if (pkg->state_status == SS_NOT_INSTALLED) {    // Added the control, so every already removed package could be skipped
913                     opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
914                     continue;
915                }
916                opkg_remove_pkg(conf, pkg_to_remove,0);
917                done = 1;
918            }
919            free (pkg_name);
920         }
921         pkg_vec_free(available);
922      } else {
923           pkg_vec_t *installed_pkgs = pkg_vec_alloc();
924           int i;
925           int flagged_pkg_count = 0;
926           int removed;
927
928           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed_pkgs);
929
930           for (i = 0; i < installed_pkgs->len; i++) {
931                pkg_t *pkg = installed_pkgs->pkgs[i];
932                if (pkg->state_flag & SF_USER) {
933                     flagged_pkg_count++;
934                } else {
935                     if (!pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL))
936                          opkg_message(conf, OPKG_NOTICE, "Non-user leaf package: %s\n", pkg->name);
937                }
938           }
939           if (!flagged_pkg_count) {
940                opkg_message(conf, OPKG_NOTICE, "No packages flagged as installed by user, \n"
941                             "so refusing to uninstall unflagged non-leaf packages\n");
942                return 0;
943           }
944
945           /* find packages not flagged SF_USER (i.e., installed to
946            * satisfy a dependence) and not having any dependents, and
947            * remove them */
948           do {
949                removed = 0;
950                for (i = 0; i < installed_pkgs->len; i++) {
951                     pkg_t *pkg = installed_pkgs->pkgs[i];
952                     if (!(pkg->state_flag & SF_USER)
953                         && !pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL)) {
954                          removed++;
955                          opkg_message(conf, OPKG_NOTICE, "Removing non-user leaf package %s\n");
956                          opkg_remove_pkg(conf, pkg,0);
957                          done = 1;
958                     }
959                }
960           } while (removed);
961           pkg_vec_free(installed_pkgs);
962      }
963
964      if ( done == 0 ) 
965         opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
966
967      write_status_files_if_changed(conf);
968      return 0;
969 }
970
971 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv)
972 {
973      int i;
974      pkg_t *pkg;
975
976      global_conf = conf;
977      signal(SIGINT, sigint_handler);
978
979      pkg_info_preinstall_check(conf);
980
981      for (i=0; i < argc; i++) {
982           if (conf->restrict_to_default_dest) {
983                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
984                                                            argv[i],
985                                                            conf->default_dest);
986           } else {
987                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
988           }
989
990           if (pkg == NULL) {
991                opkg_message(conf, OPKG_ERROR,
992                             "Package %s is not installed.\n", argv[i]);
993                continue;
994           }
995           opkg_purge_pkg(conf, pkg);
996      }
997
998      write_status_files_if_changed(conf);
999      return 0;
1000 }
1001
1002 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
1003 {
1004      int i;
1005      pkg_t *pkg;
1006      const char *flags = argv[0];
1007     
1008      global_conf = conf;
1009      signal(SIGINT, sigint_handler);
1010
1011      for (i=1; i < argc; i++) {
1012           if (conf->restrict_to_default_dest) {
1013                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
1014                                                            argv[i],
1015                                                            conf->default_dest);
1016           } else {
1017                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
1018           }
1019
1020           if (pkg == NULL) {
1021                opkg_message(conf, OPKG_ERROR,
1022                             "Package %s is not installed.\n", argv[i]);
1023                continue;
1024           }
1025           if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
1026               ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
1027               pkg->state_flag = pkg_state_flag_from_str(flags);
1028           }
1029 /* pb_ asked this feature 03292004 */
1030 /* Actually I will use only this two, but this is an open for various status */
1031           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
1032               pkg->state_status = pkg_state_status_from_str(flags);
1033           }
1034           opkg_state_changed++;
1035           opkg_message(conf, OPKG_NOTICE,
1036                        "Setting flags for package %s to %s\n",
1037                        pkg->name, flags);
1038      }
1039
1040      write_status_files_if_changed(conf);
1041      return 0;
1042 }
1043
1044 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
1045 {
1046      pkg_t *pkg;
1047      str_list_t *files;
1048      str_list_elt_t *iter;
1049      char *pkg_version;
1050
1051      if (argc < 1) {
1052           return EINVAL;
1053      }
1054
1055      pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
1056                                             argv[0]);
1057      if (pkg == NULL) {
1058           opkg_message(conf, OPKG_ERROR,
1059                        "Package %s not installed.\n", argv[0]);
1060           return 0;
1061      }
1062
1063      files = pkg_get_installed_files(pkg);
1064      pkg_version = pkg_version_str_alloc(pkg);
1065
1066      printf("Package %s (%s) is installed on %s and has the following files:\n",
1067                 pkg->name, pkg_version, pkg->dest->name);
1068
1069      for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
1070           printf("%s\n", (char *)iter->data);
1071
1072      free(pkg_version);
1073      pkg_free_installed_files(pkg);
1074
1075      return 0;
1076 }
1077
1078 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
1079 {
1080
1081      if (argc > 0) {
1082           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1083           const char *rel_str = "depends on";
1084           int i;
1085      
1086           pkg_info_preinstall_check(conf);
1087
1088           if (conf->query_all)
1089                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1090           else
1091                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1092           for (i = 0; i < argc; i++) {
1093                const char *target = argv[i];
1094                int j;
1095
1096                opkg_message(conf, OPKG_ERROR, "target=%s\n", target);
1097
1098                for (j = 0; j < available_pkgs->len; j++) {
1099                     pkg_t *pkg = available_pkgs->pkgs[j];
1100                     if (fnmatch(target, pkg->name, 0) == 0) {
1101                          int k;
1102                          int count = pkg->depends_count + pkg->pre_depends_count;
1103                          opkg_message(conf, OPKG_ERROR, "What %s (arch=%s) %s\n",
1104                                       target, pkg->architecture, rel_str);
1105                          for (k = 0; k < count; k++) {
1106                               compound_depend_t *cdepend = &pkg->depends[k];
1107                               int l;
1108                               for (l = 0; l < cdepend->possibility_count; l++) {
1109                                    depend_t *possibility = cdepend->possibilities[l];
1110                                    opkg_message(conf, OPKG_ERROR, "    %s", possibility->pkg->name);
1111                                    if (conf->verbosity > 0) {
1112                                         // char *ver = abstract_pkg_version_str_alloc(possibility->pkg); 
1113                                         opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
1114                                         if (possibility->version) {
1115                                              char *typestr = NULL;
1116                                              switch (possibility->constraint) {
1117                                              case NONE: typestr = "none"; break;
1118                                              case EARLIER: typestr = "<"; break;
1119                                              case EARLIER_EQUAL: typestr = "<="; break;
1120                                              case EQUAL: typestr = "="; break;
1121                                              case LATER_EQUAL: typestr = ">="; break;
1122                                              case LATER: typestr = ">"; break;
1123                                              }
1124                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1125                                         }
1126                                         // free(ver);
1127                                    }
1128                                    opkg_message(conf, OPKG_ERROR, "\n");
1129                               }
1130                          }
1131                     }
1132                }
1133           }
1134           pkg_vec_free(available_pkgs);
1135      }
1136      return 0;
1137 }
1138
1139 enum what_field_type {
1140   WHATDEPENDS,
1141   WHATCONFLICTS,
1142   WHATPROVIDES,
1143   WHATREPLACES,
1144   WHATRECOMMENDS,
1145   WHATSUGGESTS
1146 };
1147
1148 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int recursive, int argc, char **argv)
1149 {
1150
1151      if (argc > 0) {
1152           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1153           const char *rel_str = NULL;
1154           int i;
1155           int changed;
1156
1157           switch (what_field_type) {
1158           case WHATDEPENDS: rel_str = "depends on"; break;
1159           case WHATCONFLICTS: rel_str = "conflicts with"; break;
1160           case WHATSUGGESTS: rel_str = "suggests"; break;
1161           case WHATRECOMMENDS: rel_str = "recommends"; break;
1162           case WHATPROVIDES: rel_str = "provides"; break;
1163           case WHATREPLACES: rel_str = "replaces"; break;
1164           }
1165      
1166           if (conf->query_all)
1167                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1168           else
1169                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1170
1171           /* mark the root set */
1172           pkg_vec_clear_marks(available_pkgs);
1173           opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1174           for (i = 0; i < argc; i++) {
1175                const char *dependee_pattern = argv[i];
1176                pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1177           }
1178           for (i = 0; i < available_pkgs->len; i++) {
1179                pkg_t *pkg = available_pkgs->pkgs[i];
1180                if (pkg->state_flag & SF_MARKED) {
1181                     /* mark the parent (abstract) package */
1182                     pkg_mark_provides(pkg);
1183                     opkg_message(conf, OPKG_NOTICE, "  %s\n", pkg->name);
1184                }
1185           }
1186
1187           opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1188           do {
1189                int j;
1190                changed = 0;
1191
1192                for (j = 0; j < available_pkgs->len; j++) {
1193                     pkg_t *pkg = available_pkgs->pkgs[j];
1194                     int k;
1195                     int count = ((what_field_type == WHATCONFLICTS)
1196                                  ? pkg->conflicts_count
1197                                  : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1198                     /* skip this package if it is already marked */
1199                     if (pkg->parent->state_flag & SF_MARKED) {
1200                          continue;
1201                     }
1202                     for (k = 0; k < count; k++) {
1203                          compound_depend_t *cdepend = 
1204                               (what_field_type == WHATCONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1205                          int l;
1206                          for (l = 0; l < cdepend->possibility_count; l++) {
1207                               depend_t *possibility = cdepend->possibilities[l];
1208                               if (possibility->pkg->state_flag & SF_MARKED) {
1209                                    /* mark the depending package so we won't visit it again */
1210                                    pkg->state_flag |= SF_MARKED;
1211                                    pkg_mark_provides(pkg);
1212                                    changed++;
1213
1214                                    opkg_message(conf, OPKG_NOTICE, "    %s", pkg->name);
1215                                    if (conf->verbosity > 0) {
1216                                         char *ver = pkg_version_str_alloc(pkg); 
1217                                         opkg_message(conf, OPKG_NOTICE, " %s", ver);
1218                                         opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1219                                         if (possibility->version) {
1220                                              char *typestr = NULL;
1221                                              switch (possibility->constraint) {
1222                                              case NONE: typestr = "none"; break;
1223                                              case EARLIER: typestr = "<"; break;
1224                                              case EARLIER_EQUAL: typestr = "<="; break;
1225                                              case EQUAL: typestr = "="; break;
1226                                              case LATER_EQUAL: typestr = ">="; break;
1227                                              case LATER: typestr = ">"; break;
1228                                              }
1229                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1230                                         }
1231                                         free(ver);
1232                                         if (!pkg_dependence_satisfiable(conf, possibility))
1233                                              opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1234                                    }
1235                                    opkg_message(conf, OPKG_NOTICE, "\n");
1236                                    goto next_package;
1237                               }
1238                          }
1239                     }
1240                next_package:
1241                     ;
1242                }
1243           } while (changed && recursive);
1244           pkg_vec_free(available_pkgs);
1245      }
1246
1247      return 0;
1248 }
1249
1250 static int pkg_mark_provides(pkg_t *pkg)
1251 {
1252      int provides_count = pkg->provides_count;
1253      abstract_pkg_t **provides = pkg->provides;
1254      int i;
1255      pkg->parent->state_flag |= SF_MARKED;
1256      for (i = 0; i < provides_count; i++) {
1257           provides[i]->state_flag |= SF_MARKED;
1258      }
1259      return 0;
1260 }
1261
1262 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1263 {
1264      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 1, argc, argv);
1265 }
1266 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1267 {
1268      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 0, argc, argv);
1269 }
1270
1271 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1272 {
1273      return opkg_what_depends_conflicts_cmd(conf, WHATSUGGESTS, 0, argc, argv);
1274 }
1275
1276 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1277 {
1278      return opkg_what_depends_conflicts_cmd(conf, WHATRECOMMENDS, 0, argc, argv);
1279 }
1280
1281 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1282 {
1283      return opkg_what_depends_conflicts_cmd(conf, WHATCONFLICTS, 0, argc, argv);
1284 }
1285
1286 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1287 {
1288
1289      if (argc > 0) {
1290           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1291           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1292           int i;
1293      
1294           pkg_info_preinstall_check(conf);
1295
1296           if (conf->query_all)
1297                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1298           else
1299                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1300           for (i = 0; i < argc; i++) {
1301                const char *target = argv[i];
1302                int j;
1303
1304                opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1305                             rel_str, target);
1306                for (j = 0; j < available_pkgs->len; j++) {
1307                     pkg_t *pkg = available_pkgs->pkgs[j];
1308                     int k;
1309                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1310                     for (k = 0; k < count; k++) {
1311                          abstract_pkg_t *apkg = 
1312                               ((what_field_type == WHATPROVIDES) 
1313                                ? pkg->provides[k]
1314                                : pkg->replaces[k]);
1315                          if (fnmatch(target, apkg->name, 0) == 0) {
1316                               opkg_message(conf, OPKG_ERROR, "    %s", pkg->name);
1317                               if (strcmp(target, apkg->name) != 0)
1318                                    opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1319                               opkg_message(conf, OPKG_ERROR, "\n");
1320                          }
1321                     }
1322                }
1323           }
1324           pkg_vec_free(available_pkgs);
1325      }
1326      return 0;
1327 }
1328
1329 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1330 {
1331      return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1332 }
1333
1334 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1335 {
1336      return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1337 }
1338
1339 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1340 {
1341      int i;
1342
1343      pkg_vec_t *installed;
1344      pkg_t *pkg;
1345      str_list_t *installed_files;
1346      str_list_elt_t *iter;
1347      char *installed_file;
1348
1349      if (argc < 1) {
1350           return EINVAL;
1351      }
1352  
1353      installed = pkg_vec_alloc();
1354      pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1355      pkg_vec_sort(installed, pkg_compare_names);
1356
1357      for (i=0; i < installed->len; i++) {
1358           pkg = installed->pkgs[i];
1359
1360           installed_files = pkg_get_installed_files(pkg);
1361
1362           for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1363                installed_file = (char *)iter->data;
1364                if (fnmatch(argv[0], installed_file, 0)==0)
1365                     print_pkg(pkg);
1366           }
1367
1368           pkg_free_installed_files(pkg);
1369      }
1370
1371      pkg_vec_free(installed);
1372
1373      return 0;
1374 }
1375
1376 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1377 {
1378      if (argc == 3) {
1379           /* this is a bit gross */
1380           struct pkg p1, p2;
1381           parseVersion(&p1, argv[0]); 
1382           parseVersion(&p2, argv[2]); 
1383           return pkg_version_satisfied(&p1, &p2, argv[1]);
1384      } else {
1385           opkg_message(conf, OPKG_ERROR,
1386                        "opkg compare_versions <v1> <op> <v2>\n"
1387                        "<op> is one of <= >= << >> =\n");
1388           return -1;
1389      }
1390 }
1391
1392 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1393 {
1394      nv_pair_list_elt_t *l;
1395
1396      list_for_each_entry(l, &conf->arch_list.head, node) {
1397           nv_pair_t *nv = (nv_pair_t *)l->data;
1398           printf("arch %s %s\n", nv->name, nv->value);
1399      }
1400      return 0;
1401 }