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