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