Remove the purge command. Undocumented and only duplicates remove functionality.
[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 /* pb_ asked this feature 03292004 */
884 /* Actually I will use only this two, but this is an open for various status */
885 if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
886 pkg->state_status = pkg_state_status_from_str(flags);
887 }
888 opkg_state_changed++;
889 opkg_message(conf, OPKG_NOTICE,
890 "Setting flags for package %s to %s\n",
891 pkg->name, flags);
892 }
893
894 write_status_files_if_changed(conf);
895 return 0;
896 }
897
898 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
899 {
900 pkg_t *pkg;
901 str_list_t *files;
902 str_list_elt_t *iter;
903 char *pkg_version;
904
905 if (argc < 1) {
906 return EINVAL;
907 }
908
909 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
910 argv[0]);
911 if (pkg == NULL) {
912 opkg_message(conf, OPKG_ERROR,
913 "Package %s not installed.\n", argv[0]);
914 return 0;
915 }
916
917 files = pkg_get_installed_files(conf, pkg);
918 pkg_version = pkg_version_str_alloc(pkg);
919
920 printf("Package %s (%s) is installed on %s and has the following files:\n",
921 pkg->name, pkg_version, pkg->dest->name);
922
923 for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
924 printf("%s\n", (char *)iter->data);
925
926 free(pkg_version);
927 pkg_free_installed_files(pkg);
928
929 return 0;
930 }
931
932 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
933 {
934
935 if (argc > 0) {
936 pkg_vec_t *available_pkgs = pkg_vec_alloc();
937 const char *rel_str = "depends on";
938 int i;
939
940 pkg_info_preinstall_check(conf);
941
942 if (conf->query_all)
943 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
944 else
945 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
946 for (i = 0; i < argc; i++) {
947 const char *target = argv[i];
948 int j;
949
950 opkg_message(conf, OPKG_NOTICE, "target=%s\n", target);
951
952 for (j = 0; j < available_pkgs->len; j++) {
953 pkg_t *pkg = available_pkgs->pkgs[j];
954 if (fnmatch(target, pkg->name, 0) == 0) {
955 int k;
956 int count = pkg->depends_count + pkg->pre_depends_count;
957 opkg_message(conf, OPKG_NOTICE, "What %s (arch=%s) %s\n",
958 target, pkg->architecture, rel_str);
959 for (k = 0; k < count; k++) {
960 compound_depend_t *cdepend = &pkg->depends[k];
961 int l;
962 for (l = 0; l < cdepend->possibility_count; l++) {
963 depend_t *possibility = cdepend->possibilities[l];
964 opkg_message(conf, OPKG_NOTICE, " %s", possibility->pkg->name);
965 if (conf->verbosity >= OPKG_NOTICE) {
966 if (possibility->version) {
967 char *typestr = NULL;
968 opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
969 switch (possibility->constraint) {
970 case NONE: typestr = "none"; break;
971 case EARLIER: typestr = "<"; break;
972 case EARLIER_EQUAL: typestr = "<="; break;
973 case EQUAL: typestr = "="; break;
974 case LATER_EQUAL: typestr = ">="; break;
975 case LATER: typestr = ">"; break;
976 }
977 opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
978 }
979 }
980 opkg_message(conf, OPKG_NOTICE, "\n");
981 }
982 }
983 }
984 }
985 }
986 pkg_vec_free(available_pkgs);
987 }
988 return 0;
989 }
990
991 enum what_field_type {
992 WHATDEPENDS,
993 WHATCONFLICTS,
994 WHATPROVIDES,
995 WHATREPLACES,
996 WHATRECOMMENDS,
997 WHATSUGGESTS
998 };
999
1000 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum depend_type what_field_type, int recursive, int argc, char **argv)
1001 {
1002
1003 if (argc > 0) {
1004 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1005 const char *rel_str = NULL;
1006 int i;
1007 int changed;
1008
1009 switch (what_field_type) {
1010 case DEPEND: rel_str = "depends on"; break;
1011 case CONFLICTS: rel_str = "conflicts with"; break;
1012 case SUGGEST: rel_str = "suggests"; break;
1013 case RECOMMEND: rel_str = "recommends"; break;
1014 default: return -1;
1015 }
1016
1017 if (conf->query_all)
1018 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1019 else
1020 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1021
1022 /* mark the root set */
1023 pkg_vec_clear_marks(available_pkgs);
1024 opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1025 for (i = 0; i < argc; i++) {
1026 const char *dependee_pattern = argv[i];
1027 pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1028 }
1029 for (i = 0; i < available_pkgs->len; i++) {
1030 pkg_t *pkg = available_pkgs->pkgs[i];
1031 if (pkg->state_flag & SF_MARKED) {
1032 /* mark the parent (abstract) package */
1033 pkg_mark_provides(pkg);
1034 opkg_message(conf, OPKG_NOTICE, " %s\n", pkg->name);
1035 }
1036 }
1037
1038 opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1039 do {
1040 int j;
1041 changed = 0;
1042
1043 for (j = 0; j < available_pkgs->len; j++) {
1044 pkg_t *pkg = available_pkgs->pkgs[j];
1045 int k;
1046 int count = ((what_field_type == CONFLICTS)
1047 ? pkg->conflicts_count
1048 : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1049 /* skip this package if it is already marked */
1050 if (pkg->parent->state_flag & SF_MARKED) {
1051 continue;
1052 }
1053 for (k = 0; k < count; k++) {
1054 compound_depend_t *cdepend =
1055 (what_field_type == CONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1056 int l;
1057 if (what_field_type != cdepend->type)
1058 continue;
1059 for (l = 0; l < cdepend->possibility_count; l++) {
1060 depend_t *possibility = cdepend->possibilities[l];
1061 if (possibility->pkg->state_flag & SF_MARKED) {
1062 /* mark the depending package so we won't visit it again */
1063 pkg->state_flag |= SF_MARKED;
1064 pkg_mark_provides(pkg);
1065 changed++;
1066
1067 if (conf->verbosity >= OPKG_NOTICE) {
1068 char *ver = pkg_version_str_alloc(pkg);
1069 opkg_message(conf, OPKG_NOTICE, " %s", pkg->name);
1070 opkg_message(conf, OPKG_NOTICE, " %s", ver);
1071 opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1072 if (possibility->version) {
1073 char *typestr = NULL;
1074 switch (possibility->constraint) {
1075 case NONE: typestr = "none"; break;
1076 case EARLIER: typestr = "<"; break;
1077 case EARLIER_EQUAL: typestr = "<="; break;
1078 case EQUAL: typestr = "="; break;
1079 case LATER_EQUAL: typestr = ">="; break;
1080 case LATER: typestr = ">"; break;
1081 }
1082 opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1083 }
1084 free(ver);
1085 if (!pkg_dependence_satisfiable(conf, possibility))
1086 opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1087 }
1088 opkg_message(conf, OPKG_NOTICE, "\n");
1089 goto next_package;
1090 }
1091 }
1092 }
1093 next_package:
1094 ;
1095 }
1096 } while (changed && recursive);
1097 pkg_vec_free(available_pkgs);
1098 }
1099
1100 return 0;
1101 }
1102
1103 static int pkg_mark_provides(pkg_t *pkg)
1104 {
1105 int provides_count = pkg->provides_count;
1106 abstract_pkg_t **provides = pkg->provides;
1107 int i;
1108 pkg->parent->state_flag |= SF_MARKED;
1109 for (i = 0; i < provides_count; i++) {
1110 provides[i]->state_flag |= SF_MARKED;
1111 }
1112 return 0;
1113 }
1114
1115 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1116 {
1117 return opkg_what_depends_conflicts_cmd(conf, DEPEND, 1, argc, argv);
1118 }
1119 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1120 {
1121 return opkg_what_depends_conflicts_cmd(conf, DEPEND, 0, argc, argv);
1122 }
1123
1124 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1125 {
1126 return opkg_what_depends_conflicts_cmd(conf, SUGGEST, 0, argc, argv);
1127 }
1128
1129 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1130 {
1131 return opkg_what_depends_conflicts_cmd(conf, RECOMMEND, 0, argc, argv);
1132 }
1133
1134 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1135 {
1136 return opkg_what_depends_conflicts_cmd(conf, CONFLICTS, 0, argc, argv);
1137 }
1138
1139 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1140 {
1141
1142 if (argc > 0) {
1143 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1144 const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1145 int i;
1146
1147 pkg_info_preinstall_check(conf);
1148
1149 if (conf->query_all)
1150 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1151 else
1152 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1153 for (i = 0; i < argc; i++) {
1154 const char *target = argv[i];
1155 int j;
1156
1157 opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1158 rel_str, target);
1159 for (j = 0; j < available_pkgs->len; j++) {
1160 pkg_t *pkg = available_pkgs->pkgs[j];
1161 int k;
1162 int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1163 for (k = 0; k < count; k++) {
1164 abstract_pkg_t *apkg =
1165 ((what_field_type == WHATPROVIDES)
1166 ? pkg->provides[k]
1167 : pkg->replaces[k]);
1168 if (fnmatch(target, apkg->name, 0) == 0) {
1169 opkg_message(conf, OPKG_ERROR, " %s", pkg->name);
1170 if (strcmp(target, apkg->name) != 0)
1171 opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1172 opkg_message(conf, OPKG_ERROR, "\n");
1173 }
1174 }
1175 }
1176 }
1177 pkg_vec_free(available_pkgs);
1178 }
1179 return 0;
1180 }
1181
1182 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1183 {
1184 return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1185 }
1186
1187 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1188 {
1189 return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1190 }
1191
1192 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1193 {
1194 int i;
1195
1196 pkg_vec_t *installed;
1197 pkg_t *pkg;
1198 str_list_t *installed_files;
1199 str_list_elt_t *iter;
1200 char *installed_file;
1201
1202 if (argc < 1) {
1203 return EINVAL;
1204 }
1205
1206 installed = pkg_vec_alloc();
1207 pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1208 pkg_vec_sort(installed, pkg_compare_names);
1209
1210 for (i=0; i < installed->len; i++) {
1211 pkg = installed->pkgs[i];
1212
1213 installed_files = pkg_get_installed_files(conf, pkg);
1214
1215 for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1216 installed_file = (char *)iter->data;
1217 if (fnmatch(argv[0], installed_file, 0)==0)
1218 print_pkg(pkg);
1219 }
1220
1221 pkg_free_installed_files(pkg);
1222 }
1223
1224 pkg_vec_free(installed);
1225
1226 return 0;
1227 }
1228
1229 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1230 {
1231 if (argc == 3) {
1232 /* this is a bit gross */
1233 struct pkg p1, p2;
1234 parse_version(&p1, argv[0]);
1235 parse_version(&p2, argv[2]);
1236 return pkg_version_satisfied(&p1, &p2, argv[1]);
1237 } else {
1238 opkg_message(conf, OPKG_ERROR,
1239 "opkg compare_versions <v1> <op> <v2>\n"
1240 "<op> is one of <= >= << >> =\n");
1241 return -1;
1242 }
1243 }
1244
1245 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1246 {
1247 nv_pair_list_elt_t *l;
1248
1249 list_for_each_entry(l, &conf->arch_list.head, node) {
1250 nv_pair_t *nv = (nv_pair_t *)l->data;
1251 printf("arch %s %s\n", nv->name, nv->value);
1252 }
1253 return 0;
1254 }