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