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