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