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