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