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