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