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