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