1 /* opkg_cmd.c - the opkg package management system
5 Copyright (C) 2001 University of Southern California
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.
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.
23 #include "opkg_conf.h"
25 #include "opkg_message.h"
28 #include "pkg_parse.h"
29 #include "sprintf_alloc.h"
31 #include "file_util.h"
33 #include "libbb/libbb.h"
34 #include "opkg_utils.h"
35 #include "opkg_defines.h"
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"
49 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv);
50 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv);
51 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv);
52 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv);
53 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv);
54 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv);
55 static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv);
56 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv);
57 static int opkg_list_upgradable_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 static int pkg_mark_provides(pkg_t *pkg);
77 /* XXX: CLEANUP: The usage strings should be incorporated into this
78 array for easier maintenance */
79 static opkg_cmd_t cmds[] = {
80 {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd},
81 {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd},
82 {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd},
83 {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd},
84 {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd},
85 {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd},
86 {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd},
87 {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd},
88 {"install_pending", 0, (opkg_cmd_fun_t)opkg_install_pending_cmd},
89 {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd},
90 {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd},
91 {"purge", 1, (opkg_cmd_fun_t)opkg_purge_cmd},
92 {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd},
93 {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd},
94 {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd},
95 {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd},
96 {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
97 {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
98 {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
99 {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
100 {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
101 {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
102 {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd},
103 {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd},
104 {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd},
105 {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd},
106 {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd},
107 {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd},
108 {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd},
109 {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd},
112 static void print_pkg(pkg_t *pkg)
114 char *version = pkg_version_str_alloc(pkg);
115 if (pkg->description)
116 printf("%s - %s - %s\n", pkg->name, version, pkg->description);
118 printf("%s - %s\n", pkg->name, version);
122 int opkg_state_changed;
123 static void write_status_files_if_changed(opkg_conf_t *conf)
125 if (opkg_state_changed && !conf->noaction) {
126 opkg_message(conf, OPKG_INFO,
127 " writing status file\n");
128 opkg_conf_write_status_files(conf);
129 pkg_write_changed_filelists(conf);
131 opkg_message(conf, OPKG_DEBUG, "Nothing to be done\n");
136 static int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
138 opkg_cmd_t *opkg_cmd_find(const char *name)
143 for (i=0; i < num_cmds; i++) {
145 if (strcmp(name, cmd->name) == 0) {
153 int opkg_cmd_exec(opkg_cmd_t *cmd, opkg_conf_t *conf, int argc, const char **argv, void *userdata)
157 result = (cmd->fun)(conf, argc, argv);
165 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
171 pkg_src_list_elt_t *iter;
175 sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir);
177 if (! file_is_dir(lists_dir)) {
178 if (file_exists(lists_dir)) {
179 opkg_message(conf, OPKG_ERROR,
180 "%s: ERROR: %s exists, but is not a directory\n",
181 __FUNCTION__, lists_dir);
185 err = file_mkdir_hier(lists_dir, 0755);
187 opkg_message(conf, OPKG_ERROR,
188 "%s: ERROR: failed to make directory %s: %s\n",
189 __FUNCTION__, lists_dir, strerror(errno));
198 tmp = xstrdup("/tmp/opkg.XXXXXX");
200 if (mkdtemp (tmp) == NULL) {
206 for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) {
207 char *url, *list_file_name;
209 src = (pkg_src_t *)iter->data;
211 if (src->extra_data) /* debian style? */
212 sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data,
213 src->gzip ? "Packages.gz" : "Packages");
215 sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
217 sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
222 sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
223 err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
225 opkg_message (conf, OPKG_NOTICE, "Inflating %s\n", url);
226 in = fopen (tmp_file_name, "r");
227 out = fopen (list_file_name, "w");
236 unlink (tmp_file_name);
240 err = opkg_download(conf, url, list_file_name, NULL, NULL);
244 opkg_message(conf, OPKG_NOTICE,
245 "Updated list of available packages in %s\n",
249 #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
250 if (conf->check_signature) {
251 /* download detached signitures to verify the package lists */
252 /* get the url for the sig file */
253 if (src->extra_data) /* debian style? */
254 sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data,
257 sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig");
259 /* create temporary file for it */
262 /* Put the signature in the right place */
263 sprintf_alloc (&tmp_file_name, "%s/%s.sig", lists_dir, src->name);
265 err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
268 opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
271 err = opkg_verify_file (conf, list_file_name, tmp_file_name);
273 opkg_message (conf, OPKG_NOTICE, "Signature check passed\n");
275 opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
277 /* We shouldn't unlink the signature ! */
278 // unlink (tmp_file_name);
279 free (tmp_file_name);
285 free(list_file_name);
295 struct opkg_intercept
301 typedef struct opkg_intercept *opkg_intercept_t;
303 static opkg_intercept_t opkg_prep_intercepts(opkg_conf_t *conf)
305 opkg_intercept_t ctx;
309 ctx = xcalloc(1, sizeof (*ctx));
310 ctx->oldpath = xstrdup(getenv("PATH"));
312 sprintf_alloc (&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
313 setenv ("PATH", newpath, 1);
318 sprintf_alloc (&ctx->statedir, "/tmp/opkg-intercept-%d-%d", getpid (), gen);
319 if (mkdir (ctx->statedir, 0770) < 0) {
320 if (errno == EEXIST) {
321 free (ctx->statedir);
325 perror (ctx->statedir);
328 setenv ("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
332 static int opkg_finalize_intercepts(opkg_intercept_t ctx)
339 setenv ("PATH", ctx->oldpath, 1);
343 dir = opendir (ctx->statedir);
346 while (de = readdir (dir), de != NULL) {
349 if (de->d_name[0] == '.')
352 sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name);
353 if (access (path, X_OK) == 0) {
363 perror (ctx->statedir);
365 sprintf_alloc (&cmd, "rm -rf %s", ctx->statedir);
369 free (ctx->statedir);
375 /* For package pkg do the following: If it is already visited, return. If not,
376 add it in visited list and recurse to its deps. Finally, add it to ordered
378 pkg_vec all contains all available packages in repos.
379 pkg_vec visited contains packages already visited by this function, and is
380 used to end recursion and avoid an infinite loop on graph cycles.
381 pkg_vec ordered will finally contain the ordered set of packages.
383 static int opkg_recurse_pkgs_in_order(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *all,
384 pkg_vec_t *visited, pkg_vec_t *ordered)
389 compound_depend_t * compound_depend;
390 depend_t ** possible_satisfiers;
391 abstract_pkg_t *abpkg;
392 abstract_pkg_t **dependents;
394 /* If it's just an available package, that is, not installed and not even
396 /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED
397 would do here. However, if there is an intermediate node (pkg) that is
398 configured and installed between two unpacked packages, the latter
399 won't be properly reordered, unless all installed/unpacked pkgs are
401 if (pkg->state_status == SS_NOT_INSTALLED)
404 /* If the package has already been visited (by this function), skip it */
405 for(j = 0; j < visited->len; j++)
406 if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) {
407 opkg_message(conf, OPKG_INFO,
408 " pkg: %s already visited\n", pkg->name);
412 pkg_vec_insert(visited, pkg);
414 count = pkg->pre_depends_count + pkg->depends_count + \
415 pkg->recommends_count + pkg->suggests_count;
417 opkg_message(conf, OPKG_INFO,
418 " pkg: %s\n", pkg->name);
420 /* Iterate over all the dependencies of pkg. For each one, find a package
421 that is either installed or unpacked and satisfies this dependency.
422 (there should only be one such package per dependency installed or
423 unpacked). Then recurse to the dependency package */
424 for (j=0; j < count ; j++) {
425 compound_depend = &pkg->depends[j];
426 possible_satisfiers = compound_depend->possibilities;
427 for (k=0; k < compound_depend->possibility_count ; k++) {
428 abpkg = possible_satisfiers[k]->pkg;
429 dependents = abpkg->provided_by->pkgs;
431 if (dependents != NULL)
432 while (l < abpkg->provided_by->len && dependents[l] != NULL) {
433 opkg_message(conf, OPKG_INFO,
434 " Descending on pkg: %s\n",
435 dependents [l]->name);
437 /* find whether dependent l is installed or unpacked,
438 * and then find which package in the list satisfies it */
439 for(m = 0; m < all->len; m++) {
441 if ( dep->state_status != SS_NOT_INSTALLED)
442 if ( ! strcmp(dep->name, dependents[l]->name)) {
443 opkg_recurse_pkgs_in_order(conf, dep, all,
445 /* Stop the outer loop */
446 l = abpkg->provided_by->len;
447 /* break from the inner loop */
456 /* When all recursions from this node down, are over, and all
457 dependencies have been added in proper order in the ordered array, add
458 also the package pkg to ordered array */
459 pkg_vec_insert(ordered, pkg);
465 static int opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
467 pkg_vec_t *all, *ordered, *visited;
473 opkg_message(conf, OPKG_INFO,
474 "Configuring unpacked packages\n");
477 all = pkg_vec_alloc();
479 pkg_hash_fetch_available(&conf->pkg_hash, all);
481 /* Reorder pkgs in order to be configured according to the Depends: tag
483 opkg_message(conf, OPKG_INFO,
484 "Reordering packages before configuring them...\n");
485 ordered = pkg_vec_alloc();
486 visited = pkg_vec_alloc();
487 for(i = 0; i < all->len; i++) {
489 opkg_recurse_pkgs_in_order(conf, pkg, all, visited, ordered);
493 ic = opkg_prep_intercepts (conf);
495 for(i = 0; i < all->len; i++) {
498 if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
501 if (pkg->state_status == SS_UNPACKED) {
502 opkg_message(conf, OPKG_NOTICE,
503 "Configuring %s\n", pkg->name);
505 r = opkg_configure(conf, pkg);
507 pkg->state_status = SS_INSTALLED;
508 pkg->parent->state_status = SS_INSTALLED;
509 pkg->state_flag &= ~SF_PREFER;
517 r = opkg_finalize_intercepts (ic);
522 pkg_vec_free(ordered);
523 pkg_vec_free(visited);
528 static opkg_conf_t *global_conf;
530 static void sigint_handler(int sig)
532 signal(sig, SIG_DFL);
533 opkg_message(NULL, OPKG_NOTICE,
534 "opkg: interrupted. writing out status database\n");
535 write_status_files_if_changed(global_conf);
539 static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv)
546 signal(SIGINT, sigint_handler);
549 * Now scan through package names and install
551 for (i=0; i < argc; i++) {
554 opkg_message(conf, OPKG_DEBUG2, "Debug install_cmd: %s \n",arg );
555 err = opkg_prepare_url_for_install(conf, arg, &argv[i]);
556 if (err != EINVAL && err != 0)
559 pkg_info_preinstall_check(conf);
561 for (i=0; i < argc; i++) {
563 err = opkg_install_by_name(conf, arg);
564 if (err == OPKG_PKG_HAS_NO_CANDIDATE) {
565 opkg_message(conf, OPKG_ERROR,
566 "Cannot find package %s.\n",
571 opkg_configure_packages(conf, NULL);
573 write_status_files_if_changed(conf);
578 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv)
585 signal(SIGINT, sigint_handler);
588 for (i=0; i < argc; i++) {
591 err = opkg_prepare_url_for_install(conf, arg, &arg);
592 if (err != EINVAL && err != 0)
595 pkg_info_preinstall_check(conf);
597 for (i=0; i < argc; i++) {
599 if (conf->restrict_to_default_dest) {
600 pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
604 opkg_message(conf, OPKG_NOTICE,
605 "Package %s not installed in %s\n",
606 argv[i], conf->default_dest->name);
610 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
614 opkg_upgrade_pkg(conf, pkg);
616 opkg_install_by_name(conf, arg);
620 pkg_vec_t *installed = pkg_vec_alloc();
622 pkg_info_preinstall_check(conf);
624 pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
625 for (i = 0; i < installed->len; i++) {
626 pkg = installed->pkgs[i];
627 opkg_upgrade_pkg(conf, pkg);
629 pkg_vec_free(installed);
632 opkg_configure_packages(conf, NULL);
634 write_status_files_if_changed(conf);
639 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv)
645 pkg_info_preinstall_check(conf);
646 for (i = 0; i < argc; i++) {
649 pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, arg, &err);
651 opkg_message(conf, OPKG_ERROR,
652 "Cannot find package %s.\n"
653 "Check the spelling or perhaps run 'opkg update'\n",
658 err = opkg_download_pkg(conf, pkg, ".");
661 opkg_message(conf, OPKG_ERROR,
662 "Failed to download %s\n", pkg->name);
664 opkg_message(conf, OPKG_NOTICE,
665 "Downloaded %s as %s\n",
666 pkg->name, pkg->local_filename);
674 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv)
677 pkg_vec_t *available;
679 char *pkg_name = NULL;
684 available = pkg_vec_alloc();
685 pkg_hash_fetch_available(&conf->pkg_hash, available);
686 pkg_vec_sort(available, pkg_compare_names);
687 for (i=0; i < available->len; i++) {
688 pkg = available->pkgs[i];
689 /* if we have package name or pattern and pkg does not match, then skip it */
690 if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
694 pkg_vec_free(available);
700 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
703 pkg_vec_t *available;
705 char *pkg_name = NULL;
710 available = pkg_vec_alloc();
711 pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
712 pkg_vec_sort(available, pkg_compare_names);
713 for (i=0; i < available->len; i++) {
714 pkg = available->pkgs[i];
715 /* if we have package name or pattern and pkg does not match, then skip it */
716 if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
721 pkg_vec_free(available);
726 static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv)
728 struct active_list *head = prepare_upgrade_list(conf);
729 struct active_list *node=NULL;
730 pkg_t *_old_pkg, *_new_pkg;
732 for (node = active_list_next(head, head); node;node = active_list_next(head,node)) {
733 _old_pkg = list_entry(node, pkg_t, list);
734 _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, _old_pkg->name, NULL);
735 old_v = pkg_version_str_alloc(_old_pkg);
736 new_v = pkg_version_str_alloc(_new_pkg);
737 printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
741 active_list_head_delete(head);
745 static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int installed_only)
748 pkg_vec_t *available;
750 char *pkg_name = NULL;
756 available = pkg_vec_alloc();
758 pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
760 pkg_hash_fetch_available(&conf->pkg_hash, available);
762 for (i=0; i < available->len; i++) {
763 pkg = available->pkgs[i];
764 if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
768 pkg_formatted_info(stdout, pkg);
770 if (conf->verbosity > 1) {
771 conffile_list_elt_t *iter;
772 for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
773 conffile_t *cf = (conffile_t *)iter->data;
774 int modified = conffile_has_been_modified(conf, cf);
776 opkg_message(conf, OPKG_NOTICE,
777 "conffile=%s md5sum=%s modified=%d\n",
778 cf->name, cf->value, modified);
782 pkg_vec_free(available);
787 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv)
789 return opkg_info_status_cmd(conf, argc, argv, 0);
792 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv)
794 return opkg_info_status_cmd(conf, argc, argv, 1);
797 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv)
802 char *pkg_name = NULL;
806 err = opkg_configure_packages (conf, pkg_name);
809 err = opkg_configure_packages (conf, NULL);
812 write_status_files_if_changed(conf);
817 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv)
823 sprintf_alloc(&globpattern, "%s/*" OPKG_PKG_EXTENSION, conf->pending_dir);
824 err = glob(globpattern, 0, NULL, &globbuf);
830 opkg_message(conf, OPKG_NOTICE,
831 "The following packages in %s will now be installed.\n",
833 for (i = 0; i < globbuf.gl_pathc; i++) {
834 opkg_message(conf, OPKG_NOTICE,
835 "%s%s", i == 0 ? "" : " ", globbuf.gl_pathv[i]);
837 opkg_message(conf, OPKG_NOTICE, "\n");
838 for (i = 0; i < globbuf.gl_pathc; i++) {
839 err = opkg_install_from_file(conf, globbuf.gl_pathv[i]);
841 err = unlink(globbuf.gl_pathv[i]);
843 opkg_message(conf, OPKG_ERROR,
844 "%s: ERROR: failed to unlink %s: %s\n",
845 __FUNCTION__, globbuf.gl_pathv[i], strerror(err));
855 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv)
859 pkg_t *pkg_to_remove;
860 pkg_vec_t *available;
861 char *pkg_name = NULL;
863 signal(SIGINT, sigint_handler);
865 // ENH: Add the "no pkg removed" just in case.
869 pkg_info_preinstall_check(conf);
871 available = pkg_vec_alloc();
872 pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
873 for (i=0; i < argc; i++) {
874 pkg_name = xcalloc(1, strlen(argv[i])+2);
875 strcpy(pkg_name,argv[i]);
876 for (a=0; a < available->len; a++) {
877 pkg = available->pkgs[a];
878 if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
881 if (conf->restrict_to_default_dest) {
882 pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
886 pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
889 if (pkg_to_remove == NULL) {
890 opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
893 if (pkg->state_status == SS_NOT_INSTALLED) { // Added the control, so every already removed package could be skipped
894 opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
897 opkg_remove_pkg(conf, pkg_to_remove,0);
902 pkg_vec_free(available);
904 pkg_vec_t *installed_pkgs = pkg_vec_alloc();
906 int flagged_pkg_count = 0;
909 pkg_hash_fetch_all_installed(&conf->pkg_hash, installed_pkgs);
911 for (i = 0; i < installed_pkgs->len; i++) {
912 pkg_t *pkg = installed_pkgs->pkgs[i];
913 if (pkg->state_flag & SF_USER) {
916 if (!pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL))
917 opkg_message(conf, OPKG_NOTICE, "Non-user leaf package: %s\n", pkg->name);
920 if (!flagged_pkg_count) {
921 opkg_message(conf, OPKG_NOTICE, "No packages flagged as installed by user, \n"
922 "so refusing to uninstall unflagged non-leaf packages\n");
926 /* find packages not flagged SF_USER (i.e., installed to
927 * satisfy a dependence) and not having any dependents, and
931 for (i = 0; i < installed_pkgs->len; i++) {
932 pkg_t *pkg = installed_pkgs->pkgs[i];
933 if (!(pkg->state_flag & SF_USER)
934 && !pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL)) {
936 opkg_message(conf, OPKG_NOTICE, "Removing non-user leaf package %s\n");
937 opkg_remove_pkg(conf, pkg,0);
942 pkg_vec_free(installed_pkgs);
946 opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
948 write_status_files_if_changed(conf);
952 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv)
958 signal(SIGINT, sigint_handler);
960 pkg_info_preinstall_check(conf);
962 for (i=0; i < argc; i++) {
963 if (conf->restrict_to_default_dest) {
964 pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
968 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
972 opkg_message(conf, OPKG_ERROR,
973 "Package %s is not installed.\n", argv[i]);
976 opkg_purge_pkg(conf, pkg);
979 write_status_files_if_changed(conf);
983 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
987 const char *flags = argv[0];
990 signal(SIGINT, sigint_handler);
992 for (i=1; i < argc; i++) {
993 if (conf->restrict_to_default_dest) {
994 pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
998 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
1002 opkg_message(conf, OPKG_ERROR,
1003 "Package %s is not installed.\n", argv[i]);
1006 if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
1007 ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
1008 pkg->state_flag = pkg_state_flag_from_str(flags);
1010 /* pb_ asked this feature 03292004 */
1011 /* Actually I will use only this two, but this is an open for various status */
1012 if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
1013 pkg->state_status = pkg_state_status_from_str(flags);
1015 opkg_state_changed++;
1016 opkg_message(conf, OPKG_NOTICE,
1017 "Setting flags for package %s to %s\n",
1021 write_status_files_if_changed(conf);
1025 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
1029 str_list_elt_t *iter;
1036 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
1039 opkg_message(conf, OPKG_ERROR,
1040 "Package %s not installed.\n", argv[0]);
1044 files = pkg_get_installed_files(pkg);
1045 pkg_version = pkg_version_str_alloc(pkg);
1047 printf("Package %s (%s) is installed on %s and has the following files:\n",
1048 pkg->name, pkg_version, pkg->dest->name);
1050 for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
1051 printf("%s\n", (char *)iter->data);
1054 pkg_free_installed_files(pkg);
1059 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
1063 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1064 const char *rel_str = "depends on";
1067 pkg_info_preinstall_check(conf);
1069 if (conf->query_all)
1070 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1072 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1073 for (i = 0; i < argc; i++) {
1074 const char *target = argv[i];
1077 opkg_message(conf, OPKG_ERROR, "target=%s\n", target);
1079 for (j = 0; j < available_pkgs->len; j++) {
1080 pkg_t *pkg = available_pkgs->pkgs[j];
1081 if (fnmatch(target, pkg->name, 0) == 0) {
1083 int count = pkg->depends_count + pkg->pre_depends_count;
1084 opkg_message(conf, OPKG_ERROR, "What %s (arch=%s) %s\n",
1085 target, pkg->architecture, rel_str);
1086 for (k = 0; k < count; k++) {
1087 compound_depend_t *cdepend = &pkg->depends[k];
1089 for (l = 0; l < cdepend->possibility_count; l++) {
1090 depend_t *possibility = cdepend->possibilities[l];
1091 opkg_message(conf, OPKG_ERROR, " %s", possibility->pkg->name);
1092 if (conf->verbosity > 0) {
1093 // char *ver = abstract_pkg_version_str_alloc(possibility->pkg);
1094 opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
1095 if (possibility->version) {
1096 char *typestr = NULL;
1097 switch (possibility->constraint) {
1098 case NONE: typestr = "none"; break;
1099 case EARLIER: typestr = "<"; break;
1100 case EARLIER_EQUAL: typestr = "<="; break;
1101 case EQUAL: typestr = "="; break;
1102 case LATER_EQUAL: typestr = ">="; break;
1103 case LATER: typestr = ">"; break;
1105 opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1109 opkg_message(conf, OPKG_ERROR, "\n");
1115 pkg_vec_free(available_pkgs);
1120 enum what_field_type {
1129 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int recursive, int argc, char **argv)
1133 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1134 const char *rel_str = NULL;
1138 switch (what_field_type) {
1139 case WHATDEPENDS: rel_str = "depends on"; break;
1140 case WHATCONFLICTS: rel_str = "conflicts with"; break;
1141 case WHATSUGGESTS: rel_str = "suggests"; break;
1142 case WHATRECOMMENDS: rel_str = "recommends"; break;
1143 case WHATPROVIDES: rel_str = "provides"; break;
1144 case WHATREPLACES: rel_str = "replaces"; break;
1147 if (conf->query_all)
1148 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1150 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1152 /* mark the root set */
1153 pkg_vec_clear_marks(available_pkgs);
1154 opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1155 for (i = 0; i < argc; i++) {
1156 const char *dependee_pattern = argv[i];
1157 pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1159 for (i = 0; i < available_pkgs->len; i++) {
1160 pkg_t *pkg = available_pkgs->pkgs[i];
1161 if (pkg->state_flag & SF_MARKED) {
1162 /* mark the parent (abstract) package */
1163 pkg_mark_provides(pkg);
1164 opkg_message(conf, OPKG_NOTICE, " %s\n", pkg->name);
1168 opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1173 for (j = 0; j < available_pkgs->len; j++) {
1174 pkg_t *pkg = available_pkgs->pkgs[j];
1176 int count = ((what_field_type == WHATCONFLICTS)
1177 ? pkg->conflicts_count
1178 : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1179 /* skip this package if it is already marked */
1180 if (pkg->parent->state_flag & SF_MARKED) {
1183 for (k = 0; k < count; k++) {
1184 compound_depend_t *cdepend =
1185 (what_field_type == WHATCONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1187 for (l = 0; l < cdepend->possibility_count; l++) {
1188 depend_t *possibility = cdepend->possibilities[l];
1189 if (possibility->pkg->state_flag & SF_MARKED) {
1190 /* mark the depending package so we won't visit it again */
1191 pkg->state_flag |= SF_MARKED;
1192 pkg_mark_provides(pkg);
1195 opkg_message(conf, OPKG_NOTICE, " %s", pkg->name);
1196 if (conf->verbosity > 0) {
1197 char *ver = pkg_version_str_alloc(pkg);
1198 opkg_message(conf, OPKG_NOTICE, " %s", ver);
1199 opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1200 if (possibility->version) {
1201 char *typestr = NULL;
1202 switch (possibility->constraint) {
1203 case NONE: typestr = "none"; break;
1204 case EARLIER: typestr = "<"; break;
1205 case EARLIER_EQUAL: typestr = "<="; break;
1206 case EQUAL: typestr = "="; break;
1207 case LATER_EQUAL: typestr = ">="; break;
1208 case LATER: typestr = ">"; break;
1210 opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1213 if (!pkg_dependence_satisfiable(conf, possibility))
1214 opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1216 opkg_message(conf, OPKG_NOTICE, "\n");
1224 } while (changed && recursive);
1225 pkg_vec_free(available_pkgs);
1231 static int pkg_mark_provides(pkg_t *pkg)
1233 int provides_count = pkg->provides_count;
1234 abstract_pkg_t **provides = pkg->provides;
1236 pkg->parent->state_flag |= SF_MARKED;
1237 for (i = 0; i < provides_count; i++) {
1238 provides[i]->state_flag |= SF_MARKED;
1243 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1245 return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 1, argc, argv);
1247 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1249 return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 0, argc, argv);
1252 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1254 return opkg_what_depends_conflicts_cmd(conf, WHATSUGGESTS, 0, argc, argv);
1257 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1259 return opkg_what_depends_conflicts_cmd(conf, WHATRECOMMENDS, 0, argc, argv);
1262 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1264 return opkg_what_depends_conflicts_cmd(conf, WHATCONFLICTS, 0, argc, argv);
1267 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1271 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1272 const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1275 pkg_info_preinstall_check(conf);
1277 if (conf->query_all)
1278 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1280 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1281 for (i = 0; i < argc; i++) {
1282 const char *target = argv[i];
1285 opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1287 for (j = 0; j < available_pkgs->len; j++) {
1288 pkg_t *pkg = available_pkgs->pkgs[j];
1290 int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1291 for (k = 0; k < count; k++) {
1292 abstract_pkg_t *apkg =
1293 ((what_field_type == WHATPROVIDES)
1295 : pkg->replaces[k]);
1296 if (fnmatch(target, apkg->name, 0) == 0) {
1297 opkg_message(conf, OPKG_ERROR, " %s", pkg->name);
1298 if (strcmp(target, apkg->name) != 0)
1299 opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1300 opkg_message(conf, OPKG_ERROR, "\n");
1305 pkg_vec_free(available_pkgs);
1310 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1312 return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1315 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1317 return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1320 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1324 pkg_vec_t *installed;
1326 str_list_t *installed_files;
1327 str_list_elt_t *iter;
1328 char *installed_file;
1334 installed = pkg_vec_alloc();
1335 pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1336 pkg_vec_sort(installed, pkg_compare_names);
1338 for (i=0; i < installed->len; i++) {
1339 pkg = installed->pkgs[i];
1341 installed_files = pkg_get_installed_files(pkg);
1343 for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1344 installed_file = (char *)iter->data;
1345 if (fnmatch(argv[0], installed_file, 0)==0)
1349 pkg_free_installed_files(pkg);
1352 pkg_vec_free(installed);
1357 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1360 /* this is a bit gross */
1362 parseVersion(&p1, argv[0]);
1363 parseVersion(&p2, argv[2]);
1364 return pkg_version_satisfied(&p1, &p2, argv[1]);
1366 opkg_message(conf, OPKG_ERROR,
1367 "opkg compare_versions <v1> <op> <v2>\n"
1368 "<op> is one of <= >= << >> =\n");
1373 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1375 nv_pair_list_elt_t *l;
1377 list_for_each_entry(l, &conf->arch_list.head, node) {
1378 nv_pair_t *nv = (nv_pair_t *)l->data;
1379 printf("arch %s %s\n", nv->name, nv->value);