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