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