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