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