Initial stab at untangling the #include maze. Probably needs a second pass.
[project/opkg-lede.git] / libopkg / opkg_cmd.c
1 /* opkg_cmd.c - the opkg package management system
2
3 Carl D. Worth
4
5 Copyright (C) 2001 University of Southern California
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16 */
17
18 #include <stdio.h>
19 #include <dirent.h>
20 #include <glob.h>
21 #include <fnmatch.h>
22 #include <signal.h>
23 #include <unistd.h>
24
25 #include "opkg_conf.h"
26 #include "opkg_cmd.h"
27 #include "opkg_message.h"
28 #include "pkg.h"
29 #include "pkg_dest.h"
30 #include "pkg_parse.h"
31 #include "sprintf_alloc.h"
32 #include "pkg.h"
33 #include "file_util.h"
34 #include "libbb/libbb.h"
35 #include "opkg_utils.h"
36 #include "opkg_defines.h"
37 #include "opkg_download.h"
38 #include "opkg_install.h"
39 #include "opkg_upgrade.h"
40 #include "opkg_remove.h"
41 #include "opkg_configure.h"
42 #include "xsystem.h"
43
44 static void
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(DEBUG, "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(DEBUG, "pkg %s.\n", pkg->name);
315
316 /* Iterate over all the dependencies of pkg. For each one, find a package
317 that is either installed or unpacked and satisfies this dependency.
318 (there should only be one such package per dependency installed or
319 unpacked). Then recurse to the dependency package */
320 for (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(DEBUG, "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 opkg_state_changed++;
405 } else {
406 if (!err)
407 err = r;
408 }
409 }
410 }
411
412 r = opkg_finalize_intercepts (ic);
413 if (r && !err)
414 err = r;
415
416 error:
417 pkg_vec_free(all);
418 pkg_vec_free(ordered);
419 pkg_vec_free(visited);
420
421 return err;
422 }
423
424 static int
425 opkg_install_cmd(int argc, char **argv)
426 {
427 int i;
428 char *arg;
429 int err=0;
430
431 signal(SIGINT, sigint_handler);
432
433 /*
434 * Now scan through package names and install
435 */
436 for (i=0; i < argc; i++) {
437 arg = argv[i];
438
439 opkg_msg(DEBUG2, "%s\n", arg);
440 err = opkg_prepare_url_for_install(arg, &argv[i]);
441 if (err)
442 return err;
443 }
444 pkg_info_preinstall_check();
445
446 for (i=0; i < argc; i++) {
447 arg = argv[i];
448 err = opkg_install_by_name(arg);
449 if (err) {
450 opkg_msg(ERROR, "Cannot install package %s.\n", arg);
451 }
452 }
453
454 opkg_configure_packages(NULL);
455
456 write_status_files_if_changed();
457
458 return err;
459 }
460
461 static int
462 opkg_upgrade_cmd(int argc, char **argv)
463 {
464 int i;
465 pkg_t *pkg;
466 int err;
467
468 signal(SIGINT, sigint_handler);
469
470 if (argc) {
471 for (i=0; i < argc; i++) {
472 char *arg = argv[i];
473
474 err = opkg_prepare_url_for_install(arg, &arg);
475 if (err)
476 return err;
477 }
478 pkg_info_preinstall_check();
479
480 for (i=0; i < argc; i++) {
481 char *arg = argv[i];
482 if (conf->restrict_to_default_dest) {
483 pkg = pkg_hash_fetch_installed_by_name_dest(argv[i],
484 conf->default_dest);
485 if (pkg == NULL) {
486 opkg_msg(NOTICE, "Package %s not installed in %s.\n",
487 argv[i], conf->default_dest->name);
488 continue;
489 }
490 } else {
491 pkg = pkg_hash_fetch_installed_by_name(argv[i]);
492 }
493 if (pkg)
494 opkg_upgrade_pkg(pkg);
495 else {
496 opkg_install_by_name(arg);
497 }
498 }
499 } else {
500 pkg_vec_t *installed = pkg_vec_alloc();
501
502 pkg_info_preinstall_check();
503
504 pkg_hash_fetch_all_installed(installed);
505 for (i = 0; i < installed->len; i++) {
506 pkg = installed->pkgs[i];
507 opkg_upgrade_pkg(pkg);
508 }
509 pkg_vec_free(installed);
510 }
511
512 opkg_configure_packages(NULL);
513
514 write_status_files_if_changed();
515
516 return 0;
517 }
518
519 static int
520 opkg_download_cmd(int argc, char **argv)
521 {
522 int i, err;
523 char *arg;
524 pkg_t *pkg;
525
526 pkg_info_preinstall_check();
527 for (i = 0; i < argc; i++) {
528 arg = argv[i];
529
530 pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg);
531 if (pkg == NULL) {
532 opkg_msg(ERROR, "Cannot find package %s.\n", arg);
533 continue;
534 }
535
536 err = opkg_download_pkg(pkg, ".");
537
538 if (err) {
539 opkg_msg(ERROR, "Failed to download %s.\n", pkg->name);
540 } else {
541 opkg_msg(NOTICE, "Downloaded %s as %s.\n",
542 pkg->name, pkg->local_filename);
543 }
544 }
545
546 return 0;
547 }
548
549
550 static int
551 opkg_list_cmd(int argc, char **argv)
552 {
553 int i;
554 pkg_vec_t *available;
555 pkg_t *pkg;
556 char *pkg_name = NULL;
557
558 if (argc > 0) {
559 pkg_name = argv[0];
560 }
561 available = pkg_vec_alloc();
562 pkg_hash_fetch_available(available);
563 pkg_vec_sort(available, pkg_compare_names);
564 for (i=0; i < available->len; i++) {
565 pkg = available->pkgs[i];
566 /* if we have package name or pattern and pkg does not match, then skip it */
567 if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
568 continue;
569 print_pkg(pkg);
570 }
571 pkg_vec_free(available);
572
573 return 0;
574 }
575
576
577 static int
578 opkg_list_installed_cmd(int argc, char **argv)
579 {
580 int i ;
581 pkg_vec_t *available;
582 pkg_t *pkg;
583 char *pkg_name = NULL;
584
585 if (argc > 0) {
586 pkg_name = argv[0];
587 }
588 available = pkg_vec_alloc();
589 pkg_hash_fetch_all_installed(available);
590 pkg_vec_sort(available, pkg_compare_names);
591 for (i=0; i < available->len; i++) {
592 pkg = available->pkgs[i];
593 /* if we have package name or pattern and pkg does not match, then skip it */
594 if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
595 continue;
596 print_pkg(pkg);
597 }
598
599 pkg_vec_free(available);
600
601 return 0;
602 }
603
604 static int
605 opkg_list_upgradable_cmd(int argc, char **argv)
606 {
607 struct active_list *head = prepare_upgrade_list();
608 struct active_list *node=NULL;
609 pkg_t *_old_pkg, *_new_pkg;
610 char *old_v, *new_v;
611 for (node = active_list_next(head, head); node;node = active_list_next(head,node)) {
612 _old_pkg = list_entry(node, pkg_t, list);
613 _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(_old_pkg->name);
614 if (_new_pkg == NULL)
615 continue;
616 old_v = pkg_version_str_alloc(_old_pkg);
617 new_v = pkg_version_str_alloc(_new_pkg);
618 printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
619 free(old_v);
620 free(new_v);
621 }
622 active_list_head_delete(head);
623 return 0;
624 }
625
626 static int
627 opkg_info_status_cmd(int argc, char **argv, int installed_only)
628 {
629 int i;
630 pkg_vec_t *available;
631 pkg_t *pkg;
632 char *pkg_name = NULL;
633
634 if (argc > 0) {
635 pkg_name = argv[0];
636 }
637
638 available = pkg_vec_alloc();
639 if (installed_only)
640 pkg_hash_fetch_all_installed(available);
641 else
642 pkg_hash_fetch_available(available);
643
644 for (i=0; i < available->len; i++) {
645 pkg = available->pkgs[i];
646 if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
647 continue;
648 }
649
650 pkg_formatted_info(stdout, pkg);
651
652 if (conf->verbosity >= NOTICE) {
653 conffile_list_elt_t *iter;
654 for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
655 conffile_t *cf = (conffile_t *)iter->data;
656 int modified = conffile_has_been_modified(cf);
657 if (cf->value)
658 opkg_msg(INFO, "conffile=%s md5sum=%s modified=%d.\n",
659 cf->name, cf->value, modified);
660 }
661 }
662 }
663 pkg_vec_free(available);
664
665 return 0;
666 }
667
668 static int
669 opkg_info_cmd(int argc, char **argv)
670 {
671 return opkg_info_status_cmd(argc, argv, 0);
672 }
673
674 static int
675 opkg_status_cmd(int argc, char **argv)
676 {
677 return opkg_info_status_cmd(argc, argv, 1);
678 }
679
680 static int
681 opkg_configure_cmd(int argc, char **argv)
682 {
683 int err;
684 char *pkg_name = NULL;
685
686 if (argc > 0)
687 pkg_name = argv[0];
688
689 err = opkg_configure_packages(pkg_name);
690
691 write_status_files_if_changed();
692
693 return err;
694 }
695
696 static int
697 opkg_remove_cmd(int argc, char **argv)
698 {
699 int i, a, done;
700 pkg_t *pkg;
701 pkg_t *pkg_to_remove;
702 pkg_vec_t *available;
703
704 done = 0;
705
706 signal(SIGINT, sigint_handler);
707
708 pkg_info_preinstall_check();
709
710 available = pkg_vec_alloc();
711 pkg_hash_fetch_all_installed(available);
712
713 for (i=0; i<argc; i++) {
714 for (a=0; a<available->len; a++) {
715 pkg = available->pkgs[a];
716 if (fnmatch(argv[i], pkg->name, 0)) {
717 continue;
718 }
719 if (conf->restrict_to_default_dest) {
720 pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(
721 pkg->name,
722 conf->default_dest);
723 } else {
724 pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name);
725 }
726
727 if (pkg_to_remove == NULL) {
728 opkg_msg(ERROR, "Package %s is not installed.\n", pkg->name);
729 continue;
730 }
731 if (pkg->state_status == SS_NOT_INSTALLED) { // Added the control, so every already removed package could be skipped
732 opkg_msg(ERROR, "Package %s not installed.\n", pkg->name);
733 continue;
734 }
735 opkg_remove_pkg(pkg_to_remove, 0);
736 done = 1;
737 }
738 }
739
740 pkg_vec_free(available);
741
742 if (done == 0)
743 opkg_msg(NOTICE, "No packages removed.\n");
744
745 write_status_files_if_changed();
746 return 0;
747 }
748
749 static int
750 opkg_flag_cmd(int argc, char **argv)
751 {
752 int i;
753 pkg_t *pkg;
754 const char *flags = argv[0];
755
756 signal(SIGINT, sigint_handler);
757
758 for (i=1; i < argc; i++) {
759 if (conf->restrict_to_default_dest) {
760 pkg = pkg_hash_fetch_installed_by_name_dest(argv[i],
761 conf->default_dest);
762 } else {
763 pkg = pkg_hash_fetch_installed_by_name(argv[i]);
764 }
765
766 if (pkg == NULL) {
767 opkg_msg(ERROR, "Package %s is not installed.\n", argv[i]);
768 continue;
769 }
770 if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
771 ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
772 pkg->state_flag = pkg_state_flag_from_str(flags);
773 }
774
775 /*
776 * Useful if a package is installed in an offline_root, and
777 * should be configured by opkg-cl configure at a later date.
778 */
779 if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
780 pkg->state_status = pkg_state_status_from_str(flags);
781 }
782
783 opkg_state_changed++;
784 opkg_msg(NOTICE, "Setting flags for package %s to %s.\n",
785 pkg->name, flags);
786 }
787
788 write_status_files_if_changed();
789 return 0;
790 }
791
792 static int
793 opkg_files_cmd(int argc, char **argv)
794 {
795 pkg_t *pkg;
796 str_list_t *files;
797 str_list_elt_t *iter;
798 char *pkg_version;
799
800 if (argc < 1) {
801 return -1;
802 }
803
804 pkg = pkg_hash_fetch_installed_by_name(argv[0]);
805 if (pkg == NULL) {
806 opkg_msg(ERROR, "Package %s not installed.\n", argv[0]);
807 return 0;
808 }
809
810 files = pkg_get_installed_files(pkg);
811 pkg_version = pkg_version_str_alloc(pkg);
812
813 printf("Package %s (%s) is installed on %s and has the following files:\n",
814 pkg->name, pkg_version, pkg->dest->name);
815
816 for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
817 printf("%s\n", (char *)iter->data);
818
819 free(pkg_version);
820 pkg_free_installed_files(pkg);
821
822 return 0;
823 }
824
825 static int
826 opkg_depends_cmd(int argc, char **argv)
827 {
828 int i, j, k;
829 int depends_count;
830 pkg_vec_t *available_pkgs;
831 compound_depend_t *cdep;
832 pkg_t *pkg;
833 char *str;
834
835 pkg_info_preinstall_check();
836
837 available_pkgs = pkg_vec_alloc();
838 if (conf->query_all)
839 pkg_hash_fetch_available(available_pkgs);
840 else
841 pkg_hash_fetch_all_installed(available_pkgs);
842
843 for (i=0; i<argc; i++) {
844 for (j=0; j<available_pkgs->len; j++) {
845 pkg = available_pkgs->pkgs[j];
846
847 if (fnmatch(argv[i], pkg->name, 0) != 0)
848 continue;
849
850 depends_count = pkg->depends_count +
851 pkg->pre_depends_count +
852 pkg->recommends_count +
853 pkg->suggests_count;
854
855 opkg_msg(NOTICE, "%s depends on:\n", pkg->name);
856
857 for (k=0; k<depends_count; k++) {
858 cdep = &pkg->depends[k];
859
860 if (cdep->type != DEPEND)
861 continue;
862
863 str = pkg_depend_str(pkg, k);
864 opkg_msg(NOTICE, "\t%s\n", str);
865 free(str);
866 }
867
868 }
869 }
870
871 pkg_vec_free(available_pkgs);
872 return 0;
873 }
874
875 static int
876 pkg_mark_provides(pkg_t *pkg)
877 {
878 int provides_count = pkg->provides_count;
879 abstract_pkg_t **provides = pkg->provides;
880 int i;
881 pkg->parent->state_flag |= SF_MARKED;
882 for (i = 0; i < provides_count; i++) {
883 provides[i]->state_flag |= SF_MARKED;
884 }
885 return 0;
886 }
887
888 enum what_field_type {
889 WHATDEPENDS,
890 WHATCONFLICTS,
891 WHATPROVIDES,
892 WHATREPLACES,
893 WHATRECOMMENDS,
894 WHATSUGGESTS
895 };
896
897 static int
898 opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive, int argc, char **argv)
899 {
900 depend_t *possibility;
901 compound_depend_t *cdep;
902 pkg_vec_t *available_pkgs;
903 pkg_t *pkg;
904 int i, j, k, l;
905 int changed, count;
906 const char *rel_str = NULL;
907 char *ver;
908
909 switch (what_field_type) {
910 case DEPEND: rel_str = "depends on"; break;
911 case CONFLICTS: rel_str = "conflicts with"; break;
912 case SUGGEST: rel_str = "suggests"; break;
913 case RECOMMEND: rel_str = "recommends"; break;
914 default: return -1;
915 }
916
917 available_pkgs = pkg_vec_alloc();
918
919 if (conf->query_all)
920 pkg_hash_fetch_available(available_pkgs);
921 else
922 pkg_hash_fetch_all_installed(available_pkgs);
923
924 /* mark the root set */
925 pkg_vec_clear_marks(available_pkgs);
926 opkg_msg(NOTICE, "Root set:\n");
927 for (i = 0; i < argc; i++)
928 pkg_vec_mark_if_matches(available_pkgs, argv[i]);
929
930 for (i = 0; i < available_pkgs->len; i++) {
931 pkg = available_pkgs->pkgs[i];
932 if (pkg->state_flag & SF_MARKED) {
933 /* mark the parent (abstract) package */
934 pkg_mark_provides(pkg);
935 opkg_msg(NOTICE, " %s\n", pkg->name);
936 }
937 }
938
939 opkg_msg(NOTICE, "What %s root set\n", rel_str);
940 do {
941 changed = 0;
942
943 for (j=0; j<available_pkgs->len; j++) {
944
945 pkg = available_pkgs->pkgs[j];
946 count = ((what_field_type == CONFLICTS)
947 ? pkg->conflicts_count
948 : pkg->pre_depends_count +
949 pkg->depends_count +
950 pkg->recommends_count +
951 pkg->suggests_count);
952
953 /* skip this package if it is already marked */
954 if (pkg->parent->state_flag & SF_MARKED)
955 continue;
956
957 for (k=0; k<count; k++) {
958 cdep = (what_field_type == CONFLICTS)
959 ? &pkg->conflicts[k]
960 : &pkg->depends[k];
961
962 if (what_field_type != cdep->type)
963 continue;
964
965 for (l=0; l<cdep->possibility_count; l++) {
966 possibility = cdep->possibilities[l];
967
968 if ((possibility->pkg->state_flag
969 & SF_MARKED)
970 != SF_MARKED)
971 continue;
972
973 /* mark the depending package so we
974 * won't visit it again */
975 pkg->state_flag |= SF_MARKED;
976 pkg_mark_provides(pkg);
977 changed++;
978
979 ver = pkg_version_str_alloc(pkg);
980 opkg_msg(NOTICE, "\t%s %s\t%s %s",
981 pkg->name,
982 ver,
983 rel_str,
984 possibility->pkg->name);
985 free(ver);
986 if (possibility->version) {
987 opkg_msg(NOTICE, " (%s%s)",
988 constraint_to_str(possibility->constraint),
989 possibility->version);
990 }
991 if (!pkg_dependence_satisfiable(possibility))
992 opkg_msg(NOTICE,
993 " unsatisfiable");
994 opkg_msg(NOTICE, "\n");
995 goto next_package;
996 }
997 }
998 next_package:
999 ;
1000 }
1001 } while (changed && recursive);
1002
1003 pkg_vec_free(available_pkgs);
1004
1005 return 0;
1006 }
1007
1008 static int
1009 opkg_whatdepends_recursively_cmd(int argc, char **argv)
1010 {
1011 return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv);
1012 }
1013
1014 static int
1015 opkg_whatdepends_cmd(int argc, char **argv)
1016 {
1017 return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv);
1018 }
1019
1020 static int
1021 opkg_whatsuggests_cmd(int argc, char **argv)
1022 {
1023 return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv);
1024 }
1025
1026 static int
1027 opkg_whatrecommends_cmd(int argc, char **argv)
1028 {
1029 return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv);
1030 }
1031
1032 static int
1033 opkg_whatconflicts_cmd(int argc, char **argv)
1034 {
1035 return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv);
1036 }
1037
1038 static int
1039 opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc, char **argv)
1040 {
1041
1042 if (argc > 0) {
1043 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1044 const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1045 int i;
1046
1047 pkg_info_preinstall_check();
1048
1049 if (conf->query_all)
1050 pkg_hash_fetch_available(available_pkgs);
1051 else
1052 pkg_hash_fetch_all_installed(available_pkgs);
1053 for (i = 0; i < argc; i++) {
1054 const char *target = argv[i];
1055 int j;
1056
1057 opkg_msg(NOTICE, "What %s %s\n",
1058 rel_str, target);
1059 for (j = 0; j < available_pkgs->len; j++) {
1060 pkg_t *pkg = available_pkgs->pkgs[j];
1061 int k;
1062 int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1063 for (k = 0; k < count; k++) {
1064 abstract_pkg_t *apkg =
1065 ((what_field_type == WHATPROVIDES)
1066 ? pkg->provides[k]
1067 : pkg->replaces[k]);
1068 if (fnmatch(target, apkg->name, 0) == 0) {
1069 opkg_msg(NOTICE, " %s", pkg->name);
1070 if (strcmp(target, apkg->name) != 0)
1071 opkg_msg(NOTICE, "\t%s %s\n",
1072 rel_str, apkg->name);
1073 opkg_msg(NOTICE, "\n");
1074 }
1075 }
1076 }
1077 }
1078 pkg_vec_free(available_pkgs);
1079 }
1080 return 0;
1081 }
1082
1083 static int
1084 opkg_whatprovides_cmd(int argc, char **argv)
1085 {
1086 return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv);
1087 }
1088
1089 static int
1090 opkg_whatreplaces_cmd(int argc, char **argv)
1091 {
1092 return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv);
1093 }
1094
1095 static int
1096 opkg_search_cmd(int argc, char **argv)
1097 {
1098 int i;
1099
1100 pkg_vec_t *installed;
1101 pkg_t *pkg;
1102 str_list_t *installed_files;
1103 str_list_elt_t *iter;
1104 char *installed_file;
1105
1106 if (argc < 1) {
1107 return -1;
1108 }
1109
1110 installed = pkg_vec_alloc();
1111 pkg_hash_fetch_all_installed(installed);
1112 pkg_vec_sort(installed, pkg_compare_names);
1113
1114 for (i=0; i < installed->len; i++) {
1115 pkg = installed->pkgs[i];
1116
1117 installed_files = pkg_get_installed_files(pkg);
1118
1119 for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1120 installed_file = (char *)iter->data;
1121 if (fnmatch(argv[0], installed_file, 0)==0)
1122 print_pkg(pkg);
1123 }
1124
1125 pkg_free_installed_files(pkg);
1126 }
1127
1128 pkg_vec_free(installed);
1129
1130 return 0;
1131 }
1132
1133 static int
1134 opkg_compare_versions_cmd(int argc, char **argv)
1135 {
1136 if (argc == 3) {
1137 /* this is a bit gross */
1138 struct pkg p1, p2;
1139 parse_version(&p1, argv[0]);
1140 parse_version(&p2, argv[2]);
1141 return pkg_version_satisfied(&p1, &p2, argv[1]);
1142 } else {
1143 opkg_msg(ERROR,
1144 "opkg compare_versions <v1> <op> <v2>\n"
1145 "<op> is one of <= >= << >> =\n");
1146 return -1;
1147 }
1148 }
1149
1150 static int
1151 opkg_print_architecture_cmd(int argc, char **argv)
1152 {
1153 nv_pair_list_elt_t *l;
1154
1155 list_for_each_entry(l, &conf->arch_list.head, node) {
1156 nv_pair_t *nv = (nv_pair_t *)l->data;
1157 printf("arch %s %s\n", nv->name, nv->value);
1158 }
1159 return 0;
1160 }
1161
1162
1163 /* XXX: CLEANUP: The usage strings should be incorporated into this
1164 array for easier maintenance */
1165 static opkg_cmd_t cmds[] = {
1166 {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1167 {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1168 {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd, PFM_SOURCE},
1169 {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE},
1170 {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE},
1171 {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE},
1172 {"list-upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE},
1173 {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd, 0},
1174 {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1175 {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1176 {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1177 {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1178 {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1179 {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1180 {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1181 {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1182 {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1183 {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1184 {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1185 {"print_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 {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1188 {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1189 {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1190 {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1191 {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1192 {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1193 {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1194 {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1195 {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1196 };
1197
1198 opkg_cmd_t *
1199 opkg_cmd_find(const char *name)
1200 {
1201 int i;
1202 opkg_cmd_t *cmd;
1203 int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
1204
1205 for (i=0; i < num_cmds; i++) {
1206 cmd = &cmds[i];
1207 if (strcmp(name, cmd->name) == 0)
1208 return cmd;
1209 }
1210
1211 return NULL;
1212 }
1213
1214 int
1215 opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv)
1216 {
1217 return (cmd->fun)(argc, argv);
1218 }