opkg: Implement proper reordering of packages before configuring.
[oweals/opkg-lede.git] / libopkg / opkg_cmd.c
1 /* opkg_cmd.c - the opkg package management system
2
3    Carl D. Worth
4
5    Copyright (C) 2001 University of Southern California
6
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2, or (at
10    your option) any later version.
11
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 */
17
18
19 #include "includes.h"
20 #include <dirent.h>
21 #include <glob.h>
22
23 #include "opkg_conf.h"
24 #include "opkg_cmd.h"
25 #include "opkg_message.h"
26 #include "pkg.h"
27 #include "pkg_dest.h"
28 #include "pkg_parse.h"
29 #include "sprintf_alloc.h"
30 #include "pkg.h"
31 #include "file_util.h"
32 #include "str_util.h"
33 #include "libbb/libbb.h"
34 #include "opkg_utils.h"
35 #include "opkg_defines.h"
36
37 #include <fnmatch.h>
38
39
40 #include "opkg_download.h"
41 #include "opkg_install.h"
42 #include "opkg_upgrade.h"
43 #include "opkg_remove.h"
44 #include "opkg_configure.h"
45 #include "opkg_message.h"
46
47 #include "libopkg.h"
48 static void *p_userdata = NULL;
49
50 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv);
51 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv);
52 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv);
53 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv);
54 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv);
55 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv);
56 static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv);
57 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv);
58 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv);
59 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv);
60 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv);
61 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv);
62 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv);
63 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv);
64 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv);
65 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv);
66 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv);
67 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv);
68 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv);
69 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv);
70 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv);
71 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv);
72 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv);
73 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv);
74 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv);
75
76 /* XXX: CLEANUP: The usage strings should be incorporated into this
77    array for easier maintenance */
78 static opkg_cmd_t cmds[] = {
79      {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd}, 
80      {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd},
81      {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd},
82      {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd},
83      {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd},
84      {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd},
85      {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd},
86      {"install_pending", 0, (opkg_cmd_fun_t)opkg_install_pending_cmd},
87      {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd},
88      {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd},
89      {"purge", 1, (opkg_cmd_fun_t)opkg_purge_cmd},
90      {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd},
91      {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd},
92      {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd},
93      {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd},
94      {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
95      {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
96      {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
97      {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
98      {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
99      {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
100      {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd},
101      {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd},
102      {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd},
103      {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd},
104      {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd},
105      {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd},
106      {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd},
107      {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd},
108 };
109
110 int opkg_state_changed;
111 static void write_status_files_if_changed(opkg_conf_t *conf)
112 {
113      if (opkg_state_changed && !conf->noaction) {
114           opkg_message(conf, OPKG_INFO,
115                        "  writing status file\n");
116           opkg_conf_write_status_files(conf);
117           pkg_write_changed_filelists(conf);
118      } else { 
119           opkg_message(conf, OPKG_NOTICE, "Nothing to be done\n");
120      }
121 }
122
123
124 static int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
125
126 opkg_cmd_t *opkg_cmd_find(const char *name)
127 {
128      int i;
129      opkg_cmd_t *cmd;
130
131      for (i=0; i < num_cmds; i++) {
132           cmd = &cmds[i];
133           if (strcmp(name, cmd->name) == 0) {
134                return cmd;
135           }
136      }
137
138      return NULL;
139 }
140
141 int opkg_cmd_exec(opkg_cmd_t *cmd, opkg_conf_t *conf, int argc, const char **argv, void *userdata)
142 {
143         int result;
144         p_userdata = userdata;
145       
146
147         result = (cmd->fun)(conf, argc, argv);
148
149         if ( result != 0 ) {
150            opkg_message(conf, OPKG_NOTICE, "An error ocurred, return value: %d.\n", result);
151         }
152
153         if ( error_list ) {
154            reverse_error_list(&error_list);
155
156            opkg_message(conf, OPKG_NOTICE, "Collected errors:\n");
157            /* Here we print the errors collected and free the list */
158            while (error_list != NULL) {
159                  opkg_message(conf, OPKG_NOTICE, "%s",error_list->errmsg);
160                  error_list = error_list->next;
161
162            }
163            free_error_list(&error_list);
164
165         }
166    
167         p_userdata = NULL;
168         return result;
169 }
170
171 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
172 {
173      char *tmp;
174      int err;
175      int failures;
176      char *lists_dir;
177      pkg_src_list_elt_t *iter;
178      pkg_src_t *src;
179
180  
181     sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir);
182  
183     if (! file_is_dir(lists_dir)) {
184           if (file_exists(lists_dir)) {
185                opkg_message(conf, OPKG_ERROR,
186                             "%s: ERROR: %s exists, but is not a directory\n",
187                             __FUNCTION__, lists_dir);
188                free(lists_dir);
189                return EINVAL;
190           }
191           err = file_mkdir_hier(lists_dir, 0755);
192           if (err) {
193                opkg_message(conf, OPKG_ERROR,
194                             "%s: ERROR: failed to make directory %s: %s\n",
195                             __FUNCTION__, lists_dir, strerror(errno));
196                free(lists_dir);
197                return EINVAL;
198           }     
199      } 
200
201      failures = 0;
202
203
204      tmp = strdup ("/tmp/opkg.XXXXXX");
205
206      if (mkdtemp (tmp) == NULL) {
207          perror ("mkdtemp");
208          failures++;
209      }
210
211
212      for (iter = conf->pkg_src_list.head; iter; iter = iter->next) {
213           char *url, *list_file_name;
214
215           src = iter->data;
216
217           if (src->extra_data)  /* debian style? */
218               sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, 
219                             src->gzip ? "Packages.gz" : "Packages");
220           else
221               sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
222
223           sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
224           if (src->gzip) {
225               char *tmp_file_name;
226               FILE *in, *out;
227               
228               sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
229               err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
230               if (err == 0) {
231                    opkg_message (conf, OPKG_NOTICE, "Inflating %s\n", url);
232                    in = fopen (tmp_file_name, "r");
233                    out = fopen (list_file_name, "w");
234                    if (in && out)
235                         unzip (in, out);
236                    else
237                         err = 1;
238                    if (in)
239                         fclose (in);
240                    if (out)
241                         fclose (out);
242                    unlink (tmp_file_name);
243               }
244           } else
245               err = opkg_download(conf, url, list_file_name, NULL, NULL);
246           if (err) {
247                failures++;
248           } else {
249                opkg_message(conf, OPKG_NOTICE,
250                             "Updated list of available packages in %s\n",
251                             list_file_name);
252           }
253           free(url);
254
255 #ifdef HAVE_GPGME
256           /* download detached signitures to verify the package lists */
257           /* get the url for the sig file */
258           if (src->extra_data)  /* debian style? */
259               sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data,
260                             "Packages.sig");
261           else
262               sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig");
263
264           /* create temporary file for it */
265           char *tmp_file_name;
266
267           sprintf_alloc (&tmp_file_name, "%s/%s", tmp, "Packages.sig");
268
269           err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
270           if (err) {
271             failures++;
272                 opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
273           } else {
274             int err;
275             err = opkg_verify_file (conf, list_file_name, tmp_file_name);
276             if (err == 0)
277                 opkg_message (conf, OPKG_NOTICE, "Signature check passed\n");
278             else
279                 opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
280           }
281           unlink (tmp_file_name);
282           free (tmp_file_name);
283           free (url);
284 #else
285           opkg_message (conf, OPKG_NOTICE, "Signiture check for %s skipped "
286               "because GPG support was not enabled in this build\n", src->name);
287 #endif
288           free(list_file_name);
289      }
290      rmdir (tmp);
291      free (tmp);
292      free(lists_dir);
293
294      return failures;
295 }
296
297
298 /* scan the args passed and cache the local filenames of the packages */
299 int opkg_multiple_files_scan(opkg_conf_t *conf, int argc, char **argv)
300 {
301      int i;
302      int err;
303     
304      /* 
305       * First scan through package names/urls
306       * For any urls, download the packages and install in database.
307       * For any files, install package info in database.
308       */
309      for (i = 0; i < argc; i ++) {
310           char *filename = argv [i];
311           //char *tmp = basename (tmp);
312           //int tmplen = strlen (tmp);
313
314           //if (strcmp (tmp + (tmplen - strlen (OPKG_PKG_EXTENSION)), OPKG_PKG_EXTENSION) != 0)
315           //     continue;
316           //if (strcmp (tmp + (tmplen - strlen (DPKG_PKG_EXTENSION)), DPKG_PKG_EXTENSION) != 0)
317           //     continue;
318         
319           opkg_message(conf, OPKG_DEBUG2, "Debug mfs: %s  \n",filename );
320
321           err = opkg_prepare_url_for_install(conf, filename, &argv[i]);
322           if (err)
323             return err;
324      }
325      return 0;
326 }
327
328 struct opkg_intercept
329 {
330     char *oldpath;
331     char *statedir;
332 };
333
334 typedef struct opkg_intercept *opkg_intercept_t;
335
336 opkg_intercept_t opkg_prep_intercepts(opkg_conf_t *conf)
337 {
338     opkg_intercept_t ctx;
339     char *newpath;
340     int gen;
341
342     ctx = malloc (sizeof (*ctx));
343     ctx->oldpath = strdup (getenv ("PATH"));
344
345     sprintf_alloc (&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
346     setenv ("PATH", newpath, 1);
347     free (newpath);
348     
349     gen = 0;
350  retry:
351     sprintf_alloc (&ctx->statedir, "/tmp/opkg-intercept-%d-%d", getpid (), gen);
352     if (mkdir (ctx->statedir, 0770) < 0) {
353         if (errno == EEXIST) {
354             free (ctx->statedir);
355             gen++;
356             goto retry;
357         }
358         perror (ctx->statedir);
359         return NULL;
360     }
361     setenv ("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
362     return ctx;
363 }
364
365 int opkg_finalize_intercepts(opkg_intercept_t ctx)
366 {
367     char *cmd;
368     DIR *dir;
369     int err = 0;
370
371     setenv ("PATH", ctx->oldpath, 1);
372     free (ctx->oldpath);
373
374     dir = opendir (ctx->statedir);
375     if (dir) {
376         struct dirent *de;
377         while (de = readdir (dir), de != NULL) {
378             char *path;
379             
380             if (de->d_name[0] == '.')
381                 continue;
382             
383             sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name);
384             if (access (path, X_OK) == 0) {
385                 if (system (path)) {
386                     err = errno;
387                     perror (de->d_name);
388                 }
389             }
390             free (path);
391         }
392     } else
393         perror (ctx->statedir);
394         
395     sprintf_alloc (&cmd, "rm -rf %s", ctx->statedir);
396     system (cmd);
397     free (cmd);
398
399     free (ctx->statedir);
400     free (ctx);
401
402     return err;
403 }
404
405 /* For package pkg do the following: If it is already visited, return. If not,
406    add it in visited list and recurse to its deps. Finally, add it to ordered 
407    list.
408    pkg_vec all contains all available packages in repos.
409    pkg_vec visited contains packages already visited by this function, and is 
410    used to end recursion and avoid an infinite loop on graph cycles.
411    pkg_vec ordered will finally contain the ordered set of packages.
412 */
413 int opkg_recurse_pkgs_in_order(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *all,
414                                pkg_vec_t *visited, pkg_vec_t *ordered)
415 {
416     int j,k,l,m;
417     int count;
418     pkg_t *dep;
419     compound_depend_t * compound_depend;
420     depend_t ** possible_satisfiers;
421     abstract_pkg_t *abpkg;
422     abstract_pkg_t **dependents;
423
424     /* If it's just an available package, that is, not installed and not even
425        unpacked, skip it */
426     /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED 
427        would do here. However, if there is an intermediate node (pkg) that is 
428        configured and installed between two unpacked packages, the latter 
429        won't be properly reordered, unless all installed/unpacked pkgs are
430        checked */
431     if (pkg->state_status == SS_NOT_INSTALLED) 
432         return 0;
433
434     /* If the  package has already been visited (by this function), skip it */
435     for(j = 0; j < visited->len; j++) 
436         if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) {
437             opkg_message(conf, OPKG_INFO,
438                          "  pkg: %s already visited\n", pkg->name);
439             return 0;
440         }
441     
442     pkg_vec_insert(visited, pkg);
443
444     count = pkg->pre_depends_count + pkg->depends_count + \
445         pkg->recommends_count + pkg->suggests_count;
446
447     opkg_message(conf, OPKG_INFO,
448                  "  pkg: %s\n", pkg->name);
449
450     /* Iterate over all the dependencies of pkg. For each one, find a package 
451        that is either installed or unpacked and satisfies this dependency.
452        (there should only be one such package per dependency installed or 
453        unpacked). Then recurse to the dependency package */
454     for (j=0; j < count ; j++) {
455         compound_depend = &pkg->depends[j];
456         possible_satisfiers = compound_depend->possibilities;
457         for (k=0; k < compound_depend->possibility_count ; k++) {
458             abpkg = possible_satisfiers[k]->pkg;
459             dependents = abpkg->provided_by->pkgs;
460             l = 0;
461             if (dependents != NULL)
462                 while (dependents [l] != NULL && l < abpkg->provided_by->len) {
463                     opkg_message(conf, OPKG_INFO,
464                                  "  Descending on pkg: %s\n", 
465                                  dependents [l]->name);
466     
467                     /* find whether dependent l is installed or unpacked,
468                      * and then find which package in the list satisfies it */
469                     for(m = 0; m < all->len; m++) {
470                         dep = all->pkgs[m];
471                         if ( dep->state_status != SS_NOT_INSTALLED)
472                             if ( ! strcmp(dep->name, dependents[l]->name)) {
473                                 opkg_recurse_pkgs_in_order(conf, dep, all, 
474                                                            visited, ordered);
475                                 /* Stop the outer loop */
476                                 l = abpkg->provided_by->len;
477                                 /* break from the inner loop */
478                                 break;
479                             }
480                     }
481                     l++;
482                 }
483         }
484     }
485
486     /* When all recursions from this node down, are over, and all 
487        dependencies have been added in proper order in the ordered array, add
488        also the package pkg to ordered array */
489     pkg_vec_insert(ordered, pkg);
490
491     return 0;
492
493 }
494
495 int opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
496 {
497     pkg_vec_t *all, *ordered, *visited;
498      int i;
499      pkg_t *pkg;
500      opkg_intercept_t ic;
501      int r, err = 0;
502
503      opkg_message(conf, OPKG_INFO,
504                   "Configuring unpacked packages\n");
505      fflush( stdout );
506
507      all = pkg_vec_alloc();
508
509      pkg_hash_fetch_available(&conf->pkg_hash, all);
510
511      /* Reorder pkgs in order to be configured according to the Depends: tag
512         order */
513      opkg_message(conf, OPKG_INFO,
514                   "Reordering packages before configuring them...\n");
515      ordered = pkg_vec_alloc();
516      visited = pkg_vec_alloc();
517      for(i = 0; i < all->len; i++) {
518          pkg = all->pkgs[i];
519          opkg_recurse_pkgs_in_order(conf, pkg, all, visited, ordered);
520      }
521
522
523      ic = opkg_prep_intercepts (conf);
524     
525      for(i = 0; i < all->len; i++) {
526           pkg = all->pkgs[i];
527
528           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
529                continue;
530
531           if (pkg->state_status == SS_UNPACKED) {
532                opkg_message(conf, OPKG_NOTICE,
533                             "Configuring %s\n", pkg->name);
534                fflush( stdout );
535                r = opkg_configure(conf, pkg);
536                if (r == 0) {
537                     pkg->state_status = SS_INSTALLED;
538                     pkg->parent->state_status = SS_INSTALLED;
539                     pkg->state_flag &= ~SF_PREFER;
540                } else {
541                     if (!err)
542                         err = r;
543                }
544           }
545      }
546
547      r = opkg_finalize_intercepts (ic);
548      if (r && !err)
549          err = r;
550
551      pkg_vec_free(all);
552      pkg_vec_free(ordered);
553      pkg_vec_free(visited);
554
555      return err;
556 }
557
558 static opkg_conf_t *global_conf;
559
560 static void sigint_handler(int sig)
561 {
562      signal(sig, SIG_DFL);
563      opkg_message(NULL, OPKG_NOTICE,
564                   "opkg: interrupted. writing out status database\n");
565      write_status_files_if_changed(global_conf);
566      exit(128 + sig);
567 }
568
569 static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv)
570 {
571      int i;
572      char *arg;
573      int err=0;
574
575      global_conf = conf;
576      signal(SIGINT, sigint_handler);
577
578      /*
579       * Now scan through package names and install
580       */
581      for (i=0; i < argc; i++) {
582           arg = argv[i];
583
584           opkg_message(conf, OPKG_DEBUG2, "Debug install_cmd: %s  \n",arg );
585           err = opkg_prepare_url_for_install(conf, arg, &argv[i]);
586           if (err != EINVAL && err != 0)
587               return err;
588      }
589      pkg_info_preinstall_check(conf);
590
591      for (i=0; i < argc; i++) {
592           arg = argv[i];
593           if (conf->multiple_providers)
594                err = opkg_install_multi_by_name(conf, arg);
595           else{
596                err = opkg_install_by_name(conf, arg);
597           }
598           if (err == OPKG_PKG_HAS_NO_CANDIDATE) {
599                opkg_message(conf, OPKG_ERROR,
600                             "Cannot find package %s.\n"
601                             "Check the spelling or perhaps run 'opkg update'\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);
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