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