Remove unused parameter from pkg_hash_fetch_best_installation_candidate().
[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 #include <fnmatch.h>
23
24 #include "opkg_conf.h"
25 #include "opkg_cmd.h"
26 #include "opkg_message.h"
27 #include "pkg.h"
28 #include "pkg_dest.h"
29 #include "pkg_parse.h"
30 #include "sprintf_alloc.h"
31 #include "pkg.h"
32 #include "file_util.h"
33 #include "libbb/libbb.h"
34 #include "opkg_utils.h"
35 #include "opkg_defines.h"
36 #include "opkg_download.h"
37 #include "opkg_install.h"
38 #include "opkg_upgrade.h"
39 #include "opkg_remove.h"
40 #include "opkg_configure.h"
41 #include "opkg_message.h"
42 #include "libopkg.h"
43 #include "xsystem.h"
44
45 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv);
46 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv);
47 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv);
48 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv);
49 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv);
50 static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv);
51 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv);
52 static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv);
53 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv);
54 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv);
55 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv);
56 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv);
57 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv);
58 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv);
59 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv);
60 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv);
61 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv);
62 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv);
63 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv);
64 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv);
65 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv);
66 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv);
67 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv);
68 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv);
69 static int pkg_mark_provides(pkg_t *pkg);
70
71 /* XXX: CLEANUP: The usage strings should be incorporated into this
72    array for easier maintenance */
73 static opkg_cmd_t cmds[] = {
74      {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd}, 
75      {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd},
76      {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd},
77      {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd},
78      {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd},
79      {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd},
80      {"list-upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd},
81      {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd},
82      {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd},
83      {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd},
84      {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd},
85      {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd},
86      {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd},
87      {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd},
88      {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd},
89      {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd},
90      {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
91      {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
92      {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
93      {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
94      {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
95      {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
96      {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd},
97      {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd},
98      {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd},
99      {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd},
100      {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd},
101      {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd},
102      {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd},
103      {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd},
104 };
105
106 static void print_pkg(pkg_t *pkg)
107 {
108         char *version = pkg_version_str_alloc(pkg);
109         if (pkg->description)
110                 printf("%s - %s - %s\n", pkg->name, version, pkg->description);
111         else
112                 printf("%s - %s\n", pkg->name, version);
113         free(version);
114 }
115
116 int opkg_state_changed;
117 static void write_status_files_if_changed(opkg_conf_t *conf)
118 {
119      if (opkg_state_changed && !conf->noaction) {
120           opkg_message(conf, OPKG_INFO,
121                        "  writing status file\n");
122           opkg_conf_write_status_files(conf);
123           pkg_write_changed_filelists(conf);
124      } else { 
125           opkg_message(conf, OPKG_DEBUG, "Nothing to be done\n");
126      }
127 }
128
129
130 static int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
131
132 opkg_cmd_t *opkg_cmd_find(const char *name)
133 {
134      int i;
135      opkg_cmd_t *cmd;
136
137      for (i=0; i < num_cmds; i++) {
138           cmd = &cmds[i];
139           if (strcmp(name, cmd->name) == 0) {
140                return cmd;
141           }
142      }
143
144      return NULL;
145 }
146
147 int opkg_cmd_exec(opkg_cmd_t *cmd, opkg_conf_t *conf, int argc, const char **argv, void *userdata)
148 {
149         int result;
150
151         result = (cmd->fun)(conf, argc, argv);
152
153         print_error_list();
154         free_error_list();
155
156         return result;
157 }
158
159 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
160 {
161      char *tmp;
162      int err;
163      int failures;
164      char *lists_dir;
165      pkg_src_list_elt_t *iter;
166      pkg_src_t *src;
167
168  
169     sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir);
170  
171     if (! file_is_dir(lists_dir)) {
172           if (file_exists(lists_dir)) {
173                opkg_message(conf, OPKG_ERROR,
174                             "%s: ERROR: %s exists, but is not a directory\n",
175                             __FUNCTION__, lists_dir);
176                free(lists_dir);
177                return -1;
178           }
179           err = file_mkdir_hier(lists_dir, 0755);
180           if (err) {
181                opkg_message(conf, OPKG_ERROR,
182                             "%s: ERROR: failed to make directory %s: %s\n",
183                             __FUNCTION__, lists_dir, strerror(errno));
184                free(lists_dir);
185                return -1;
186           }     
187      } 
188
189      failures = 0;
190
191      sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir);
192      if (mkdtemp (tmp) == NULL) {
193          perror ("mkdtemp");
194          return -1;
195      }
196
197
198      for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) {
199           char *url, *list_file_name;
200
201           src = (pkg_src_t *)iter->data;
202
203           if (src->extra_data)  /* debian style? */
204               sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, 
205                             src->gzip ? "Packages.gz" : "Packages");
206           else
207               sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
208
209           sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
210           if (src->gzip) {
211               char *tmp_file_name;
212               FILE *in, *out;
213               
214               sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
215               err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
216               if (err == 0) {
217                    opkg_message (conf, OPKG_NOTICE, "Inflating %s\n", url);
218                    in = fopen (tmp_file_name, "r");
219                    out = fopen (list_file_name, "w");
220                    if (in && out)
221                         unzip (in, out);
222                    else
223                         err = 1;
224                    if (in)
225                         fclose (in);
226                    if (out)
227                         fclose (out);
228                    unlink (tmp_file_name);
229               }
230               free(tmp_file_name);
231           } else
232               err = opkg_download(conf, url, list_file_name, NULL, NULL);
233           if (err) {
234                failures++;
235           } else {
236                opkg_message(conf, OPKG_NOTICE,
237                             "Updated list of available packages in %s\n",
238                             list_file_name);
239           }
240           free(url);
241 #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
242           if (conf->check_signature) {
243               /* download detached signitures to verify the package lists */
244               /* get the url for the sig file */
245               if (src->extra_data)      /* debian style? */
246                   sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data,
247                           "Packages.sig");
248               else
249                   sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig");
250
251               /* create temporary file for it */
252               char *tmp_file_name;
253
254               /* Put the signature in the right place */
255               sprintf_alloc (&tmp_file_name, "%s/%s.sig", lists_dir, src->name);
256
257               err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
258               if (err) {
259                   failures++;
260                   opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
261               } else {
262                   int err;
263                   err = opkg_verify_file (conf, list_file_name, tmp_file_name);
264                   if (err == 0)
265                       opkg_message (conf, OPKG_NOTICE, "Signature check passed\n");
266                   else
267                       opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
268               }
269               /* We shouldn't unlink the signature ! */
270               // unlink (tmp_file_name);
271               free (tmp_file_name);
272               free (url);
273           }
274 #else
275           // Do nothing
276 #endif
277           free(list_file_name);
278      }
279      rmdir (tmp);
280      free (tmp);
281      free(lists_dir);
282
283      return failures;
284 }
285
286
287 struct opkg_intercept
288 {
289     char *oldpath;
290     char *statedir;
291 };
292
293 typedef struct opkg_intercept *opkg_intercept_t;
294
295 static opkg_intercept_t opkg_prep_intercepts(opkg_conf_t *conf)
296 {
297     opkg_intercept_t ctx;
298     char *newpath;
299
300     ctx = xcalloc(1, sizeof (*ctx));
301     ctx->oldpath = xstrdup(getenv("PATH"));
302     sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
303     sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX", conf->tmp_dir);
304
305     if (mkdtemp(ctx->statedir) == NULL) {
306         fprintf(stderr, "%s: mkdtemp: %s\n", __FUNCTION__, strerror(errno));
307         free(ctx->oldpath);
308         free(ctx->statedir);
309         free(newpath);
310         free(ctx);
311         return NULL;
312     }
313
314     setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
315     setenv("PATH", newpath, 1);
316     free(newpath);
317
318     return ctx;
319 }
320
321 static int opkg_finalize_intercepts(opkg_intercept_t ctx)
322 {
323     DIR *dir;
324     int err = 0;
325
326     setenv ("PATH", ctx->oldpath, 1);
327     free (ctx->oldpath);
328
329     dir = opendir (ctx->statedir);
330     if (dir) {
331         struct dirent *de;
332         while (de = readdir (dir), de != NULL) {
333             char *path;
334
335             if (de->d_name[0] == '.')
336                 continue;
337             
338             sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name);
339             if (access (path, X_OK) == 0) {
340                 const char *argv[] = {"sh", "-c", path, NULL};
341                 xsystem (argv);
342             }
343             free (path);
344         }
345         closedir(dir);
346     } else
347         perror (ctx->statedir);
348         
349     rm_r(ctx->statedir);
350     free (ctx->statedir);
351     free (ctx);
352
353     return err;
354 }
355
356 /* For package pkg do the following: If it is already visited, return. If not,
357    add it in visited list and recurse to its deps. Finally, add it to ordered 
358    list.
359    pkg_vec all contains all available packages in repos.
360    pkg_vec visited contains packages already visited by this function, and is 
361    used to end recursion and avoid an infinite loop on graph cycles.
362    pkg_vec ordered will finally contain the ordered set of packages.
363 */
364 static int opkg_recurse_pkgs_in_order(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *all,
365                                pkg_vec_t *visited, pkg_vec_t *ordered)
366 {
367     int j,k,l,m;
368     int count;
369     pkg_t *dep;
370     compound_depend_t * compound_depend;
371     depend_t ** possible_satisfiers;
372     abstract_pkg_t *abpkg;
373     abstract_pkg_t **dependents;
374
375     /* If it's just an available package, that is, not installed and not even
376        unpacked, skip it */
377     /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED 
378        would do here. However, if there is an intermediate node (pkg) that is 
379        configured and installed between two unpacked packages, the latter 
380        won't be properly reordered, unless all installed/unpacked pkgs are
381        checked */
382     if (pkg->state_status == SS_NOT_INSTALLED) 
383         return 0;
384
385     /* If the  package has already been visited (by this function), skip it */
386     for(j = 0; j < visited->len; j++) 
387         if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) {
388             opkg_message(conf, OPKG_INFO,
389                          "  pkg: %s already visited\n", pkg->name);
390             return 0;
391         }
392     
393     pkg_vec_insert(visited, pkg);
394
395     count = pkg->pre_depends_count + pkg->depends_count + \
396         pkg->recommends_count + pkg->suggests_count;
397
398     opkg_message(conf, OPKG_INFO,
399                  "  pkg: %s\n", pkg->name);
400
401     /* Iterate over all the dependencies of pkg. For each one, find a package 
402        that is either installed or unpacked and satisfies this dependency.
403        (there should only be one such package per dependency installed or 
404        unpacked). Then recurse to the dependency package */
405     for (j=0; j < count ; j++) {
406         compound_depend = &pkg->depends[j];
407         possible_satisfiers = compound_depend->possibilities;
408         for (k=0; k < compound_depend->possibility_count ; k++) {
409             abpkg = possible_satisfiers[k]->pkg;
410             dependents = abpkg->provided_by->pkgs;
411             l = 0;
412             if (dependents != NULL)
413                 while (l < abpkg->provided_by->len && dependents[l] != NULL) {
414                     opkg_message(conf, OPKG_INFO,
415                                  "  Descending on pkg: %s\n", 
416                                  dependents [l]->name);
417     
418                     /* find whether dependent l is installed or unpacked,
419                      * and then find which package in the list satisfies it */
420                     for(m = 0; m < all->len; m++) {
421                         dep = all->pkgs[m];
422                         if ( dep->state_status != SS_NOT_INSTALLED)
423                             if ( ! strcmp(dep->name, dependents[l]->name)) {
424                                 opkg_recurse_pkgs_in_order(conf, dep, all, 
425                                                            visited, ordered);
426                                 /* Stop the outer loop */
427                                 l = abpkg->provided_by->len;
428                                 /* break from the inner loop */
429                                 break;
430                             }
431                     }
432                     l++;
433                 }
434         }
435     }
436
437     /* When all recursions from this node down, are over, and all 
438        dependencies have been added in proper order in the ordered array, add
439        also the package pkg to ordered array */
440     pkg_vec_insert(ordered, pkg);
441
442     return 0;
443
444 }
445
446 static int opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
447 {
448      pkg_vec_t *all, *ordered, *visited;
449      int i;
450      pkg_t *pkg;
451      opkg_intercept_t ic;
452      int r, err = 0;
453
454      opkg_message(conf, OPKG_INFO,
455                   "Configuring unpacked packages\n");
456      fflush( stdout );
457
458      all = pkg_vec_alloc();
459
460      pkg_hash_fetch_available(&conf->pkg_hash, all);
461
462      /* Reorder pkgs in order to be configured according to the Depends: tag
463         order */
464      opkg_message(conf, OPKG_INFO,
465                   "Reordering packages before configuring them...\n");
466      ordered = pkg_vec_alloc();
467      visited = pkg_vec_alloc();
468      for(i = 0; i < all->len; i++) {
469          pkg = all->pkgs[i];
470          opkg_recurse_pkgs_in_order(conf, pkg, all, visited, ordered);
471      }
472
473      ic = opkg_prep_intercepts (conf);
474      if (ic == NULL) {
475              err = -1;
476              goto error;
477      }
478     
479      for(i = 0; i < all->len; i++) {
480           pkg = all->pkgs[i];
481
482           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
483                continue;
484
485           if (pkg->state_status == SS_UNPACKED) {
486                opkg_message(conf, OPKG_NOTICE,
487                             "Configuring %s\n", pkg->name);
488                fflush( stdout );
489                r = opkg_configure(conf, pkg);
490                if (r == 0) {
491                     pkg->state_status = SS_INSTALLED;
492                     pkg->parent->state_status = SS_INSTALLED;
493                     pkg->state_flag &= ~SF_PREFER;
494                } else {
495                     if (!err)
496                         err = r;
497                }
498           }
499      }
500
501      r = opkg_finalize_intercepts (ic);
502      if (r && !err)
503          err = r;
504
505 error:
506      pkg_vec_free(all);
507      pkg_vec_free(ordered);
508      pkg_vec_free(visited);
509
510      return err;
511 }
512
513 static opkg_conf_t *global_conf;
514
515 static void sigint_handler(int sig)
516 {
517      signal(sig, SIG_DFL);
518      opkg_message(NULL, OPKG_NOTICE,
519                   "opkg: interrupted. writing out status database\n");
520      write_status_files_if_changed(global_conf);
521      exit(128 + sig);
522 }
523
524 static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv)
525 {
526      int i;
527      char *arg;
528      int err=0;
529
530      global_conf = conf;
531      signal(SIGINT, sigint_handler);
532
533      /*
534       * Now scan through package names and install
535       */
536      for (i=0; i < argc; i++) {
537           arg = argv[i];
538
539           opkg_message(conf, OPKG_DEBUG2, "Debug install_cmd: %s  \n",arg );
540           err = opkg_prepare_url_for_install(conf, arg, &argv[i]);
541           if (err)
542               return err;
543      }
544      pkg_info_preinstall_check(conf);
545
546      for (i=0; i < argc; i++) {
547           arg = argv[i];
548           err = opkg_install_by_name(conf, arg);
549           if (err) {
550                opkg_message(conf, OPKG_ERROR, "Cannot find package %s.\n", arg);
551           }
552      }
553
554      opkg_configure_packages(conf, NULL);
555
556      write_status_files_if_changed(conf);
557
558      return err;
559 }
560
561 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv)
562 {
563      int i;
564      pkg_t *pkg;
565      int err;
566
567      global_conf = conf;
568      signal(SIGINT, sigint_handler);
569
570      if (argc) {
571           for (i=0; i < argc; i++) {
572                char *arg = argv[i];
573
574                err = opkg_prepare_url_for_install(conf, arg, &arg);
575                if (err)
576                    return err;
577           }
578           pkg_info_preinstall_check(conf);
579
580           for (i=0; i < argc; i++) {
581                char *arg = argv[i];
582                if (conf->restrict_to_default_dest) {
583                     pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
584                                                                 argv[i],
585                                                                 conf->default_dest);
586                     if (pkg == NULL) {
587                          opkg_message(conf, OPKG_NOTICE,
588                                       "Package %s not installed in %s\n",
589                                       argv[i], conf->default_dest->name);
590                          continue;
591                     }
592                } else {
593                     pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
594                                                            argv[i]);
595                }
596                if (pkg)
597                     opkg_upgrade_pkg(conf, pkg);
598                else {
599                     opkg_install_by_name(conf, arg);
600                }
601           }
602      } else {
603           pkg_vec_t *installed = pkg_vec_alloc();
604
605           pkg_info_preinstall_check(conf);
606
607           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
608           for (i = 0; i < installed->len; i++) {
609                pkg = installed->pkgs[i];
610                opkg_upgrade_pkg(conf, pkg);
611           }
612           pkg_vec_free(installed);
613      }
614
615      opkg_configure_packages(conf, NULL);
616
617      write_status_files_if_changed(conf);
618
619      return 0;
620 }
621
622 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv)
623 {
624      int i, err;
625      char *arg;
626      pkg_t *pkg;
627
628      pkg_info_preinstall_check(conf);
629      for (i = 0; i < argc; i++) {
630           arg = argv[i];
631
632           pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, arg);
633           if (pkg == NULL) {
634                opkg_message(conf, OPKG_ERROR,
635                             "Cannot find package %s.\n"
636                             "Check the spelling or perhaps run 'opkg update'\n",
637                             arg);
638                continue;
639           }
640
641           err = opkg_download_pkg(conf, pkg, ".");
642
643           if (err) {
644                opkg_message(conf, OPKG_ERROR,
645                             "Failed to download %s\n", pkg->name);
646           } else {
647                opkg_message(conf, OPKG_NOTICE,
648                             "Downloaded %s as %s\n",
649                             pkg->name, pkg->local_filename);
650           }
651      }
652
653      return 0;
654 }
655
656
657 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv)
658 {
659      int i;
660      pkg_vec_t *available;
661      pkg_t *pkg;
662      char *pkg_name = NULL;
663
664      if (argc > 0) {
665           pkg_name = argv[0];
666      }
667      available = pkg_vec_alloc();
668      pkg_hash_fetch_available(&conf->pkg_hash, available);
669      pkg_vec_sort(available, pkg_compare_names);
670      for (i=0; i < available->len; i++) {
671           pkg = available->pkgs[i];
672           /* if we have package name or pattern and pkg does not match, then skip it */
673           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
674                continue;
675           print_pkg(pkg);
676      }
677      pkg_vec_free(available);
678
679      return 0;
680 }
681
682
683 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
684 {
685      int i ;
686      pkg_vec_t *available;
687      pkg_t *pkg;
688      char *pkg_name = NULL;
689
690      if (argc > 0) {
691           pkg_name = argv[0];
692      }
693      available = pkg_vec_alloc();
694      pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
695      pkg_vec_sort(available, pkg_compare_names);
696      for (i=0; i < available->len; i++) {
697           pkg = available->pkgs[i];
698           /* if we have package name or pattern and pkg does not match, then skip it */
699           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
700                continue;
701           print_pkg(pkg);
702      }
703
704      pkg_vec_free(available);
705
706      return 0;
707 }
708
709 static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv) 
710 {
711     struct active_list *head = prepare_upgrade_list(conf);
712     struct active_list *node=NULL;
713     pkg_t *_old_pkg, *_new_pkg;
714     char *old_v, *new_v;
715     for (node = active_list_next(head, head); node;node = active_list_next(head,node)) {
716         _old_pkg = list_entry(node, pkg_t, list);
717         _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, _old_pkg->name);
718         if (_new_pkg == NULL)
719                 continue;
720         old_v = pkg_version_str_alloc(_old_pkg);
721         new_v = pkg_version_str_alloc(_new_pkg);
722         printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
723         free(old_v);
724         free(new_v);
725     }
726     active_list_head_delete(head);
727     return 0;
728 }
729
730 static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int installed_only)
731 {
732      int i;
733      pkg_vec_t *available;
734      pkg_t *pkg;
735      char *pkg_name = NULL;
736
737      if (argc > 0) {
738           pkg_name = argv[0];
739      }
740
741      available = pkg_vec_alloc();
742      if (installed_only)
743           pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
744      else
745           pkg_hash_fetch_available(&conf->pkg_hash, available);
746
747      for (i=0; i < available->len; i++) {
748           pkg = available->pkgs[i];
749           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
750                continue;
751           }
752
753           pkg_formatted_info(stdout, pkg);
754
755           if (conf->verbosity >= OPKG_NOTICE) {
756                conffile_list_elt_t *iter;
757                for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
758                     conffile_t *cf = (conffile_t *)iter->data;
759                     int modified = conffile_has_been_modified(conf, cf);
760                     if (cf->value)
761                         opkg_message(conf, OPKG_INFO,
762                                 "conffile=%s md5sum=%s modified=%d\n",
763                                  cf->name, cf->value, modified);
764                }
765           }
766      }
767      pkg_vec_free(available);
768
769      return 0;
770 }
771
772 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv)
773 {
774      return opkg_info_status_cmd(conf, argc, argv, 0);
775 }
776
777 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv)
778 {
779      return opkg_info_status_cmd(conf, argc, argv, 1);
780 }
781
782 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv)
783 {
784      
785      int err;
786      if (argc > 0) {
787           char *pkg_name = NULL;
788
789           pkg_name = argv[0];
790
791           err = opkg_configure_packages (conf, pkg_name);
792      
793      } else {
794           err = opkg_configure_packages (conf, NULL);
795      }
796
797      write_status_files_if_changed(conf);
798
799      return err;
800 }
801
802 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv)
803 {
804      int i, a, done;
805      pkg_t *pkg;
806      pkg_t *pkg_to_remove;
807      pkg_vec_t *available;
808
809      global_conf = conf;
810      done = 0;
811
812      signal(SIGINT, sigint_handler);
813
814      pkg_info_preinstall_check(conf);
815
816      available = pkg_vec_alloc();
817      pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
818
819      for (i=0; i<argc; i++) {
820         for (a=0; a<available->len; a++) {
821             pkg = available->pkgs[a];
822             if (fnmatch(argv[i], pkg->name, 0)) {
823                continue;
824             }
825             if (conf->restrict_to_default_dest) {
826                  pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
827                                         pkg->name,
828                                         conf->default_dest);
829             } else {
830                  pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
831             }
832         
833             if (pkg_to_remove == NULL) {
834                  opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
835                  continue;
836             }
837             if (pkg->state_status == SS_NOT_INSTALLED) {    // Added the control, so every already removed package could be skipped
838                  opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
839                  continue;
840             }
841             opkg_remove_pkg(conf, pkg_to_remove, 0);
842             done = 1;
843         }
844      }
845
846      pkg_vec_free(available);
847
848      if (done == 0)
849         opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
850
851      write_status_files_if_changed(conf);
852      return 0;
853 }
854
855 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
856 {
857      int i;
858      pkg_t *pkg;
859      const char *flags = argv[0];
860     
861      global_conf = conf;
862      signal(SIGINT, sigint_handler);
863
864      for (i=1; i < argc; i++) {
865           if (conf->restrict_to_default_dest) {
866                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
867                                                            argv[i],
868                                                            conf->default_dest);
869           } else {
870                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
871           }
872
873           if (pkg == NULL) {
874                opkg_message(conf, OPKG_ERROR,
875                             "Package %s is not installed.\n", argv[i]);
876                continue;
877           }
878           if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
879               ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
880               pkg->state_flag = pkg_state_flag_from_str(flags);
881           }
882
883           /* 
884            * Useful if a package is installed in an offline_root, and
885            * should be configured by opkg-cl configure at a later date.
886            */
887           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
888               pkg->state_status = pkg_state_status_from_str(flags);
889           }
890
891           opkg_state_changed++;
892           opkg_message(conf, OPKG_NOTICE,
893                        "Setting flags for package %s to %s\n",
894                        pkg->name, flags);
895      }
896
897      write_status_files_if_changed(conf);
898      return 0;
899 }
900
901 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
902 {
903      pkg_t *pkg;
904      str_list_t *files;
905      str_list_elt_t *iter;
906      char *pkg_version;
907
908      if (argc < 1) {
909           return EINVAL;
910      }
911
912      pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
913                                             argv[0]);
914      if (pkg == NULL) {
915           opkg_message(conf, OPKG_ERROR,
916                        "Package %s not installed.\n", argv[0]);
917           return 0;
918      }
919
920      files = pkg_get_installed_files(conf, pkg);
921      pkg_version = pkg_version_str_alloc(pkg);
922
923      printf("Package %s (%s) is installed on %s and has the following files:\n",
924                 pkg->name, pkg_version, pkg->dest->name);
925
926      for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
927           printf("%s\n", (char *)iter->data);
928
929      free(pkg_version);
930      pkg_free_installed_files(pkg);
931
932      return 0;
933 }
934
935 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
936 {
937         int i, j, k;
938         int depends_count;
939         pkg_vec_t *available_pkgs;
940         compound_depend_t *cdep;
941         pkg_t *pkg;
942         char *str;
943
944         pkg_info_preinstall_check(conf);
945
946         available_pkgs = pkg_vec_alloc();
947         if (conf->query_all)
948                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
949         else
950                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
951
952         for (i=0; i<argc; i++) {
953                 for (j=0; j<available_pkgs->len; j++) {
954                         pkg = available_pkgs->pkgs[j];
955
956                         if (fnmatch(argv[i], pkg->name, 0) != 0)
957                                 continue;
958
959                         depends_count = pkg->depends_count +
960                                         pkg->pre_depends_count +
961                                         pkg->recommends_count +
962                                         pkg->suggests_count;
963
964                         opkg_message(conf, OPKG_NOTICE, "%s depends on:\n",
965                                       pkg->name);
966
967                         for (k=0; k<depends_count; k++) {
968                                 cdep = &pkg->depends[k];
969
970                                 if (cdep->type != DEPEND)
971                                       continue;
972
973                                 str = pkg_depend_str(pkg, k);
974                                 opkg_message(conf, OPKG_NOTICE, "\t%s\n", str);
975                                 free(str);
976                         }
977
978                }
979         }
980
981         pkg_vec_free(available_pkgs);
982         return 0;
983 }
984
985 enum what_field_type {
986   WHATDEPENDS,
987   WHATCONFLICTS,
988   WHATPROVIDES,
989   WHATREPLACES,
990   WHATRECOMMENDS,
991   WHATSUGGESTS
992 };
993
994 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum depend_type what_field_type, int recursive, int argc, char **argv)
995 {
996         depend_t *possibility;
997         compound_depend_t *cdep;
998         pkg_vec_t *available_pkgs;
999         pkg_t *pkg;
1000         int i, j, k, l;
1001         int changed, count;
1002         const char *rel_str = NULL;
1003         char *ver;
1004
1005         switch (what_field_type) {
1006         case DEPEND: rel_str = "depends on"; break;
1007         case CONFLICTS: rel_str = "conflicts with"; break;
1008         case SUGGEST: rel_str = "suggests"; break;
1009         case RECOMMEND: rel_str = "recommends"; break;
1010         default: return -1;
1011         }
1012      
1013         available_pkgs = pkg_vec_alloc();
1014
1015         if (conf->query_all)
1016                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1017         else
1018                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1019
1020         /* mark the root set */
1021         pkg_vec_clear_marks(available_pkgs);
1022         opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1023         for (i = 0; i < argc; i++)
1024                pkg_vec_mark_if_matches(available_pkgs, argv[i]);
1025
1026         for (i = 0; i < available_pkgs->len; i++) {
1027                pkg = available_pkgs->pkgs[i];
1028                if (pkg->state_flag & SF_MARKED) {
1029                     /* mark the parent (abstract) package */
1030                     pkg_mark_provides(pkg);
1031                     opkg_message(conf, OPKG_NOTICE, "  %s\n", pkg->name);
1032                }
1033         }
1034
1035         opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1036         do {
1037                 changed = 0;
1038
1039                 for (j=0; j<available_pkgs->len; j++) {
1040
1041                         pkg = available_pkgs->pkgs[j];
1042                         count = ((what_field_type == CONFLICTS)
1043                                  ? pkg->conflicts_count
1044                                  : pkg->pre_depends_count +
1045                                  pkg->depends_count +
1046                                  pkg->recommends_count +
1047                                  pkg->suggests_count);
1048
1049                         /* skip this package if it is already marked */
1050                         if (pkg->parent->state_flag & SF_MARKED)
1051                                 continue;
1052
1053                         for (k=0; k<count; k++) {
1054                                 cdep = (what_field_type == CONFLICTS)
1055                                         ? &pkg->conflicts[k]
1056                                         : &pkg->depends[k];
1057
1058                                 if (what_field_type != cdep->type)
1059                                         continue;
1060
1061                                 for (l=0; l<cdep->possibility_count; l++) {
1062                                         possibility = cdep->possibilities[l];
1063
1064                                         if ((possibility->pkg->state_flag
1065                                                                 & SF_MARKED)
1066                                                         != SF_MARKED)
1067                                                 continue;
1068                                         
1069                                         /* mark the depending package so we
1070                                         * won't visit it again */
1071                                         pkg->state_flag |= SF_MARKED;
1072                                         pkg_mark_provides(pkg);
1073                                         changed++;
1074
1075                                         ver = pkg_version_str_alloc(pkg); 
1076                                         opkg_message(conf, OPKG_NOTICE,
1077                                                         "\t%s %s\t%s %s",
1078                                                         pkg->name,
1079                                                         ver,
1080                                                         rel_str,
1081                                                         possibility->pkg->name);
1082                                         free(ver);
1083                                         if (possibility->version) {
1084                                                 opkg_message(conf, OPKG_NOTICE,
1085                                                         " (%s%s)",
1086                                                         constraint_to_str(possibility->constraint),
1087                                                         possibility->version);
1088                                         }
1089                                         if (!pkg_dependence_satisfiable(conf, possibility))
1090                                                 opkg_message(conf, OPKG_NOTICE,
1091                                                         " unsatisfiable");
1092                                         opkg_message(conf, OPKG_NOTICE, "\n");
1093                                         goto next_package;
1094                                 }
1095                         }
1096 next_package:
1097                         ;
1098                 }
1099         } while (changed && recursive);
1100
1101         pkg_vec_free(available_pkgs);
1102
1103         return 0;
1104 }
1105
1106 static int pkg_mark_provides(pkg_t *pkg)
1107 {
1108      int provides_count = pkg->provides_count;
1109      abstract_pkg_t **provides = pkg->provides;
1110      int i;
1111      pkg->parent->state_flag |= SF_MARKED;
1112      for (i = 0; i < provides_count; i++) {
1113           provides[i]->state_flag |= SF_MARKED;
1114      }
1115      return 0;
1116 }
1117
1118 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1119 {
1120      return opkg_what_depends_conflicts_cmd(conf, DEPEND, 1, argc, argv);
1121 }
1122 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1123 {
1124      return opkg_what_depends_conflicts_cmd(conf, DEPEND, 0, argc, argv);
1125 }
1126
1127 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1128 {
1129      return opkg_what_depends_conflicts_cmd(conf, SUGGEST, 0, argc, argv);
1130 }
1131
1132 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1133 {
1134      return opkg_what_depends_conflicts_cmd(conf, RECOMMEND, 0, argc, argv);
1135 }
1136
1137 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1138 {
1139      return opkg_what_depends_conflicts_cmd(conf, CONFLICTS, 0, argc, argv);
1140 }
1141
1142 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1143 {
1144
1145      if (argc > 0) {
1146           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1147           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1148           int i;
1149      
1150           pkg_info_preinstall_check(conf);
1151
1152           if (conf->query_all)
1153                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1154           else
1155                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1156           for (i = 0; i < argc; i++) {
1157                const char *target = argv[i];
1158                int j;
1159
1160                opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1161                             rel_str, target);
1162                for (j = 0; j < available_pkgs->len; j++) {
1163                     pkg_t *pkg = available_pkgs->pkgs[j];
1164                     int k;
1165                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1166                     for (k = 0; k < count; k++) {
1167                          abstract_pkg_t *apkg = 
1168                               ((what_field_type == WHATPROVIDES) 
1169                                ? pkg->provides[k]
1170                                : pkg->replaces[k]);
1171                          if (fnmatch(target, apkg->name, 0) == 0) {
1172                               opkg_message(conf, OPKG_ERROR, "    %s", pkg->name);
1173                               if (strcmp(target, apkg->name) != 0)
1174                                    opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1175                               opkg_message(conf, OPKG_ERROR, "\n");
1176                          }
1177                     }
1178                }
1179           }
1180           pkg_vec_free(available_pkgs);
1181      }
1182      return 0;
1183 }
1184
1185 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1186 {
1187      return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1188 }
1189
1190 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1191 {
1192      return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1193 }
1194
1195 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1196 {
1197      int i;
1198
1199      pkg_vec_t *installed;
1200      pkg_t *pkg;
1201      str_list_t *installed_files;
1202      str_list_elt_t *iter;
1203      char *installed_file;
1204
1205      if (argc < 1) {
1206           return EINVAL;
1207      }
1208  
1209      installed = pkg_vec_alloc();
1210      pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1211      pkg_vec_sort(installed, pkg_compare_names);
1212
1213      for (i=0; i < installed->len; i++) {
1214           pkg = installed->pkgs[i];
1215
1216           installed_files = pkg_get_installed_files(conf, pkg);
1217
1218           for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1219                installed_file = (char *)iter->data;
1220                if (fnmatch(argv[0], installed_file, 0)==0)
1221                     print_pkg(pkg);
1222           }
1223
1224           pkg_free_installed_files(pkg);
1225      }
1226
1227      pkg_vec_free(installed);
1228
1229      return 0;
1230 }
1231
1232 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1233 {
1234      if (argc == 3) {
1235           /* this is a bit gross */
1236           struct pkg p1, p2;
1237           parse_version(&p1, argv[0]); 
1238           parse_version(&p2, argv[2]); 
1239           return pkg_version_satisfied(&p1, &p2, argv[1]);
1240      } else {
1241           opkg_message(conf, OPKG_ERROR,
1242                        "opkg compare_versions <v1> <op> <v2>\n"
1243                        "<op> is one of <= >= << >> =\n");
1244           return -1;
1245      }
1246 }
1247
1248 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1249 {
1250      nv_pair_list_elt_t *l;
1251
1252      list_for_each_entry(l, &conf->arch_list.head, node) {
1253           nv_pair_t *nv = (nv_pair_t *)l->data;
1254           printf("arch %s %s\n", nv->name, nv->value);
1255      }
1256      return 0;
1257 }