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