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