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