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