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