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