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