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