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