Merge commit 'grg' into HEAD
[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 "libopkg.h"
42 #include "xsystem.h"
43
44 static void
45 print_pkg(pkg_t *pkg)
46 {
47 char *version = pkg_version_str_alloc(pkg);
48 if (pkg->description)
49 printf("%s - %s - %s\n", pkg->name, version, pkg->description);
50 else
51 printf("%s - %s\n", pkg->name, version);
52 free(version);
53 }
54
55 int opkg_state_changed;
56
57 static void
58 write_status_files_if_changed(void)
59 {
60 if (opkg_state_changed && !conf->noaction) {
61 opkg_msg(INFO, "Writing status file.\n");
62 opkg_conf_write_status_files();
63 pkg_write_changed_filelists();
64 } else {
65 opkg_msg(DEBUG, "Nothing to be done.\n");
66 }
67 }
68
69 static void
70 sigint_handler(int sig)
71 {
72 signal(sig, SIG_DFL);
73 opkg_msg(NOTICE, "Interrupted. Writing out status database.\n");
74 write_status_files_if_changed();
75 exit(128 + sig);
76 }
77
78 static int
79 opkg_update_cmd(int argc, char **argv)
80 {
81 char *tmp;
82 int err;
83 int failures;
84 char *lists_dir;
85 pkg_src_list_elt_t *iter;
86 pkg_src_t *src;
87
88
89 sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir);
90
91 if (! file_is_dir(lists_dir)) {
92 if (file_exists(lists_dir)) {
93 opkg_msg(ERROR, "%s exists, but is not a directory.\n",
94 lists_dir);
95 free(lists_dir);
96 return -1;
97 }
98 err = file_mkdir_hier(lists_dir, 0755);
99 if (err) {
100 free(lists_dir);
101 return -1;
102 }
103 }
104
105 failures = 0;
106
107 sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir);
108 if (mkdtemp (tmp) == NULL) {
109 opkg_perror(ERROR, "Failed to make temp dir %s", conf->tmp_dir);
110 return -1;
111 }
112
113
114 for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) {
115 char *url, *list_file_name;
116
117 src = (pkg_src_t *)iter->data;
118
119 if (src->extra_data) /* debian style? */
120 sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data,
121 src->gzip ? "Packages.gz" : "Packages");
122 else
123 sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
124
125 sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
126 if (src->gzip) {
127 char *tmp_file_name;
128 FILE *in, *out;
129
130 sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
131 err = opkg_download(url, tmp_file_name, NULL, NULL);
132 if (err == 0) {
133 opkg_msg(NOTICE, "Inflating %s.\n", url);
134 in = fopen (tmp_file_name, "r");
135 out = fopen (list_file_name, "w");
136 if (in && out)
137 unzip (in, out);
138 else
139 err = 1;
140 if (in)
141 fclose (in);
142 if (out)
143 fclose (out);
144 unlink (tmp_file_name);
145 }
146 free(tmp_file_name);
147 } else
148 err = opkg_download(url, list_file_name, NULL, NULL);
149 if (err) {
150 failures++;
151 } else {
152 opkg_msg(NOTICE, "Updated list of available packages in %s.\n",
153 list_file_name);
154 }
155 free(url);
156 #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
157 if (conf->check_signature) {
158 /* download detached signitures to verify the package lists */
159 /* get the url for the sig file */
160 if (src->extra_data) /* debian style? */
161 sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data,
162 "Packages.sig");
163 else
164 sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig");
165
166 /* create temporary file for it */
167 char *tmp_file_name;
168
169 /* Put the signature in the right place */
170 sprintf_alloc (&tmp_file_name, "%s/%s.sig", lists_dir, src->name);
171
172 err = opkg_download(url, tmp_file_name, NULL, NULL);
173 if (err) {
174 failures++;
175 opkg_msg(NOTICE, "Signature check failed.\n");
176 } else {
177 err = opkg_verify_file (list_file_name, tmp_file_name);
178 if (err == 0)
179 opkg_msg(NOTICE, "Signature check passed.\n");
180 else
181 opkg_msg(NOTICE, "Signature check failed.\n");
182 }
183 /* We shouldn't unlink the signature ! */
184 // unlink (tmp_file_name);
185 free (tmp_file_name);
186 free (url);
187 }
188 #else
189 // Do nothing
190 #endif
191 free(list_file_name);
192 }
193 rmdir (tmp);
194 free (tmp);
195 free(lists_dir);
196
197 return failures;
198 }
199
200
201 struct opkg_intercept
202 {
203 char *oldpath;
204 char *statedir;
205 };
206
207 typedef struct opkg_intercept *opkg_intercept_t;
208
209 static opkg_intercept_t
210 opkg_prep_intercepts(void)
211 {
212 opkg_intercept_t ctx;
213 char *newpath;
214
215 ctx = xcalloc(1, sizeof (*ctx));
216 ctx->oldpath = xstrdup(getenv("PATH"));
217 sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
218 sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX", conf->tmp_dir);
219
220 if (mkdtemp(ctx->statedir) == NULL) {
221 opkg_perror(ERROR,"Failed to make temp dir %s", ctx->statedir);
222 free(ctx->oldpath);
223 free(ctx->statedir);
224 free(newpath);
225 free(ctx);
226 return NULL;
227 }
228
229 setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
230 setenv("PATH", newpath, 1);
231 free(newpath);
232
233 return ctx;
234 }
235
236 static int
237 opkg_finalize_intercepts(opkg_intercept_t ctx)
238 {
239 DIR *dir;
240 int err = 0;
241
242 setenv ("PATH", ctx->oldpath, 1);
243 free (ctx->oldpath);
244
245 dir = opendir (ctx->statedir);
246 if (dir) {
247 struct dirent *de;
248 while (de = readdir (dir), de != NULL) {
249 char *path;
250
251 if (de->d_name[0] == '.')
252 continue;
253
254 sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name);
255 if (access (path, X_OK) == 0) {
256 const char *argv[] = {"sh", "-c", path, NULL};
257 xsystem (argv);
258 }
259 free (path);
260 }
261 closedir(dir);
262 } else
263 opkg_perror(ERROR, "Failed to open dir %s", ctx->statedir);
264
265 rm_r(ctx->statedir);
266 free (ctx->statedir);
267 free (ctx);
268
269 return err;
270 }
271
272 /* For package pkg do the following: If it is already visited, return. If not,
273 add it in visited list and recurse to its deps. Finally, add it to ordered
274 list.
275 pkg_vec all contains all available packages in repos.
276 pkg_vec visited contains packages already visited by this function, and is
277 used to end recursion and avoid an infinite loop on graph cycles.
278 pkg_vec ordered will finally contain the ordered set of packages.
279 */
280 static int
281 opkg_recurse_pkgs_in_order(pkg_t *pkg, pkg_vec_t *all,
282 pkg_vec_t *visited, pkg_vec_t *ordered)
283 {
284 int j,k,l,m;
285 int count;
286 pkg_t *dep;
287 compound_depend_t * compound_depend;
288 depend_t ** possible_satisfiers;
289 abstract_pkg_t *abpkg;
290 abstract_pkg_t **dependents;
291
292 /* If it's just an available package, that is, not installed and not even
293 unpacked, skip it */
294 /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED
295 would do here. However, if there is an intermediate node (pkg) that is
296 configured and installed between two unpacked packages, the latter
297 won't be properly reordered, unless all installed/unpacked pkgs are
298 checked */
299 if (pkg->state_status == SS_NOT_INSTALLED)
300 return 0;
301
302 /* If the package has already been visited (by this function), skip it */
303 for(j = 0; j < visited->len; j++)
304 if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) {
305 opkg_msg(INFO, "pkg %s already visited, skipping.\n", pkg->name);
306 return 0;
307 }
308
309 pkg_vec_insert(visited, pkg);
310
311 count = pkg->pre_depends_count + pkg->depends_count + \
312 pkg->recommends_count + pkg->suggests_count;
313
314 opkg_msg(INFO, "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 (j=0; j < count ; j++) {
321 compound_depend = &pkg->depends[j];
322 possible_satisfiers = compound_depend->possibilities;
323 for (k=0; k < compound_depend->possibility_count ; k++) {
324 abpkg = possible_satisfiers[k]->pkg;
325 dependents = abpkg->provided_by->pkgs;
326 l = 0;
327 if (dependents != NULL)
328 while (l < abpkg->provided_by->len && dependents[l] != NULL) {
329 opkg_msg(INFO, "Descending on pkg %s.\n",
330 dependents [l]->name);
331
332 /* find whether dependent l is installed or unpacked,
333 * and then find which package in the list satisfies it */
334 for(m = 0; m < all->len; m++) {
335 dep = all->pkgs[m];
336 if ( dep->state_status != SS_NOT_INSTALLED)
337 if ( ! strcmp(dep->name, dependents[l]->name)) {
338 opkg_recurse_pkgs_in_order(dep, all,
339 visited, ordered);
340 /* Stop the outer loop */
341 l = abpkg->provided_by->len;
342 /* break from the inner loop */
343 break;
344 }
345 }
346 l++;
347 }
348 }
349 }
350
351 /* When all recursions from this node down, are over, and all
352 dependencies have been added in proper order in the ordered array, add
353 also the package pkg to ordered array */
354 pkg_vec_insert(ordered, pkg);
355
356 return 0;
357
358 }
359
360 static int
361 opkg_configure_packages(char *pkg_name)
362 {
363 pkg_vec_t *all, *ordered, *visited;
364 int i;
365 pkg_t *pkg;
366 opkg_intercept_t ic;
367 int r, err = 0;
368
369 opkg_msg(INFO, "Configuring unpacked packages.\n");
370
371 all = pkg_vec_alloc();
372
373 pkg_hash_fetch_available(all);
374
375 /* Reorder pkgs in order to be configured according to the Depends: tag
376 order */
377 opkg_msg(INFO, "Reordering packages before configuring them...\n");
378 ordered = pkg_vec_alloc();
379 visited = pkg_vec_alloc();
380 for(i = 0; i < all->len; i++) {
381 pkg = all->pkgs[i];
382 opkg_recurse_pkgs_in_order(pkg, all, visited, ordered);
383 }
384
385 ic = opkg_prep_intercepts();
386 if (ic == NULL) {
387 err = -1;
388 goto error;
389 }
390
391 for(i = 0; i < all->len; i++) {
392 pkg = all->pkgs[i];
393
394 if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
395 continue;
396
397 if (pkg->state_status == SS_UNPACKED) {
398 opkg_msg(NOTICE, "Configuring %s.\n", pkg->name);
399 r = opkg_configure(pkg);
400 if (r == 0) {
401 pkg->state_status = SS_INSTALLED;
402 pkg->parent->state_status = SS_INSTALLED;
403 pkg->state_flag &= ~SF_PREFER;
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 int result;
1217
1218 result = (cmd->fun)(argc, argv);
1219
1220 print_error_list();
1221 free_error_list();
1222
1223 return result;
1224 }