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