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