opkg: remove redundant multiple_providers option and also remove redundant familiar_r...
[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           err = opkg_install_by_name(conf, arg);
594           if (err == OPKG_PKG_HAS_NO_CANDIDATE) {
595                opkg_message(conf, OPKG_ERROR,
596                             "Cannot find package %s.\n"
597                             "Check the spelling or perhaps run 'opkg update'\n",
598                             arg);
599           }
600      }
601
602      /* recheck to verify that all dependences are satisfied */
603      if (0) opkg_satisfy_all_dependences(conf);
604
605      opkg_configure_packages(conf, NULL);
606
607      write_status_files_if_changed(conf);
608
609      return err;
610 }
611
612 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv)
613 {
614      int i;
615      pkg_t *pkg;
616      int err;
617
618      global_conf = conf;
619      signal(SIGINT, sigint_handler);
620
621      if (argc) {
622           for (i=0; i < argc; i++) {
623                char *arg = argv[i];
624
625                err = opkg_prepare_url_for_install(conf, arg, &arg);
626                if (err != EINVAL && err != 0)
627                    return err;
628           }
629           pkg_info_preinstall_check(conf);
630
631           for (i=0; i < argc; i++) {
632                char *arg = argv[i];
633                if (conf->restrict_to_default_dest) {
634                     pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
635                                                                 argv[i],
636                                                                 conf->default_dest);
637                     if (pkg == NULL) {
638                          opkg_message(conf, OPKG_NOTICE,
639                                       "Package %s not installed in %s\n",
640                                       argv[i], conf->default_dest->name);
641                          continue;
642                     }
643                } else {
644                     pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
645                                                            argv[i]);
646                }
647                if (pkg)
648                     opkg_upgrade_pkg(conf, pkg);
649                else {
650                     opkg_install_by_name(conf, arg);
651                }
652           }
653      } else {
654           pkg_vec_t *installed = pkg_vec_alloc();
655
656           pkg_info_preinstall_check(conf);
657
658           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
659           for (i = 0; i < installed->len; i++) {
660                pkg = installed->pkgs[i];
661                opkg_upgrade_pkg(conf, pkg);
662           }
663           pkg_vec_free(installed);
664      }
665
666      /* recheck to verify that all dependences are satisfied */
667      if (0) opkg_satisfy_all_dependences(conf);
668
669      opkg_configure_packages(conf, NULL);
670
671      write_status_files_if_changed(conf);
672
673      return 0;
674 }
675
676 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv)
677 {
678      int i, err;
679      char *arg;
680      pkg_t *pkg;
681
682      pkg_info_preinstall_check(conf);
683      for (i = 0; i < argc; i++) {
684           arg = argv[i];
685
686           pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, arg);
687           if (pkg == NULL) {
688                opkg_message(conf, OPKG_ERROR,
689                             "Cannot find package %s.\n"
690                             "Check the spelling or perhaps run 'opkg update'\n",
691                             arg);
692                continue;
693           }
694
695           err = opkg_download_pkg(conf, pkg, ".");
696
697           if (err) {
698                opkg_message(conf, OPKG_ERROR,
699                             "Failed to download %s\n", pkg->name);
700           } else {
701                opkg_message(conf, OPKG_NOTICE,
702                             "Downloaded %s as %s\n",
703                             pkg->name, pkg->local_filename);
704           }
705      }
706
707      return 0;
708 }
709
710
711 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv)
712 {
713      int i ;
714      pkg_vec_t *available;
715      pkg_t *pkg;
716      char desc_short[OPKG_LIST_DESCRIPTION_LENGTH];
717      char *newline;
718      char *pkg_name = NULL;
719      char *version_str;
720
721      if (argc > 0) {
722           pkg_name = argv[0];
723      }
724      available = pkg_vec_alloc();
725      pkg_hash_fetch_available(&conf->pkg_hash, available);
726      for (i=0; i < available->len; i++) {
727           pkg = available->pkgs[i];
728           /* if we have package name or pattern and pkg does not match, then skip it */
729           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
730                continue;
731           if (pkg->description) {
732                strncpy(desc_short, pkg->description, OPKG_LIST_DESCRIPTION_LENGTH);
733           } else {
734                desc_short[0] = '\0';
735           }
736           desc_short[OPKG_LIST_DESCRIPTION_LENGTH - 1] = '\0';
737           newline = strchr(desc_short, '\n');
738           if (newline) {
739                *newline = '\0';
740           }
741           if (opkg_cb_list) {
742                 version_str = pkg_version_str_alloc(pkg);
743                 opkg_cb_list(pkg->name,desc_short,
744                                              version_str,
745                                          pkg->state_status,
746                                          p_userdata);
747                 free(version_str);
748           }
749      }
750      pkg_vec_free(available);
751
752      return 0;
753 }
754
755
756 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
757 {
758      int i ;
759      pkg_vec_t *available;
760      pkg_t *pkg;
761      char desc_short[OPKG_LIST_DESCRIPTION_LENGTH];
762      char *newline;
763      char *pkg_name = NULL;
764      char *version_str;
765
766      if (argc > 0) {
767           pkg_name = argv[0];
768      }
769      available = pkg_vec_alloc();
770      pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
771      for (i=0; i < available->len; i++) {
772           pkg = available->pkgs[i];
773           /* if we have package name or pattern and pkg does not match, then skip it */
774           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
775                continue;
776           if (pkg->description) {
777                strncpy(desc_short, pkg->description, OPKG_LIST_DESCRIPTION_LENGTH);
778           } else {
779                desc_short[0] = '\0';
780           }
781           desc_short[OPKG_LIST_DESCRIPTION_LENGTH - 1] = '\0';
782           newline = strchr(desc_short, '\n');
783           if (newline) {
784                *newline = '\0';
785           }
786           if (opkg_cb_list) {
787                 version_str = pkg_version_str_alloc(pkg);
788                 opkg_cb_list(pkg->name,desc_short,
789                                              version_str,
790                                          pkg->state_status,
791                                          p_userdata);
792                 free(version_str);
793           }
794      }
795
796      return 0;
797 }
798
799 static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int installed_only)
800 {
801      int i;
802      pkg_vec_t *available;
803      pkg_t *pkg;
804      char *pkg_name = NULL;
805      char **pkg_fields = NULL;
806      int n_fields = 0;
807      char *buff ; // = (char *)malloc(1);
808
809      if (argc > 0) {
810           pkg_name = argv[0];
811      }
812      if (argc > 1) {
813           pkg_fields = &argv[1];
814           n_fields = argc - 1;
815      }
816
817      available = pkg_vec_alloc();
818      if (installed_only)
819           pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
820      else
821           pkg_hash_fetch_available(&conf->pkg_hash, available);
822      for (i=0; i < available->len; i++) {
823           pkg = available->pkgs[i];
824           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
825                continue;
826           }
827
828           buff = pkg_formatted_info(pkg);
829           if ( buff ) {
830                if (opkg_cb_status) opkg_cb_status(pkg->name,
831                                                   pkg->state_status,
832                                                   buff,
833                                                   p_userdata);
834 /* 
835    We should not forget that actually the pointer is allocated. 
836    We need to free it :)  ( Thanks florian for seeing the error )
837 */
838                free(buff);
839           }
840           if (conf->verbosity > 1) {
841                conffile_list_elt_t *iter;
842                for (iter = pkg->conffiles.head; iter; iter = iter->next) {
843                     conffile_t *cf = iter->data;
844                     int modified = conffile_has_been_modified(conf, cf);
845                     opkg_message(conf, OPKG_NOTICE, "conffile=%s md5sum=%s modified=%d\n",
846                                  cf->name, cf->value, modified);
847                }
848           }
849      }
850      pkg_vec_free(available);
851
852      return 0;
853 }
854
855 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv)
856 {
857      return opkg_info_status_cmd(conf, argc, argv, 0);
858 }
859
860 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv)
861 {
862      return opkg_info_status_cmd(conf, argc, argv, 1);
863 }
864
865 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv)
866 {
867      
868      int err;
869      if (argc > 0) {
870           char *pkg_name = NULL;
871
872           pkg_name = argv[0];
873
874           err = opkg_configure_packages (conf, pkg_name);
875      
876      } else {
877           err = opkg_configure_packages (conf, NULL);
878      }
879
880      write_status_files_if_changed(conf);
881
882      return err;
883 }
884
885 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv)
886 {
887      int i, err;
888      char *globpattern;
889      glob_t globbuf;
890     
891      sprintf_alloc(&globpattern, "%s/*" OPKG_PKG_EXTENSION, conf->pending_dir);
892      err = glob(globpattern, 0, NULL, &globbuf);
893      free(globpattern);
894      if (err) {
895           return 0;
896      }
897
898      opkg_message(conf, OPKG_NOTICE,
899                   "The following packages in %s will now be installed.\n",
900                   conf->pending_dir);
901      for (i = 0; i < globbuf.gl_pathc; i++) {
902           opkg_message(conf, OPKG_NOTICE,
903                        "%s%s", i == 0 ? "" : " ", globbuf.gl_pathv[i]);
904      }
905      opkg_message(conf, OPKG_NOTICE, "\n");
906      for (i = 0; i < globbuf.gl_pathc; i++) {
907           err = opkg_install_from_file(conf, globbuf.gl_pathv[i]);
908           if (err == 0) {
909                err = unlink(globbuf.gl_pathv[i]);
910                if (err) {
911                     opkg_message(conf, OPKG_ERROR,
912                                  "%s: ERROR: failed to unlink %s: %s\n",
913                                  __FUNCTION__, globbuf.gl_pathv[i], strerror(err));
914                     return err;
915                }
916           }
917      }
918      globfree(&globbuf);
919
920      return err;
921 }
922
923 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv)
924 {
925      int i,a,done;
926      pkg_t *pkg;
927      pkg_t *pkg_to_remove;
928      pkg_vec_t *available;
929      char *pkg_name = NULL;
930      global_conf = conf;
931      signal(SIGINT, sigint_handler);
932
933 // ENH: Add the "no pkg removed" just in case.
934
935     done = 0;
936
937      available = pkg_vec_alloc();
938      pkg_info_preinstall_check(conf);
939      if ( argc > 0 ) {
940         pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
941         for (i=0; i < argc; i++) {
942            pkg_name = malloc(strlen(argv[i])+2);
943            strcpy(pkg_name,argv[i]);
944            for (a=0; a < available->len; a++) {
945                pkg = available->pkgs[a];
946                if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
947                   continue;
948                }
949                if (conf->restrict_to_default_dest) {
950                     pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
951                                                                 pkg->name,
952                                                                 conf->default_dest);
953                } else {
954                     pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
955                }
956         
957                if (pkg == NULL) {
958                     opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
959                     continue;
960                }
961                if (pkg->state_status == SS_NOT_INSTALLED) {    // Added the control, so every already removed package could be skipped
962                     opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
963                     continue;
964                }
965                opkg_remove_pkg(conf, pkg_to_remove,0);
966                done = 1;
967            }
968            free (pkg_name);
969         }
970         pkg_vec_free(available);
971      } else {
972           pkg_vec_t *installed_pkgs = pkg_vec_alloc();
973           int i;
974           int flagged_pkg_count = 0;
975           int removed;
976
977           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed_pkgs);
978
979           for (i = 0; i < installed_pkgs->len; i++) {
980                pkg_t *pkg = installed_pkgs->pkgs[i];
981                if (pkg->state_flag & SF_USER) {
982                     flagged_pkg_count++;
983                } else {
984                     if (!pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL))
985                          opkg_message(conf, OPKG_NOTICE, "Non-user leaf package: %s\n", pkg->name);
986                }
987           }
988           if (!flagged_pkg_count) {
989                opkg_message(conf, OPKG_NOTICE, "No packages flagged as installed by user, \n"
990                             "so refusing to uninstall unflagged non-leaf packages\n");
991                return 0;
992           }
993
994           /* find packages not flagged SF_USER (i.e., installed to
995            * satisfy a dependence) and not having any dependents, and
996            * remove them */
997           do {
998                removed = 0;
999                for (i = 0; i < installed_pkgs->len; i++) {
1000                     pkg_t *pkg = installed_pkgs->pkgs[i];
1001                     if (!(pkg->state_flag & SF_USER)
1002                         && !pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL)) {
1003                          removed++;
1004                          opkg_message(conf, OPKG_NOTICE, "Removing non-user leaf package %s\n");
1005                          opkg_remove_pkg(conf, pkg,0);
1006                          done = 1;
1007                     }
1008                }
1009           } while (removed);
1010           pkg_vec_free(installed_pkgs);
1011      }
1012
1013      if ( done == 0 ) 
1014         opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
1015
1016      write_status_files_if_changed(conf);
1017      return 0;
1018 }
1019
1020 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv)
1021 {
1022      int i;
1023      pkg_t *pkg;
1024
1025      global_conf = conf;
1026      signal(SIGINT, sigint_handler);
1027
1028      pkg_info_preinstall_check(conf);
1029
1030      for (i=0; i < argc; i++) {
1031           if (conf->restrict_to_default_dest) {
1032                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
1033                                                            argv[i],
1034                                                            conf->default_dest);
1035           } else {
1036                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
1037           }
1038
1039           if (pkg == NULL) {
1040                opkg_message(conf, OPKG_ERROR,
1041                             "Package %s is not installed.\n", argv[i]);
1042                continue;
1043           }
1044           opkg_purge_pkg(conf, pkg);
1045      }
1046
1047      write_status_files_if_changed(conf);
1048      return 0;
1049 }
1050
1051 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
1052 {
1053      int i;
1054      pkg_t *pkg;
1055      const char *flags = argv[0];
1056     
1057      global_conf = conf;
1058      signal(SIGINT, sigint_handler);
1059
1060      for (i=1; i < argc; i++) {
1061           if (conf->restrict_to_default_dest) {
1062                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
1063                                                            argv[i],
1064                                                            conf->default_dest);
1065           } else {
1066                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
1067           }
1068
1069           if (pkg == NULL) {
1070                opkg_message(conf, OPKG_ERROR,
1071                             "Package %s is not installed.\n", argv[i]);
1072                continue;
1073           }
1074           if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
1075               ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
1076               pkg->state_flag = pkg_state_flag_from_str(flags);
1077           }
1078 /* pb_ asked this feature 03292004 */
1079 /* Actually I will use only this two, but this is an open for various status */
1080           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
1081               pkg->state_status = pkg_state_status_from_str(flags);
1082           }
1083           opkg_state_changed++;
1084           opkg_message(conf, OPKG_NOTICE,
1085                        "Setting flags for package %s to %s\n",
1086                        pkg->name, flags);
1087      }
1088
1089      write_status_files_if_changed(conf);
1090      return 0;
1091 }
1092
1093 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
1094 {
1095      pkg_t *pkg;
1096      str_list_t *installed_files;
1097      str_list_elt_t *iter;
1098      char *pkg_version;
1099      size_t buff_len = 8192;
1100      size_t used_len;
1101      char *buff ;
1102
1103      buff = (char *)malloc(buff_len);
1104      if ( buff == NULL ) {
1105         fprintf( stderr,"%s: Unable to allocate memory \n",__FUNCTION__);
1106         return ENOMEM;
1107      }
1108  
1109      if (argc < 1) {
1110           return EINVAL;
1111      }
1112
1113      pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
1114                                             argv[0]);
1115      if (pkg == NULL) {
1116           opkg_message(conf, OPKG_ERROR,
1117                        "Package %s not installed.\n", argv[0]);
1118           return 0;
1119      }
1120
1121      installed_files = pkg_get_installed_files(pkg);
1122      pkg_version = pkg_version_str_alloc(pkg);
1123
1124      if (buff) {
1125      try_again:
1126           used_len = snprintf(buff, buff_len, "Package %s (%s) is installed on %s and has the following files:\n",
1127                               pkg->name, pkg_version, pkg->dest->name) + 1;
1128           if (used_len > buff_len) {
1129                buff_len *= 2;
1130                buff = realloc (buff, buff_len);
1131                goto try_again;
1132           }
1133           for (iter = installed_files->head; iter; iter = iter->next) {
1134                used_len += strlen (iter->data) + 1;
1135                while (buff_len <= used_len) {
1136                     buff_len *= 2;
1137                     buff = realloc (buff, buff_len);
1138                }
1139                strncat(buff, iter->data, buff_len);
1140                strncat(buff, "\n", buff_len);
1141           } 
1142           if (opkg_cb_list) opkg_cb_list(pkg->name,
1143                                          buff,
1144                                          pkg_version_str_alloc(pkg),
1145                                          pkg->state_status,
1146                                          p_userdata);
1147           free(buff);
1148      }
1149
1150      free(pkg_version);
1151      pkg_free_installed_files(pkg);
1152
1153      return 0;
1154 }
1155
1156 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
1157 {
1158
1159      if (argc > 0) {
1160           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1161           const char *rel_str = "depends on";
1162           int i;
1163      
1164           pkg_info_preinstall_check(conf);
1165
1166           if (conf->query_all)
1167                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1168           else
1169                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1170           for (i = 0; i < argc; i++) {
1171                const char *target = argv[i];
1172                int j;
1173
1174                opkg_message(conf, OPKG_ERROR, "target=%s\n", target);
1175
1176                for (j = 0; j < available_pkgs->len; j++) {
1177                     pkg_t *pkg = available_pkgs->pkgs[j];
1178                     if (fnmatch(target, pkg->name, 0) == 0) {
1179                          int k;
1180                          int count = pkg->depends_count + pkg->pre_depends_count;
1181                          opkg_message(conf, OPKG_ERROR, "What %s (arch=%s) %s\n",
1182                                       target, pkg->architecture, rel_str);
1183                          for (k = 0; k < count; k++) {
1184                               compound_depend_t *cdepend = &pkg->depends[k];
1185                               int l;
1186                               for (l = 0; l < cdepend->possibility_count; l++) {
1187                                    depend_t *possibility = cdepend->possibilities[l];
1188                                    opkg_message(conf, OPKG_ERROR, "    %s", possibility->pkg->name);
1189                                    if (conf->verbosity > 0) {
1190                                         // char *ver = abstract_pkg_version_str_alloc(possibility->pkg); 
1191                                         opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
1192                                         if (possibility->version) {
1193                                              char *typestr = NULL;
1194                                              switch (possibility->constraint) {
1195                                              case NONE: typestr = "none"; break;
1196                                              case EARLIER: typestr = "<"; break;
1197                                              case EARLIER_EQUAL: typestr = "<="; break;
1198                                              case EQUAL: typestr = "="; break;
1199                                              case LATER_EQUAL: typestr = ">="; break;
1200                                              case LATER: typestr = ">"; break;
1201                                              }
1202                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1203                                         }
1204                                         // free(ver);
1205                                    }
1206                                    opkg_message(conf, OPKG_ERROR, "\n");
1207                               }
1208                          }
1209                     }
1210                }
1211           }
1212           pkg_vec_free(available_pkgs);
1213      }
1214      return 0;
1215 }
1216
1217 enum what_field_type {
1218   WHATDEPENDS,
1219   WHATCONFLICTS,
1220   WHATPROVIDES,
1221   WHATREPLACES,
1222   WHATRECOMMENDS,
1223   WHATSUGGESTS
1224 };
1225
1226 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int recursive, int argc, char **argv)
1227 {
1228
1229      if (argc > 0) {
1230           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1231           const char *rel_str = NULL;
1232           int i;
1233           int changed;
1234
1235           switch (what_field_type) {
1236           case WHATDEPENDS: rel_str = "depends on"; break;
1237           case WHATCONFLICTS: rel_str = "conflicts with"; break;
1238           case WHATSUGGESTS: rel_str = "suggests"; break;
1239           case WHATRECOMMENDS: rel_str = "recommends"; break;
1240           case WHATPROVIDES: rel_str = "provides"; break;
1241           case WHATREPLACES: rel_str = "replaces"; break;
1242           }
1243      
1244           if (conf->query_all)
1245                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1246           else
1247                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1248
1249           /* mark the root set */
1250           pkg_vec_clear_marks(available_pkgs);
1251           opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1252           for (i = 0; i < argc; i++) {
1253                const char *dependee_pattern = argv[i];
1254                pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1255           }
1256           for (i = 0; i < available_pkgs->len; i++) {
1257                pkg_t *pkg = available_pkgs->pkgs[i];
1258                if (pkg->state_flag & SF_MARKED) {
1259                     /* mark the parent (abstract) package */
1260                     pkg_mark_provides(pkg);
1261                     opkg_message(conf, OPKG_NOTICE, "  %s\n", pkg->name);
1262                }
1263           }
1264
1265           opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1266           do {
1267                int j;
1268                changed = 0;
1269
1270                for (j = 0; j < available_pkgs->len; j++) {
1271                     pkg_t *pkg = available_pkgs->pkgs[j];
1272                     int k;
1273                     int count = ((what_field_type == WHATCONFLICTS)
1274                                  ? pkg->conflicts_count
1275                                  : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1276                     /* skip this package if it is already marked */
1277                     if (pkg->parent->state_flag & SF_MARKED) {
1278                          continue;
1279                     }
1280                     for (k = 0; k < count; k++) {
1281                          compound_depend_t *cdepend = 
1282                               (what_field_type == WHATCONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1283                          int l;
1284                          for (l = 0; l < cdepend->possibility_count; l++) {
1285                               depend_t *possibility = cdepend->possibilities[l];
1286                               if (possibility->pkg->state_flag & SF_MARKED) {
1287                                    /* mark the depending package so we won't visit it again */
1288                                    pkg->state_flag |= SF_MARKED;
1289                                    pkg_mark_provides(pkg);
1290                                    changed++;
1291
1292                                    opkg_message(conf, OPKG_NOTICE, "    %s", pkg->name);
1293                                    if (conf->verbosity > 0) {
1294                                         char *ver = pkg_version_str_alloc(pkg); 
1295                                         opkg_message(conf, OPKG_NOTICE, " %s", ver);
1296                                         opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1297                                         if (possibility->version) {
1298                                              char *typestr = NULL;
1299                                              switch (possibility->constraint) {
1300                                              case NONE: typestr = "none"; break;
1301                                              case EARLIER: typestr = "<"; break;
1302                                              case EARLIER_EQUAL: typestr = "<="; break;
1303                                              case EQUAL: typestr = "="; break;
1304                                              case LATER_EQUAL: typestr = ">="; break;
1305                                              case LATER: typestr = ">"; break;
1306                                              }
1307                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1308                                         }
1309                                         free(ver);
1310                                         if (!pkg_dependence_satisfiable(conf, possibility))
1311                                              opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1312                                    }
1313                                    opkg_message(conf, OPKG_NOTICE, "\n");
1314                                    goto next_package;
1315                               }
1316                          }
1317                     }
1318                next_package:
1319                     ;
1320                }
1321           } while (changed && recursive);
1322           pkg_vec_free(available_pkgs);
1323      }
1324
1325      return 0;
1326 }
1327
1328 int pkg_mark_provides(pkg_t *pkg)
1329 {
1330      int provides_count = pkg->provides_count;
1331      abstract_pkg_t **provides = pkg->provides;
1332      int i;
1333      pkg->parent->state_flag |= SF_MARKED;
1334      for (i = 0; i < provides_count; i++) {
1335           provides[i]->state_flag |= SF_MARKED;
1336      }
1337      return 0;
1338 }
1339
1340 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1341 {
1342      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 1, argc, argv);
1343 }
1344 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1345 {
1346      return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 0, argc, argv);
1347 }
1348
1349 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1350 {
1351      return opkg_what_depends_conflicts_cmd(conf, WHATSUGGESTS, 0, argc, argv);
1352 }
1353
1354 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1355 {
1356      return opkg_what_depends_conflicts_cmd(conf, WHATRECOMMENDS, 0, argc, argv);
1357 }
1358
1359 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1360 {
1361      return opkg_what_depends_conflicts_cmd(conf, WHATCONFLICTS, 0, argc, argv);
1362 }
1363
1364 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1365 {
1366
1367      if (argc > 0) {
1368           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1369           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1370           int i;
1371      
1372           pkg_info_preinstall_check(conf);
1373
1374           if (conf->query_all)
1375                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1376           else
1377                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1378           for (i = 0; i < argc; i++) {
1379                const char *target = argv[i];
1380                int j;
1381
1382                opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1383                             rel_str, target);
1384                for (j = 0; j < available_pkgs->len; j++) {
1385                     pkg_t *pkg = available_pkgs->pkgs[j];
1386                     int k;
1387                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1388                     for (k = 0; k < count; k++) {
1389                          abstract_pkg_t *apkg = 
1390                               ((what_field_type == WHATPROVIDES) 
1391                                ? pkg->provides[k]
1392                                : pkg->replaces[k]);
1393                          if (fnmatch(target, apkg->name, 0) == 0) {
1394                               opkg_message(conf, OPKG_ERROR, "    %s", pkg->name);
1395                               if (strcmp(target, apkg->name) != 0)
1396                                    opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1397                               opkg_message(conf, OPKG_ERROR, "\n");
1398                          }
1399                     }
1400                }
1401           }
1402           pkg_vec_free(available_pkgs);
1403      }
1404      return 0;
1405 }
1406
1407 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1408 {
1409      return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1410 }
1411
1412 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1413 {
1414      return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1415 }
1416
1417 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1418 {
1419      int i;
1420
1421      pkg_vec_t *installed;
1422      pkg_t *pkg;
1423      str_list_t *installed_files;
1424      str_list_elt_t *iter;
1425      char *installed_file;
1426
1427      if (argc < 1) {
1428           return EINVAL;
1429      }
1430  
1431      installed = pkg_vec_alloc();
1432      pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1433
1434      for (i=0; i < installed->len; i++) {
1435           pkg = installed->pkgs[i];
1436
1437           installed_files = pkg_get_installed_files(pkg);
1438
1439           for (iter = installed_files->head; iter; iter = iter->next) {
1440                installed_file = iter->data;
1441                if (fnmatch(argv[0], installed_file, 0)==0)  {
1442                         if (opkg_cb_list) opkg_cb_list(pkg->name, 
1443                                                        installed_file, 
1444                                                        pkg_version_str_alloc(pkg), 
1445                                                        pkg->state_status, p_userdata);
1446                }                
1447           }
1448
1449           pkg_free_installed_files(pkg);
1450      }
1451
1452      /* XXX: CLEANUP: It's not obvious from the name of
1453         pkg_hash_fetch_all_installed that we need to call
1454         pkg_vec_free to avoid a memory leak. */
1455      pkg_vec_free(installed);
1456
1457      return 0;
1458 }
1459
1460 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1461 {
1462      if (argc == 3) {
1463           /* this is a bit gross */
1464           struct pkg p1, p2;
1465           parseVersion(&p1, argv[0]); 
1466           parseVersion(&p2, argv[2]); 
1467           return pkg_version_satisfied(&p1, &p2, argv[1]);
1468      } else {
1469           opkg_message(conf, OPKG_ERROR,
1470                        "opkg compare_versions <v1> <op> <v2>\n"
1471                        "<op> is one of <= >= << >> =\n");
1472           return -1;
1473      }
1474 }
1475
1476 #ifndef HOST_CPU_STR
1477 #define HOST_CPU_STR__(X) #X
1478 #define HOST_CPU_STR_(X) HOST_CPU_STR__(X)
1479 #define HOST_CPU_STR HOST_CPU_STR_(HOST_CPU_FOO)
1480 #endif
1481
1482 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1483 {
1484      nv_pair_list_elt_t *l;
1485
1486      l = conf->arch_list.head;
1487      while (l) {
1488           nv_pair_t *nv = l->data;
1489           printf("arch %s %s\n", nv->name, nv->value);
1490           l = l->next;
1491      }
1492      return 0;
1493 }
1494
1495