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