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