f67a2645152866689a8f8336995ae1c110b78979
[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     char *cmd;
327     DIR *dir;
328     int err = 0;
329
330     setenv ("PATH", ctx->oldpath, 1);
331     free (ctx->oldpath);
332
333     dir = opendir (ctx->statedir);
334     if (dir) {
335         struct dirent *de;
336         while (de = readdir (dir), de != NULL) {
337             char *path;
338
339             if (de->d_name[0] == '.')
340                 continue;
341             
342             sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name);
343             if (access (path, X_OK) == 0) {
344                 xsystem (path);
345             }
346             free (path);
347         }
348         closedir(dir);
349     } else
350         perror (ctx->statedir);
351         
352     sprintf_alloc (&cmd, "rm -rf %s", ctx->statedir);
353     err = xsystem (cmd);
354     free (cmd);
355
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 > 1) {
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      char *pkg_name = NULL;
853      global_conf = conf;
854      signal(SIGINT, sigint_handler);
855
856 // ENH: Add the "no pkg removed" just in case.
857
858     done = 0;
859
860      pkg_info_preinstall_check(conf);
861      if ( argc > 0 ) {
862         available = pkg_vec_alloc();
863         pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
864         for (i=0; i < argc; i++) {
865            pkg_name = xcalloc(1, strlen(argv[i])+2);
866            strcpy(pkg_name,argv[i]);
867            for (a=0; a < available->len; a++) {
868                pkg = available->pkgs[a];
869                if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
870                   continue;
871                }
872                if (conf->restrict_to_default_dest) {
873                     pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
874                                                                 pkg->name,
875                                                                 conf->default_dest);
876                } else {
877                     pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
878                }
879         
880                if (pkg_to_remove == NULL) {
881                     opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
882                     continue;
883                }
884                if (pkg->state_status == SS_NOT_INSTALLED) {    // Added the control, so every already removed package could be skipped
885                     opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
886                     continue;
887                }
888                opkg_remove_pkg(conf, pkg_to_remove,0);
889                done = 1;
890            }
891            free (pkg_name);
892         }
893         pkg_vec_free(available);
894      } else {
895           pkg_vec_t *installed_pkgs = pkg_vec_alloc();
896           int i;
897           int flagged_pkg_count = 0;
898           int removed;
899
900           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed_pkgs);
901
902           for (i = 0; i < installed_pkgs->len; i++) {
903                pkg_t *pkg = installed_pkgs->pkgs[i];
904                if (pkg->state_flag & SF_USER) {
905                     flagged_pkg_count++;
906                } else {
907                     if (!pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL))
908                          opkg_message(conf, OPKG_NOTICE, "Non-user leaf package: %s\n", pkg->name);
909                }
910           }
911           if (!flagged_pkg_count) {
912                opkg_message(conf, OPKG_NOTICE, "No packages flagged as installed by user, \n"
913                             "so refusing to uninstall unflagged non-leaf packages\n");
914                return 0;
915           }
916
917           /* find packages not flagged SF_USER (i.e., installed to
918            * satisfy a dependence) and not having any dependents, and
919            * remove them */
920           do {
921                removed = 0;
922                for (i = 0; i < installed_pkgs->len; i++) {
923                     pkg_t *pkg = installed_pkgs->pkgs[i];
924                     if (!(pkg->state_flag & SF_USER)
925                         && !pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL)) {
926                          removed++;
927                          opkg_message(conf, OPKG_NOTICE, "Removing non-user leaf package %s\n");
928                          opkg_remove_pkg(conf, pkg,0);
929                          done = 1;
930                     }
931                }
932           } while (removed);
933           pkg_vec_free(installed_pkgs);
934      }
935
936      if ( done == 0 ) 
937         opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
938
939      write_status_files_if_changed(conf);
940      return 0;
941 }
942
943 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv)
944 {
945      int i;
946      pkg_t *pkg;
947
948      global_conf = conf;
949      signal(SIGINT, sigint_handler);
950
951      pkg_info_preinstall_check(conf);
952
953      for (i=0; i < argc; i++) {
954           if (conf->restrict_to_default_dest) {
955                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
956                                                            argv[i],
957                                                            conf->default_dest);
958           } else {
959                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
960           }
961
962           if (pkg == NULL) {
963                opkg_message(conf, OPKG_ERROR,
964                             "Package %s is not installed.\n", argv[i]);
965                continue;
966           }
967           opkg_purge_pkg(conf, pkg);
968      }
969
970      write_status_files_if_changed(conf);
971      return 0;
972 }
973
974 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
975 {
976      int i;
977      pkg_t *pkg;
978      const char *flags = argv[0];
979     
980      global_conf = conf;
981      signal(SIGINT, sigint_handler);
982
983      for (i=1; i < argc; i++) {
984           if (conf->restrict_to_default_dest) {
985                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
986                                                            argv[i],
987                                                            conf->default_dest);
988           } else {
989                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
990           }
991
992           if (pkg == NULL) {
993                opkg_message(conf, OPKG_ERROR,
994                             "Package %s is not installed.\n", argv[i]);
995                continue;
996           }
997           if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
998               ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
999               pkg->state_flag = pkg_state_flag_from_str(flags);
1000           }
1001 /* pb_ asked this feature 03292004 */
1002 /* Actually I will use only this two, but this is an open for various status */
1003           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
1004               pkg->state_status = pkg_state_status_from_str(flags);
1005           }
1006           opkg_state_changed++;
1007           opkg_message(conf, OPKG_NOTICE,
1008                        "Setting flags for package %s to %s\n",
1009                        pkg->name, flags);
1010      }
1011
1012      write_status_files_if_changed(conf);
1013      return 0;
1014 }
1015
1016 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
1017 {
1018      pkg_t *pkg;
1019      str_list_t *files;
1020      str_list_elt_t *iter;
1021      char *pkg_version;
1022
1023      if (argc < 1) {
1024           return EINVAL;
1025      }
1026
1027      pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
1028                                             argv[0]);
1029      if (pkg == NULL) {
1030           opkg_message(conf, OPKG_ERROR,
1031                        "Package %s not installed.\n", argv[0]);
1032           return 0;
1033      }
1034
1035      files = pkg_get_installed_files(pkg);
1036      pkg_version = pkg_version_str_alloc(pkg);
1037
1038      printf("Package %s (%s) is installed on %s and has the following files:\n",
1039                 pkg->name, pkg_version, pkg->dest->name);
1040
1041      for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
1042           printf("%s\n", (char *)iter->data);
1043
1044      free(pkg_version);
1045      pkg_free_installed_files(pkg);
1046
1047      return 0;
1048 }
1049
1050 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
1051 {
1052
1053      if (argc > 0) {
1054           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1055           const char *rel_str = "depends on";
1056           int i;
1057      
1058           pkg_info_preinstall_check(conf);
1059
1060           if (conf->query_all)
1061                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1062           else
1063                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1064           for (i = 0; i < argc; i++) {
1065                const char *target = argv[i];
1066                int j;
1067
1068                opkg_message(conf, OPKG_ERROR, "target=%s\n", target);
1069
1070                for (j = 0; j < available_pkgs->len; j++) {
1071                     pkg_t *pkg = available_pkgs->pkgs[j];
1072                     if (fnmatch(target, pkg->name, 0) == 0) {
1073                          int k;
1074                          int count = pkg->depends_count + pkg->pre_depends_count;
1075                          opkg_message(conf, OPKG_ERROR, "What %s (arch=%s) %s\n",
1076                                       target, pkg->architecture, rel_str);
1077                          for (k = 0; k < count; k++) {
1078                               compound_depend_t *cdepend = &pkg->depends[k];
1079                               int l;
1080                               for (l = 0; l < cdepend->possibility_count; l++) {
1081                                    depend_t *possibility = cdepend->possibilities[l];
1082                                    opkg_message(conf, OPKG_ERROR, "    %s", possibility->pkg->name);
1083                                    if (conf->verbosity > 0) {
1084                                         // char *ver = abstract_pkg_version_str_alloc(possibility->pkg); 
1085                                         opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
1086                                         if (possibility->version) {
1087                                              char *typestr = NULL;
1088                                              switch (possibility->constraint) {
1089                                              case NONE: typestr = "none"; break;
1090                                              case EARLIER: typestr = "<"; break;
1091                                              case EARLIER_EQUAL: typestr = "<="; break;
1092                                              case EQUAL: typestr = "="; break;
1093                                              case LATER_EQUAL: typestr = ">="; break;
1094                                              case LATER: typestr = ">"; break;
1095                                              }
1096                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1097                                         }
1098                                         // free(ver);
1099                                    }
1100                                    opkg_message(conf, OPKG_ERROR, "\n");
1101                               }
1102                          }
1103                     }
1104                }
1105           }
1106           pkg_vec_free(available_pkgs);
1107      }
1108      return 0;
1109 }
1110
1111 enum what_field_type {
1112   WHATDEPENDS,
1113   WHATCONFLICTS,
1114   WHATPROVIDES,
1115   WHATREPLACES,
1116   WHATRECOMMENDS,
1117   WHATSUGGESTS
1118 };
1119
1120 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int recursive, int argc, char **argv)
1121 {
1122
1123      if (argc > 0) {
1124           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1125           const char *rel_str = NULL;
1126           int i;
1127           int changed;
1128
1129           switch (what_field_type) {
1130           case WHATDEPENDS: rel_str = "depends on"; break;
1131           case WHATCONFLICTS: rel_str = "conflicts with"; break;
1132           case WHATSUGGESTS: rel_str = "suggests"; break;
1133           case WHATRECOMMENDS: rel_str = "recommends"; break;
1134           case WHATPROVIDES: rel_str = "provides"; break;
1135           case WHATREPLACES: rel_str = "replaces"; break;
1136           }
1137      
1138           if (conf->query_all)
1139                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1140           else
1141                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1142
1143           /* mark the root set */
1144           pkg_vec_clear_marks(available_pkgs);
1145           opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1146           for (i = 0; i < argc; i++) {
1147                const char *dependee_pattern = argv[i];
1148                pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1149           }
1150           for (i = 0; i < available_pkgs->len; i++) {
1151                pkg_t *pkg = available_pkgs->pkgs[i];
1152                if (pkg->state_flag & SF_MARKED) {
1153                     /* mark the parent (abstract) package */
1154                     pkg_mark_provides(pkg);
1155                     opkg_message(conf, OPKG_NOTICE, "  %s\n", pkg->name);
1156                }
1157           }
1158
1159           opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1160           do {
1161                int j;
1162                changed = 0;
1163
1164                for (j = 0; j < available_pkgs->len; j++) {
1165                     pkg_t *pkg = available_pkgs->pkgs[j];
1166                     int k;
1167                     int count = ((what_field_type == WHATCONFLICTS)
1168                                  ? pkg->conflicts_count
1169                                  : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1170                     /* skip this package if it is already marked */
1171                     if (pkg->parent->state_flag & SF_MARKED) {
1172                          continue;
1173                     }
1174                     for (k = 0; k < count; k++) {
1175                          compound_depend_t *cdepend = 
1176                               (what_field_type == WHATCONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1177                          int l;
1178                          for (l = 0; l < cdepend->possibility_count; l++) {
1179                               depend_t *possibility = cdepend->possibilities[l];
1180                               if (possibility->pkg->state_flag & SF_MARKED) {
1181                                    /* mark the depending package so we won't visit it again */
1182                                    pkg->state_flag |= SF_MARKED;
1183                                    pkg_mark_provides(pkg);
1184                                    changed++;
1185
1186                                    opkg_message(conf, OPKG_NOTICE, "    %s", pkg->name);
1187                                    if (conf->verbosity > 0) {
1188                                         char *ver = pkg_version_str_alloc(pkg); 
1189                                         opkg_message(conf, OPKG_NOTICE, " %s", ver);
1190                                         opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1191                                         if (possibility->version) {
1192                                              char *typestr = NULL;
1193                                              switch (possibility->constraint) {
1194                                              case NONE: typestr = "none"; break;
1195                                              case EARLIER: typestr = "<"; break;
1196                                              case EARLIER_EQUAL: typestr = "<="; break;
1197                                              case EQUAL: typestr = "="; break;
1198                                              case LATER_EQUAL: typestr = ">="; break;
1199                                              case LATER: typestr = ">"; break;
1200                                              }
1201                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1202                                         }
1203                                         free(ver);
1204                                         if (!pkg_dependence_satisfiable(conf, possibility))
1205                                              opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1206                                    }
1207                                    opkg_message(conf, OPKG_NOTICE, "\n");
1208                                    goto next_package;
1209                               }
1210                          }
1211                     }
1212                next_package:
1213                     ;
1214                }
1215           } while (changed && recursive);
1216           pkg_vec_free(available_pkgs);
1217      }
1218
1219      return 0;
1220 }
1221
1222 static int pkg_mark_provides(pkg_t *pkg)
1223 {
1224      int provides_count = pkg->provides_count;
1225      abstract_pkg_t **provides = pkg->provides;
1226      int i;
1227      pkg->parent->state_flag |= SF_MARKED;
1228      for (i = 0; i < provides_count; i++) {
1229           provides[i]->state_flag |= SF_MARKED;
1230      }
1231      return 0;
1232 }
1233
1234 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1235 {
1236      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 1, argc, argv);
1237 }
1238 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1239 {
1240      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 0, argc, argv);
1241 }
1242
1243 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1244 {
1245      return opkg_what_depends_conflicts_cmd(conf, WHATSUGGESTS, 0, argc, argv);
1246 }
1247
1248 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1249 {
1250      return opkg_what_depends_conflicts_cmd(conf, WHATRECOMMENDS, 0, argc, argv);
1251 }
1252
1253 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1254 {
1255      return opkg_what_depends_conflicts_cmd(conf, WHATCONFLICTS, 0, argc, argv);
1256 }
1257
1258 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1259 {
1260
1261      if (argc > 0) {
1262           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1263           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1264           int i;
1265      
1266           pkg_info_preinstall_check(conf);
1267
1268           if (conf->query_all)
1269                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1270           else
1271                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1272           for (i = 0; i < argc; i++) {
1273                const char *target = argv[i];
1274                int j;
1275
1276                opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1277                             rel_str, target);
1278                for (j = 0; j < available_pkgs->len; j++) {
1279                     pkg_t *pkg = available_pkgs->pkgs[j];
1280                     int k;
1281                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1282                     for (k = 0; k < count; k++) {
1283                          abstract_pkg_t *apkg = 
1284                               ((what_field_type == WHATPROVIDES) 
1285                                ? pkg->provides[k]
1286                                : pkg->replaces[k]);
1287                          if (fnmatch(target, apkg->name, 0) == 0) {
1288                               opkg_message(conf, OPKG_ERROR, "    %s", pkg->name);
1289                               if (strcmp(target, apkg->name) != 0)
1290                                    opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1291                               opkg_message(conf, OPKG_ERROR, "\n");
1292                          }
1293                     }
1294                }
1295           }
1296           pkg_vec_free(available_pkgs);
1297      }
1298      return 0;
1299 }
1300
1301 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1302 {
1303      return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1304 }
1305
1306 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1307 {
1308      return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1309 }
1310
1311 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1312 {
1313      int i;
1314
1315      pkg_vec_t *installed;
1316      pkg_t *pkg;
1317      str_list_t *installed_files;
1318      str_list_elt_t *iter;
1319      char *installed_file;
1320
1321      if (argc < 1) {
1322           return EINVAL;
1323      }
1324  
1325      installed = pkg_vec_alloc();
1326      pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1327      pkg_vec_sort(installed, pkg_compare_names);
1328
1329      for (i=0; i < installed->len; i++) {
1330           pkg = installed->pkgs[i];
1331
1332           installed_files = pkg_get_installed_files(pkg);
1333
1334           for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1335                installed_file = (char *)iter->data;
1336                if (fnmatch(argv[0], installed_file, 0)==0)
1337                     print_pkg(pkg);
1338           }
1339
1340           pkg_free_installed_files(pkg);
1341      }
1342
1343      pkg_vec_free(installed);
1344
1345      return 0;
1346 }
1347
1348 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1349 {
1350      if (argc == 3) {
1351           /* this is a bit gross */
1352           struct pkg p1, p2;
1353           parseVersion(&p1, argv[0]); 
1354           parseVersion(&p2, argv[2]); 
1355           return pkg_version_satisfied(&p1, &p2, argv[1]);
1356      } else {
1357           opkg_message(conf, OPKG_ERROR,
1358                        "opkg compare_versions <v1> <op> <v2>\n"
1359                        "<op> is one of <= >= << >> =\n");
1360           return -1;
1361      }
1362 }
1363
1364 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1365 {
1366      nv_pair_list_elt_t *l;
1367
1368      list_for_each_entry(l, &conf->arch_list.head, node) {
1369           nv_pair_t *nv = (nv_pair_t *)l->data;
1370           printf("arch %s %s\n", nv->name, nv->value);
1371      }
1372      return 0;
1373 }