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