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