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