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