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