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