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