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