only add pkg_vec_sort when needed
[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      pkg_vec_sort(available, pkg_compare_names);
715      for (i=0; i < available->len; i++) {
716           pkg = available->pkgs[i];
717           /* if we have package name or pattern and pkg does not match, then skip it */
718           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
719                continue;
720           if (pkg->description) {
721                strncpy(desc_short, pkg->description, OPKG_LIST_DESCRIPTION_LENGTH);
722           } else {
723                desc_short[0] = '\0';
724           }
725           desc_short[OPKG_LIST_DESCRIPTION_LENGTH - 1] = '\0';
726           newline = strchr(desc_short, '\n');
727           if (newline) {
728                *newline = '\0';
729           }
730           if (opkg_cb_list) {
731                 version_str = pkg_version_str_alloc(pkg);
732                 opkg_cb_list(pkg->name,desc_short,
733                                              version_str,
734                                          pkg->state_status,
735                                          p_userdata);
736                 free(version_str);
737           }
738      }
739      pkg_vec_free(available);
740
741      return 0;
742 }
743
744
745 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
746 {
747      int i ;
748      pkg_vec_t *available;
749      pkg_t *pkg;
750      char desc_short[OPKG_LIST_DESCRIPTION_LENGTH];
751      char *newline;
752      char *pkg_name = NULL;
753      char *version_str;
754
755      if (argc > 0) {
756           pkg_name = argv[0];
757      }
758      available = pkg_vec_alloc();
759      pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
760      pkg_vec_sort(available, pkg_compare_names);
761      for (i=0; i < available->len; i++) {
762           pkg = available->pkgs[i];
763           /* if we have package name or pattern and pkg does not match, then skip it */
764           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
765                continue;
766           if (pkg->description) {
767                strncpy(desc_short, pkg->description, OPKG_LIST_DESCRIPTION_LENGTH);
768           } else {
769                desc_short[0] = '\0';
770           }
771           desc_short[OPKG_LIST_DESCRIPTION_LENGTH - 1] = '\0';
772           newline = strchr(desc_short, '\n');
773           if (newline) {
774                *newline = '\0';
775           }
776           if (opkg_cb_list) {
777                 version_str = pkg_version_str_alloc(pkg);
778                 opkg_cb_list(pkg->name,desc_short,
779                                              version_str,
780                                          pkg->state_status,
781                                          p_userdata);
782                 free(version_str);
783           }
784      }
785
786      return 0;
787 }
788
789 static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv) 
790 {
791     struct active_list *head = prepare_upgrade_list(conf);
792     struct active_list *node=NULL;
793     pkg_t *_old_pkg, *_new_pkg;
794     char *old_v, *new_v;
795     for (node = active_list_next(head, head); node;node = active_list_next(head,node)) {
796         _old_pkg = list_entry(node, pkg_t, list);
797         _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, _old_pkg->name, NULL);
798         old_v = pkg_version_str_alloc(_old_pkg);
799         new_v = pkg_version_str_alloc(_new_pkg);
800         if (opkg_cb_list)
801             opkg_cb_list(_old_pkg->name, new_v, old_v, _old_pkg->state_status, p_userdata);
802         free(old_v);
803         free(new_v);
804     }
805     active_list_head_delete(head);
806     return 0;
807 }
808
809 static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int installed_only)
810 {
811      int i;
812      pkg_vec_t *available;
813      pkg_t *pkg;
814      char *pkg_name = NULL;
815      char **pkg_fields = NULL;
816      int n_fields = 0;
817      char *buff ; 
818
819      if (argc > 0) {
820           pkg_name = argv[0];
821      }
822      if (argc > 1) {
823           pkg_fields = &argv[1];
824           n_fields = argc - 1;
825      }
826
827      available = pkg_vec_alloc();
828      if (installed_only)
829           pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
830      else
831           pkg_hash_fetch_available(&conf->pkg_hash, available);
832      for (i=0; i < available->len; i++) {
833           pkg = available->pkgs[i];
834           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
835                continue;
836           }
837
838           buff = pkg_formatted_info(pkg);
839           if ( buff ) {
840                if (opkg_cb_status) opkg_cb_status(pkg->name,
841                                                   pkg->state_status,
842                                                   buff,
843                                                   p_userdata);
844 /* 
845    We should not forget that actually the pointer is allocated. 
846    We need to free it :)  ( Thanks florian for seeing the error )
847 */
848                free(buff);
849           }
850           if (conf->verbosity > 1) {
851                conffile_list_elt_t *iter;
852                for (iter = pkg->conffiles.head; iter; iter = iter->next) {
853                     conffile_t *cf = iter->data;
854                     int modified = conffile_has_been_modified(conf, cf);
855                     opkg_message(conf, OPKG_NOTICE, "conffile=%s md5sum=%s modified=%d\n",
856                                  cf->name, cf->value, modified);
857                }
858           }
859      }
860      pkg_vec_free(available);
861
862      return 0;
863 }
864
865 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv)
866 {
867      return opkg_info_status_cmd(conf, argc, argv, 0);
868 }
869
870 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv)
871 {
872      return opkg_info_status_cmd(conf, argc, argv, 1);
873 }
874
875 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv)
876 {
877      
878      int err;
879      if (argc > 0) {
880           char *pkg_name = NULL;
881
882           pkg_name = argv[0];
883
884           err = opkg_configure_packages (conf, pkg_name);
885      
886      } else {
887           err = opkg_configure_packages (conf, NULL);
888      }
889
890      write_status_files_if_changed(conf);
891
892      return err;
893 }
894
895 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv)
896 {
897      int i, err;
898      char *globpattern;
899      glob_t globbuf;
900     
901      sprintf_alloc(&globpattern, "%s/*" OPKG_PKG_EXTENSION, conf->pending_dir);
902      err = glob(globpattern, 0, NULL, &globbuf);
903      free(globpattern);
904      if (err) {
905           return 0;
906      }
907
908      opkg_message(conf, OPKG_NOTICE,
909                   "The following packages in %s will now be installed.\n",
910                   conf->pending_dir);
911      for (i = 0; i < globbuf.gl_pathc; i++) {
912           opkg_message(conf, OPKG_NOTICE,
913                        "%s%s", i == 0 ? "" : " ", globbuf.gl_pathv[i]);
914      }
915      opkg_message(conf, OPKG_NOTICE, "\n");
916      for (i = 0; i < globbuf.gl_pathc; i++) {
917           err = opkg_install_from_file(conf, globbuf.gl_pathv[i]);
918           if (err == 0) {
919                err = unlink(globbuf.gl_pathv[i]);
920                if (err) {
921                     opkg_message(conf, OPKG_ERROR,
922                                  "%s: ERROR: failed to unlink %s: %s\n",
923                                  __FUNCTION__, globbuf.gl_pathv[i], strerror(err));
924                     return err;
925                }
926           }
927      }
928      globfree(&globbuf);
929
930      return err;
931 }
932
933 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv)
934 {
935      int i,a,done;
936      pkg_t *pkg;
937      pkg_t *pkg_to_remove;
938      pkg_vec_t *available;
939      char *pkg_name = NULL;
940      global_conf = conf;
941      signal(SIGINT, sigint_handler);
942
943 // ENH: Add the "no pkg removed" just in case.
944
945     done = 0;
946
947      pkg_info_preinstall_check(conf);
948      if ( argc > 0 ) {
949         available = pkg_vec_alloc();
950         pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
951         for (i=0; i < argc; i++) {
952            pkg_name = calloc(1, strlen(argv[i])+2);
953            strcpy(pkg_name,argv[i]);
954            for (a=0; a < available->len; a++) {
955                pkg = available->pkgs[a];
956                if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
957                   continue;
958                }
959                if (conf->restrict_to_default_dest) {
960                     pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
961                                                                 pkg->name,
962                                                                 conf->default_dest);
963                } else {
964                     pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
965                }
966         
967                if (pkg == NULL) {
968                     opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
969                     continue;
970                }
971                if (pkg->state_status == SS_NOT_INSTALLED) {    // Added the control, so every already removed package could be skipped
972                     opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
973                     continue;
974                }
975                opkg_remove_pkg(conf, pkg_to_remove,0);
976                done = 1;
977            }
978            free (pkg_name);
979         }
980         pkg_vec_free(available);
981      } else {
982           pkg_vec_t *installed_pkgs = pkg_vec_alloc();
983           int i;
984           int flagged_pkg_count = 0;
985           int removed;
986
987           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed_pkgs);
988
989           for (i = 0; i < installed_pkgs->len; i++) {
990                pkg_t *pkg = installed_pkgs->pkgs[i];
991                if (pkg->state_flag & SF_USER) {
992                     flagged_pkg_count++;
993                } else {
994                     if (!pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL))
995                          opkg_message(conf, OPKG_NOTICE, "Non-user leaf package: %s\n", pkg->name);
996                }
997           }
998           if (!flagged_pkg_count) {
999                opkg_message(conf, OPKG_NOTICE, "No packages flagged as installed by user, \n"
1000                             "so refusing to uninstall unflagged non-leaf packages\n");
1001                return 0;
1002           }
1003
1004           /* find packages not flagged SF_USER (i.e., installed to
1005            * satisfy a dependence) and not having any dependents, and
1006            * remove them */
1007           do {
1008                removed = 0;
1009                for (i = 0; i < installed_pkgs->len; i++) {
1010                     pkg_t *pkg = installed_pkgs->pkgs[i];
1011                     if (!(pkg->state_flag & SF_USER)
1012                         && !pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL)) {
1013                          removed++;
1014                          opkg_message(conf, OPKG_NOTICE, "Removing non-user leaf package %s\n");
1015                          opkg_remove_pkg(conf, pkg,0);
1016                          done = 1;
1017                     }
1018                }
1019           } while (removed);
1020           pkg_vec_free(installed_pkgs);
1021      }
1022
1023      if ( done == 0 ) 
1024         opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
1025
1026      write_status_files_if_changed(conf);
1027      return 0;
1028 }
1029
1030 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv)
1031 {
1032      int i;
1033      pkg_t *pkg;
1034
1035      global_conf = conf;
1036      signal(SIGINT, sigint_handler);
1037
1038      pkg_info_preinstall_check(conf);
1039
1040      for (i=0; i < argc; i++) {
1041           if (conf->restrict_to_default_dest) {
1042                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
1043                                                            argv[i],
1044                                                            conf->default_dest);
1045           } else {
1046                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
1047           }
1048
1049           if (pkg == NULL) {
1050                opkg_message(conf, OPKG_ERROR,
1051                             "Package %s is not installed.\n", argv[i]);
1052                continue;
1053           }
1054           opkg_purge_pkg(conf, pkg);
1055      }
1056
1057      write_status_files_if_changed(conf);
1058      return 0;
1059 }
1060
1061 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
1062 {
1063      int i;
1064      pkg_t *pkg;
1065      const char *flags = argv[0];
1066     
1067      global_conf = conf;
1068      signal(SIGINT, sigint_handler);
1069
1070      for (i=1; i < argc; i++) {
1071           if (conf->restrict_to_default_dest) {
1072                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
1073                                                            argv[i],
1074                                                            conf->default_dest);
1075           } else {
1076                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
1077           }
1078
1079           if (pkg == NULL) {
1080                opkg_message(conf, OPKG_ERROR,
1081                             "Package %s is not installed.\n", argv[i]);
1082                continue;
1083           }
1084           if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
1085               ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
1086               pkg->state_flag = pkg_state_flag_from_str(flags);
1087           }
1088 /* pb_ asked this feature 03292004 */
1089 /* Actually I will use only this two, but this is an open for various status */
1090           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
1091               pkg->state_status = pkg_state_status_from_str(flags);
1092           }
1093           opkg_state_changed++;
1094           opkg_message(conf, OPKG_NOTICE,
1095                        "Setting flags for package %s to %s\n",
1096                        pkg->name, flags);
1097      }
1098
1099      write_status_files_if_changed(conf);
1100      return 0;
1101 }
1102
1103 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
1104 {
1105      pkg_t *pkg;
1106      str_list_t *installed_files;
1107      str_list_elt_t *iter;
1108      char *pkg_version;
1109      size_t buff_len = 8192;
1110      size_t used_len;
1111      char *buff ;
1112
1113      buff = (char *)calloc(1, buff_len);
1114      if ( buff == NULL ) {
1115         fprintf( stderr,"%s: Unable to allocate memory \n",__FUNCTION__);
1116         return ENOMEM;
1117      }
1118  
1119      if (argc < 1) {
1120           return EINVAL;
1121      }
1122
1123      pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
1124                                             argv[0]);
1125      if (pkg == NULL) {
1126           opkg_message(conf, OPKG_ERROR,
1127                        "Package %s not installed.\n", argv[0]);
1128           return 0;
1129      }
1130
1131      installed_files = pkg_get_installed_files(pkg);
1132      pkg_version = pkg_version_str_alloc(pkg);
1133
1134      if (buff) {
1135      try_again:
1136           used_len = snprintf(buff, buff_len, "Package %s (%s) is installed on %s and has the following files:\n",
1137                               pkg->name, pkg_version, pkg->dest->name) + 1;
1138           if (used_len > buff_len) {
1139                buff_len *= 2;
1140                buff = realloc (buff, buff_len);
1141                goto try_again;
1142           }
1143           for (iter = installed_files->head; iter; iter = iter->next) {
1144                used_len += strlen (iter->data) + 1;
1145                while (buff_len <= used_len) {
1146                     buff_len *= 2;
1147                     buff = realloc (buff, buff_len);
1148                }
1149                strncat(buff, iter->data, buff_len);
1150                strncat(buff, "\n", buff_len);
1151           } 
1152           if (opkg_cb_list) opkg_cb_list(pkg->name,
1153                                          buff,
1154                                          pkg_version_str_alloc(pkg),
1155                                          pkg->state_status,
1156                                          p_userdata);
1157           free(buff);
1158      }
1159
1160      free(pkg_version);
1161      pkg_free_installed_files(pkg);
1162
1163      return 0;
1164 }
1165
1166 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
1167 {
1168
1169      if (argc > 0) {
1170           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1171           const char *rel_str = "depends on";
1172           int i;
1173      
1174           pkg_info_preinstall_check(conf);
1175
1176           if (conf->query_all)
1177                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1178           else
1179                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1180           for (i = 0; i < argc; i++) {
1181                const char *target = argv[i];
1182                int j;
1183
1184                opkg_message(conf, OPKG_ERROR, "target=%s\n", target);
1185
1186                for (j = 0; j < available_pkgs->len; j++) {
1187                     pkg_t *pkg = available_pkgs->pkgs[j];
1188                     if (fnmatch(target, pkg->name, 0) == 0) {
1189                          int k;
1190                          int count = pkg->depends_count + pkg->pre_depends_count;
1191                          opkg_message(conf, OPKG_ERROR, "What %s (arch=%s) %s\n",
1192                                       target, pkg->architecture, rel_str);
1193                          for (k = 0; k < count; k++) {
1194                               compound_depend_t *cdepend = &pkg->depends[k];
1195                               int l;
1196                               for (l = 0; l < cdepend->possibility_count; l++) {
1197                                    depend_t *possibility = cdepend->possibilities[l];
1198                                    opkg_message(conf, OPKG_ERROR, "    %s", possibility->pkg->name);
1199                                    if (conf->verbosity > 0) {
1200                                         // char *ver = abstract_pkg_version_str_alloc(possibility->pkg); 
1201                                         opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
1202                                         if (possibility->version) {
1203                                              char *typestr = NULL;
1204                                              switch (possibility->constraint) {
1205                                              case NONE: typestr = "none"; break;
1206                                              case EARLIER: typestr = "<"; break;
1207                                              case EARLIER_EQUAL: typestr = "<="; break;
1208                                              case EQUAL: typestr = "="; break;
1209                                              case LATER_EQUAL: typestr = ">="; break;
1210                                              case LATER: typestr = ">"; break;
1211                                              }
1212                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1213                                         }
1214                                         // free(ver);
1215                                    }
1216                                    opkg_message(conf, OPKG_ERROR, "\n");
1217                               }
1218                          }
1219                     }
1220                }
1221           }
1222           pkg_vec_free(available_pkgs);
1223      }
1224      return 0;
1225 }
1226
1227 enum what_field_type {
1228   WHATDEPENDS,
1229   WHATCONFLICTS,
1230   WHATPROVIDES,
1231   WHATREPLACES,
1232   WHATRECOMMENDS,
1233   WHATSUGGESTS
1234 };
1235
1236 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int recursive, int argc, char **argv)
1237 {
1238
1239      if (argc > 0) {
1240           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1241           const char *rel_str = NULL;
1242           int i;
1243           int changed;
1244
1245           switch (what_field_type) {
1246           case WHATDEPENDS: rel_str = "depends on"; break;
1247           case WHATCONFLICTS: rel_str = "conflicts with"; break;
1248           case WHATSUGGESTS: rel_str = "suggests"; break;
1249           case WHATRECOMMENDS: rel_str = "recommends"; break;
1250           case WHATPROVIDES: rel_str = "provides"; break;
1251           case WHATREPLACES: rel_str = "replaces"; break;
1252           }
1253      
1254           if (conf->query_all)
1255                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1256           else
1257                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1258
1259           /* mark the root set */
1260           pkg_vec_clear_marks(available_pkgs);
1261           opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1262           for (i = 0; i < argc; i++) {
1263                const char *dependee_pattern = argv[i];
1264                pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1265           }
1266           for (i = 0; i < available_pkgs->len; i++) {
1267                pkg_t *pkg = available_pkgs->pkgs[i];
1268                if (pkg->state_flag & SF_MARKED) {
1269                     /* mark the parent (abstract) package */
1270                     pkg_mark_provides(pkg);
1271                     opkg_message(conf, OPKG_NOTICE, "  %s\n", pkg->name);
1272                }
1273           }
1274
1275           opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1276           do {
1277                int j;
1278                changed = 0;
1279
1280                for (j = 0; j < available_pkgs->len; j++) {
1281                     pkg_t *pkg = available_pkgs->pkgs[j];
1282                     int k;
1283                     int count = ((what_field_type == WHATCONFLICTS)
1284                                  ? pkg->conflicts_count
1285                                  : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1286                     /* skip this package if it is already marked */
1287                     if (pkg->parent->state_flag & SF_MARKED) {
1288                          continue;
1289                     }
1290                     for (k = 0; k < count; k++) {
1291                          compound_depend_t *cdepend = 
1292                               (what_field_type == WHATCONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1293                          int l;
1294                          for (l = 0; l < cdepend->possibility_count; l++) {
1295                               depend_t *possibility = cdepend->possibilities[l];
1296                               if (possibility->pkg->state_flag & SF_MARKED) {
1297                                    /* mark the depending package so we won't visit it again */
1298                                    pkg->state_flag |= SF_MARKED;
1299                                    pkg_mark_provides(pkg);
1300                                    changed++;
1301
1302                                    opkg_message(conf, OPKG_NOTICE, "    %s", pkg->name);
1303                                    if (conf->verbosity > 0) {
1304                                         char *ver = pkg_version_str_alloc(pkg); 
1305                                         opkg_message(conf, OPKG_NOTICE, " %s", ver);
1306                                         opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1307                                         if (possibility->version) {
1308                                              char *typestr = NULL;
1309                                              switch (possibility->constraint) {
1310                                              case NONE: typestr = "none"; break;
1311                                              case EARLIER: typestr = "<"; break;
1312                                              case EARLIER_EQUAL: typestr = "<="; break;
1313                                              case EQUAL: typestr = "="; break;
1314                                              case LATER_EQUAL: typestr = ">="; break;
1315                                              case LATER: typestr = ">"; break;
1316                                              }
1317                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1318                                         }
1319                                         free(ver);
1320                                         if (!pkg_dependence_satisfiable(conf, possibility))
1321                                              opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1322                                    }
1323                                    opkg_message(conf, OPKG_NOTICE, "\n");
1324                                    goto next_package;
1325                               }
1326                          }
1327                     }
1328                next_package:
1329                     ;
1330                }
1331           } while (changed && recursive);
1332           pkg_vec_free(available_pkgs);
1333      }
1334
1335      return 0;
1336 }
1337
1338 static int pkg_mark_provides(pkg_t *pkg)
1339 {
1340      int provides_count = pkg->provides_count;
1341      abstract_pkg_t **provides = pkg->provides;
1342      int i;
1343      pkg->parent->state_flag |= SF_MARKED;
1344      for (i = 0; i < provides_count; i++) {
1345           provides[i]->state_flag |= SF_MARKED;
1346      }
1347      return 0;
1348 }
1349
1350 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1351 {
1352      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 1, argc, argv);
1353 }
1354 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1355 {
1356      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 0, argc, argv);
1357 }
1358
1359 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1360 {
1361      return opkg_what_depends_conflicts_cmd(conf, WHATSUGGESTS, 0, argc, argv);
1362 }
1363
1364 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1365 {
1366      return opkg_what_depends_conflicts_cmd(conf, WHATRECOMMENDS, 0, argc, argv);
1367 }
1368
1369 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1370 {
1371      return opkg_what_depends_conflicts_cmd(conf, WHATCONFLICTS, 0, argc, argv);
1372 }
1373
1374 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1375 {
1376
1377      if (argc > 0) {
1378           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1379           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1380           int i;
1381      
1382           pkg_info_preinstall_check(conf);
1383
1384           if (conf->query_all)
1385                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1386           else
1387                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1388           for (i = 0; i < argc; i++) {
1389                const char *target = argv[i];
1390                int j;
1391
1392                opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1393                             rel_str, target);
1394                for (j = 0; j < available_pkgs->len; j++) {
1395                     pkg_t *pkg = available_pkgs->pkgs[j];
1396                     int k;
1397                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1398                     for (k = 0; k < count; k++) {
1399                          abstract_pkg_t *apkg = 
1400                               ((what_field_type == WHATPROVIDES) 
1401                                ? pkg->provides[k]
1402                                : pkg->replaces[k]);
1403                          if (fnmatch(target, apkg->name, 0) == 0) {
1404                               opkg_message(conf, OPKG_ERROR, "    %s", pkg->name);
1405                               if (strcmp(target, apkg->name) != 0)
1406                                    opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1407                               opkg_message(conf, OPKG_ERROR, "\n");
1408                          }
1409                     }
1410                }
1411           }
1412           pkg_vec_free(available_pkgs);
1413      }
1414      return 0;
1415 }
1416
1417 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1418 {
1419      return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1420 }
1421
1422 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1423 {
1424      return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1425 }
1426
1427 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1428 {
1429      int i;
1430
1431      pkg_vec_t *installed;
1432      pkg_t *pkg;
1433      str_list_t *installed_files;
1434      str_list_elt_t *iter;
1435      char *installed_file;
1436
1437      if (argc < 1) {
1438           return EINVAL;
1439      }
1440  
1441      installed = pkg_vec_alloc();
1442      pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1443      pkg_vec_sort(installed, pkg_compare_names);
1444
1445      for (i=0; i < installed->len; i++) {
1446           pkg = installed->pkgs[i];
1447
1448           installed_files = pkg_get_installed_files(pkg);
1449
1450           for (iter = installed_files->head; iter; iter = iter->next) {
1451                installed_file = iter->data;
1452                if (fnmatch(argv[0], installed_file, 0)==0)  {
1453                         if (opkg_cb_list) opkg_cb_list(pkg->name, 
1454                                                        installed_file, 
1455                                                        pkg_version_str_alloc(pkg), 
1456                                                        pkg->state_status, p_userdata);
1457                }                
1458           }
1459
1460           pkg_free_installed_files(pkg);
1461      }
1462
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