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