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