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