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