94cfb9987c4a52567163c0879a01900294054a10
[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_DEBUG, "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 && !error_list) {
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 arg);
598 }
599 }
600
601 /* recheck to verify that all dependences are satisfied */
602 if (0) opkg_satisfy_all_dependences(conf);
603
604 opkg_configure_packages(conf, NULL);
605
606 write_status_files_if_changed(conf);
607
608 return err;
609 }
610
611 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv)
612 {
613 int i;
614 pkg_t *pkg;
615 int err;
616
617 global_conf = conf;
618 signal(SIGINT, sigint_handler);
619
620 if (argc) {
621 for (i=0; i < argc; i++) {
622 char *arg = argv[i];
623
624 err = opkg_prepare_url_for_install(conf, arg, &arg);
625 if (err != EINVAL && err != 0)
626 return err;
627 }
628 pkg_info_preinstall_check(conf);
629
630 for (i=0; i < argc; i++) {
631 char *arg = argv[i];
632 if (conf->restrict_to_default_dest) {
633 pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
634 argv[i],
635 conf->default_dest);
636 if (pkg == NULL) {
637 opkg_message(conf, OPKG_NOTICE,
638 "Package %s not installed in %s\n",
639 argv[i], conf->default_dest->name);
640 continue;
641 }
642 } else {
643 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
644 argv[i]);
645 }
646 if (pkg)
647 opkg_upgrade_pkg(conf, pkg);
648 else {
649 opkg_install_by_name(conf, arg);
650 }
651 }
652 } else {
653 pkg_vec_t *installed = pkg_vec_alloc();
654
655 pkg_info_preinstall_check(conf);
656
657 pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
658 for (i = 0; i < installed->len; i++) {
659 pkg = installed->pkgs[i];
660 opkg_upgrade_pkg(conf, pkg);
661 }
662 pkg_vec_free(installed);
663 }
664
665 /* recheck to verify that all dependences are satisfied */
666 if (0) opkg_satisfy_all_dependences(conf);
667
668 opkg_configure_packages(conf, NULL);
669
670 write_status_files_if_changed(conf);
671
672 return 0;
673 }
674
675 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv)
676 {
677 int i, err;
678 char *arg;
679 pkg_t *pkg;
680
681 pkg_info_preinstall_check(conf);
682 for (i = 0; i < argc; i++) {
683 arg = argv[i];
684
685 pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, arg, &err);
686 if (pkg == NULL) {
687 opkg_message(conf, OPKG_ERROR,
688 "Cannot find package %s.\n"
689 "Check the spelling or perhaps run 'opkg update'\n",
690 arg);
691 continue;
692 }
693
694 err = opkg_download_pkg(conf, pkg, ".");
695
696 if (err) {
697 opkg_message(conf, OPKG_ERROR,
698 "Failed to download %s\n", pkg->name);
699 } else {
700 opkg_message(conf, OPKG_NOTICE,
701 "Downloaded %s as %s\n",
702 pkg->name, pkg->local_filename);
703 }
704 }
705
706 return 0;
707 }
708
709
710 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv)
711 {
712 int i ;
713 pkg_vec_t *available;
714 pkg_t *pkg;
715 char desc_short[OPKG_LIST_DESCRIPTION_LENGTH];
716 char *newline;
717 char *pkg_name = NULL;
718 char *version_str;
719
720 if (argc > 0) {
721 pkg_name = argv[0];
722 }
723 available = pkg_vec_alloc();
724 pkg_hash_fetch_available(&conf->pkg_hash, available);
725 for (i=0; i < available->len; i++) {
726 pkg = available->pkgs[i];
727 /* if we have package name or pattern and pkg does not match, then skip it */
728 if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
729 continue;
730 if (pkg->description) {
731 strncpy(desc_short, pkg->description, OPKG_LIST_DESCRIPTION_LENGTH);
732 } else {
733 desc_short[0] = '\0';
734 }
735 desc_short[OPKG_LIST_DESCRIPTION_LENGTH - 1] = '\0';
736 newline = strchr(desc_short, '\n');
737 if (newline) {
738 *newline = '\0';
739 }
740 if (opkg_cb_list) {
741 version_str = pkg_version_str_alloc(pkg);
742 opkg_cb_list(pkg->name,desc_short,
743 version_str,
744 pkg->state_status,
745 p_userdata);
746 free(version_str);
747 }
748 }
749 pkg_vec_free(available);
750
751 return 0;
752 }
753
754
755 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
756 {
757 int i ;
758 pkg_vec_t *available;
759 pkg_t *pkg;
760 char desc_short[OPKG_LIST_DESCRIPTION_LENGTH];
761 char *newline;
762 char *pkg_name = NULL;
763 char *version_str;
764
765 if (argc > 0) {
766 pkg_name = argv[0];
767 }
768 available = pkg_vec_alloc();
769 pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
770 for (i=0; i < available->len; i++) {
771 pkg = available->pkgs[i];
772 /* if we have package name or pattern and pkg does not match, then skip it */
773 if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
774 continue;
775 if (pkg->description) {
776 strncpy(desc_short, pkg->description, OPKG_LIST_DESCRIPTION_LENGTH);
777 } else {
778 desc_short[0] = '\0';
779 }
780 desc_short[OPKG_LIST_DESCRIPTION_LENGTH - 1] = '\0';
781 newline = strchr(desc_short, '\n');
782 if (newline) {
783 *newline = '\0';
784 }
785 if (opkg_cb_list) {
786 version_str = pkg_version_str_alloc(pkg);
787 opkg_cb_list(pkg->name,desc_short,
788 version_str,
789 pkg->state_status,
790 p_userdata);
791 free(version_str);
792 }
793 }
794
795 return 0;
796 }
797
798 static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int installed_only)
799 {
800 int i;
801 pkg_vec_t *available;
802 pkg_t *pkg;
803 char *pkg_name = NULL;
804 char **pkg_fields = NULL;
805 int n_fields = 0;
806 char *buff ; // = (char *)malloc(1);
807
808 if (argc > 0) {
809 pkg_name = argv[0];
810 }
811 if (argc > 1) {
812 pkg_fields = &argv[1];
813 n_fields = argc - 1;
814 }
815
816 available = pkg_vec_alloc();
817 if (installed_only)
818 pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
819 else
820 pkg_hash_fetch_available(&conf->pkg_hash, available);
821 for (i=0; i < available->len; i++) {
822 pkg = available->pkgs[i];
823 if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
824 continue;
825 }
826
827 buff = pkg_formatted_info(pkg);
828 if ( buff ) {
829 if (opkg_cb_status) opkg_cb_status(pkg->name,
830 pkg->state_status,
831 buff,
832 p_userdata);
833 /*
834 We should not forget that actually the pointer is allocated.
835 We need to free it :) ( Thanks florian for seeing the error )
836 */
837 free(buff);
838 }
839 if (conf->verbosity > 1) {
840 conffile_list_elt_t *iter;
841 for (iter = pkg->conffiles.head; iter; iter = iter->next) {
842 conffile_t *cf = iter->data;
843 int modified = conffile_has_been_modified(conf, cf);
844 opkg_message(conf, OPKG_NOTICE, "conffile=%s md5sum=%s modified=%d\n",
845 cf->name, cf->value, modified);
846 }
847 }
848 }
849 pkg_vec_free(available);
850
851 return 0;
852 }
853
854 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv)
855 {
856 return opkg_info_status_cmd(conf, argc, argv, 0);
857 }
858
859 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv)
860 {
861 return opkg_info_status_cmd(conf, argc, argv, 1);
862 }
863
864 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv)
865 {
866
867 int err;
868 if (argc > 0) {
869 char *pkg_name = NULL;
870
871 pkg_name = argv[0];
872
873 err = opkg_configure_packages (conf, pkg_name);
874
875 } else {
876 err = opkg_configure_packages (conf, NULL);
877 }
878
879 write_status_files_if_changed(conf);
880
881 return err;
882 }
883
884 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv)
885 {
886 int i, err;
887 char *globpattern;
888 glob_t globbuf;
889
890 sprintf_alloc(&globpattern, "%s/*" OPKG_PKG_EXTENSION, conf->pending_dir);
891 err = glob(globpattern, 0, NULL, &globbuf);
892 free(globpattern);
893 if (err) {
894 return 0;
895 }
896
897 opkg_message(conf, OPKG_NOTICE,
898 "The following packages in %s will now be installed.\n",
899 conf->pending_dir);
900 for (i = 0; i < globbuf.gl_pathc; i++) {
901 opkg_message(conf, OPKG_NOTICE,
902 "%s%s", i == 0 ? "" : " ", globbuf.gl_pathv[i]);
903 }
904 opkg_message(conf, OPKG_NOTICE, "\n");
905 for (i = 0; i < globbuf.gl_pathc; i++) {
906 err = opkg_install_from_file(conf, globbuf.gl_pathv[i]);
907 if (err == 0) {
908 err = unlink(globbuf.gl_pathv[i]);
909 if (err) {
910 opkg_message(conf, OPKG_ERROR,
911 "%s: ERROR: failed to unlink %s: %s\n",
912 __FUNCTION__, globbuf.gl_pathv[i], strerror(err));
913 return err;
914 }
915 }
916 }
917 globfree(&globbuf);
918
919 return err;
920 }
921
922 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv)
923 {
924 int i,a,done;
925 pkg_t *pkg;
926 pkg_t *pkg_to_remove;
927 pkg_vec_t *available;
928 char *pkg_name = NULL;
929 global_conf = conf;
930 signal(SIGINT, sigint_handler);
931
932 // ENH: Add the "no pkg removed" just in case.
933
934 done = 0;
935
936 available = pkg_vec_alloc();
937 pkg_info_preinstall_check(conf);
938 if ( argc > 0 ) {
939 pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
940 for (i=0; i < argc; i++) {
941 pkg_name = malloc(strlen(argv[i])+2);
942 strcpy(pkg_name,argv[i]);
943 for (a=0; a < available->len; a++) {
944 pkg = available->pkgs[a];
945 if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
946 continue;
947 }
948 if (conf->restrict_to_default_dest) {
949 pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
950 pkg->name,
951 conf->default_dest);
952 } else {
953 pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
954 }
955
956 if (pkg == NULL) {
957 opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
958 continue;
959 }
960 if (pkg->state_status == SS_NOT_INSTALLED) { // Added the control, so every already removed package could be skipped
961 opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
962 continue;
963 }
964 opkg_remove_pkg(conf, pkg_to_remove,0);
965 done = 1;
966 }
967 free (pkg_name);
968 }
969 pkg_vec_free(available);
970 } else {
971 pkg_vec_t *installed_pkgs = pkg_vec_alloc();
972 int i;
973 int flagged_pkg_count = 0;
974 int removed;
975
976 pkg_hash_fetch_all_installed(&conf->pkg_hash, installed_pkgs);
977
978 for (i = 0; i < installed_pkgs->len; i++) {
979 pkg_t *pkg = installed_pkgs->pkgs[i];
980 if (pkg->state_flag & SF_USER) {
981 flagged_pkg_count++;
982 } else {
983 if (!pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL))
984 opkg_message(conf, OPKG_NOTICE, "Non-user leaf package: %s\n", pkg->name);
985 }
986 }
987 if (!flagged_pkg_count) {
988 opkg_message(conf, OPKG_NOTICE, "No packages flagged as installed by user, \n"
989 "so refusing to uninstall unflagged non-leaf packages\n");
990 return 0;
991 }
992
993 /* find packages not flagged SF_USER (i.e., installed to
994 * satisfy a dependence) and not having any dependents, and
995 * remove them */
996 do {
997 removed = 0;
998 for (i = 0; i < installed_pkgs->len; i++) {
999 pkg_t *pkg = installed_pkgs->pkgs[i];
1000 if (!(pkg->state_flag & SF_USER)
1001 && !pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL)) {
1002 removed++;
1003 opkg_message(conf, OPKG_NOTICE, "Removing non-user leaf package %s\n");
1004 opkg_remove_pkg(conf, pkg,0);
1005 done = 1;
1006 }
1007 }
1008 } while (removed);
1009 pkg_vec_free(installed_pkgs);
1010 }
1011
1012 if ( done == 0 )
1013 opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
1014
1015 write_status_files_if_changed(conf);
1016 return 0;
1017 }
1018
1019 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv)
1020 {
1021 int i;
1022 pkg_t *pkg;
1023
1024 global_conf = conf;
1025 signal(SIGINT, sigint_handler);
1026
1027 pkg_info_preinstall_check(conf);
1028
1029 for (i=0; i < argc; i++) {
1030 if (conf->restrict_to_default_dest) {
1031 pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
1032 argv[i],
1033 conf->default_dest);
1034 } else {
1035 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
1036 }
1037
1038 if (pkg == NULL) {
1039 opkg_message(conf, OPKG_ERROR,
1040 "Package %s is not installed.\n", argv[i]);
1041 continue;
1042 }
1043 opkg_purge_pkg(conf, pkg);
1044 }
1045
1046 write_status_files_if_changed(conf);
1047 return 0;
1048 }
1049
1050 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
1051 {
1052 int i;
1053 pkg_t *pkg;
1054 const char *flags = argv[0];
1055
1056 global_conf = conf;
1057 signal(SIGINT, sigint_handler);
1058
1059 for (i=1; i < argc; i++) {
1060 if (conf->restrict_to_default_dest) {
1061 pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
1062 argv[i],
1063 conf->default_dest);
1064 } else {
1065 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
1066 }
1067
1068 if (pkg == NULL) {
1069 opkg_message(conf, OPKG_ERROR,
1070 "Package %s is not installed.\n", argv[i]);
1071 continue;
1072 }
1073 if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
1074 ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
1075 pkg->state_flag = pkg_state_flag_from_str(flags);
1076 }
1077 /* pb_ asked this feature 03292004 */
1078 /* Actually I will use only this two, but this is an open for various status */
1079 if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
1080 pkg->state_status = pkg_state_status_from_str(flags);
1081 }
1082 opkg_state_changed++;
1083 opkg_message(conf, OPKG_NOTICE,
1084 "Setting flags for package %s to %s\n",
1085 pkg->name, flags);
1086 }
1087
1088 write_status_files_if_changed(conf);
1089 return 0;
1090 }
1091
1092 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
1093 {
1094 pkg_t *pkg;
1095 str_list_t *installed_files;
1096 str_list_elt_t *iter;
1097 char *pkg_version;
1098 size_t buff_len = 8192;
1099 size_t used_len;
1100 char *buff ;
1101
1102 buff = (char *)malloc(buff_len);
1103 if ( buff == NULL ) {
1104 fprintf( stderr,"%s: Unable to allocate memory \n",__FUNCTION__);
1105 return ENOMEM;
1106 }
1107
1108 if (argc < 1) {
1109 return EINVAL;
1110 }
1111
1112 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
1113 argv[0]);
1114 if (pkg == NULL) {
1115 opkg_message(conf, OPKG_ERROR,
1116 "Package %s not installed.\n", argv[0]);
1117 return 0;
1118 }
1119
1120 installed_files = pkg_get_installed_files(pkg);
1121 pkg_version = pkg_version_str_alloc(pkg);
1122
1123 if (buff) {
1124 try_again:
1125 used_len = snprintf(buff, buff_len, "Package %s (%s) is installed on %s and has the following files:\n",
1126 pkg->name, pkg_version, pkg->dest->name) + 1;
1127 if (used_len > buff_len) {
1128 buff_len *= 2;
1129 buff = realloc (buff, buff_len);
1130 goto try_again;
1131 }
1132 for (iter = installed_files->head; iter; iter = iter->next) {
1133 used_len += strlen (iter->data) + 1;
1134 while (buff_len <= used_len) {
1135 buff_len *= 2;
1136 buff = realloc (buff, buff_len);
1137 }
1138 strncat(buff, iter->data, buff_len);
1139 strncat(buff, "\n", buff_len);
1140 }
1141 if (opkg_cb_list) opkg_cb_list(pkg->name,
1142 buff,
1143 pkg_version_str_alloc(pkg),
1144 pkg->state_status,
1145 p_userdata);
1146 free(buff);
1147 }
1148
1149 free(pkg_version);
1150 pkg_free_installed_files(pkg);
1151
1152 return 0;
1153 }
1154
1155 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
1156 {
1157
1158 if (argc > 0) {
1159 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1160 const char *rel_str = "depends on";
1161 int i;
1162
1163 pkg_info_preinstall_check(conf);
1164
1165 if (conf->query_all)
1166 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1167 else
1168 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1169 for (i = 0; i < argc; i++) {
1170 const char *target = argv[i];
1171 int j;
1172
1173 opkg_message(conf, OPKG_ERROR, "target=%s\n", target);
1174
1175 for (j = 0; j < available_pkgs->len; j++) {
1176 pkg_t *pkg = available_pkgs->pkgs[j];
1177 if (fnmatch(target, pkg->name, 0) == 0) {
1178 int k;
1179 int count = pkg->depends_count + pkg->pre_depends_count;
1180 opkg_message(conf, OPKG_ERROR, "What %s (arch=%s) %s\n",
1181 target, pkg->architecture, rel_str);
1182 for (k = 0; k < count; k++) {
1183 compound_depend_t *cdepend = &pkg->depends[k];
1184 int l;
1185 for (l = 0; l < cdepend->possibility_count; l++) {
1186 depend_t *possibility = cdepend->possibilities[l];
1187 opkg_message(conf, OPKG_ERROR, " %s", possibility->pkg->name);
1188 if (conf->verbosity > 0) {
1189 // char *ver = abstract_pkg_version_str_alloc(possibility->pkg);
1190 opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
1191 if (possibility->version) {
1192 char *typestr = NULL;
1193 switch (possibility->constraint) {
1194 case NONE: typestr = "none"; break;
1195 case EARLIER: typestr = "<"; break;
1196 case EARLIER_EQUAL: typestr = "<="; break;
1197 case EQUAL: typestr = "="; break;
1198 case LATER_EQUAL: typestr = ">="; break;
1199 case LATER: typestr = ">"; break;
1200 }
1201 opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1202 }
1203 // free(ver);
1204 }
1205 opkg_message(conf, OPKG_ERROR, "\n");
1206 }
1207 }
1208 }
1209 }
1210 }
1211 pkg_vec_free(available_pkgs);
1212 }
1213 return 0;
1214 }
1215
1216 enum what_field_type {
1217 WHATDEPENDS,
1218 WHATCONFLICTS,
1219 WHATPROVIDES,
1220 WHATREPLACES,
1221 WHATRECOMMENDS,
1222 WHATSUGGESTS
1223 };
1224
1225 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int recursive, int argc, char **argv)
1226 {
1227
1228 if (argc > 0) {
1229 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1230 const char *rel_str = NULL;
1231 int i;
1232 int changed;
1233
1234 switch (what_field_type) {
1235 case WHATDEPENDS: rel_str = "depends on"; break;
1236 case WHATCONFLICTS: rel_str = "conflicts with"; break;
1237 case WHATSUGGESTS: rel_str = "suggests"; break;
1238 case WHATRECOMMENDS: rel_str = "recommends"; break;
1239 case WHATPROVIDES: rel_str = "provides"; break;
1240 case WHATREPLACES: rel_str = "replaces"; break;
1241 }
1242
1243 if (conf->query_all)
1244 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1245 else
1246 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1247
1248 /* mark the root set */
1249 pkg_vec_clear_marks(available_pkgs);
1250 opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1251 for (i = 0; i < argc; i++) {
1252 const char *dependee_pattern = argv[i];
1253 pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1254 }
1255 for (i = 0; i < available_pkgs->len; i++) {
1256 pkg_t *pkg = available_pkgs->pkgs[i];
1257 if (pkg->state_flag & SF_MARKED) {
1258 /* mark the parent (abstract) package */
1259 pkg_mark_provides(pkg);
1260 opkg_message(conf, OPKG_NOTICE, " %s\n", pkg->name);
1261 }
1262 }
1263
1264 opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1265 do {
1266 int j;
1267 changed = 0;
1268
1269 for (j = 0; j < available_pkgs->len; j++) {
1270 pkg_t *pkg = available_pkgs->pkgs[j];
1271 int k;
1272 int count = ((what_field_type == WHATCONFLICTS)
1273 ? pkg->conflicts_count
1274 : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1275 /* skip this package if it is already marked */
1276 if (pkg->parent->state_flag & SF_MARKED) {
1277 continue;
1278 }
1279 for (k = 0; k < count; k++) {
1280 compound_depend_t *cdepend =
1281 (what_field_type == WHATCONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1282 int l;
1283 for (l = 0; l < cdepend->possibility_count; l++) {
1284 depend_t *possibility = cdepend->possibilities[l];
1285 if (possibility->pkg->state_flag & SF_MARKED) {
1286 /* mark the depending package so we won't visit it again */
1287 pkg->state_flag |= SF_MARKED;
1288 pkg_mark_provides(pkg);
1289 changed++;
1290
1291 opkg_message(conf, OPKG_NOTICE, " %s", pkg->name);
1292 if (conf->verbosity > 0) {
1293 char *ver = pkg_version_str_alloc(pkg);
1294 opkg_message(conf, OPKG_NOTICE, " %s", ver);
1295 opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1296 if (possibility->version) {
1297 char *typestr = NULL;
1298 switch (possibility->constraint) {
1299 case NONE: typestr = "none"; break;
1300 case EARLIER: typestr = "<"; break;
1301 case EARLIER_EQUAL: typestr = "<="; break;
1302 case EQUAL: typestr = "="; break;
1303 case LATER_EQUAL: typestr = ">="; break;
1304 case LATER: typestr = ">"; break;
1305 }
1306 opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1307 }
1308 free(ver);
1309 if (!pkg_dependence_satisfiable(conf, possibility))
1310 opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1311 }
1312 opkg_message(conf, OPKG_NOTICE, "\n");
1313 goto next_package;
1314 }
1315 }
1316 }
1317 next_package:
1318 ;
1319 }
1320 } while (changed && recursive);
1321 pkg_vec_free(available_pkgs);
1322 }
1323
1324 return 0;
1325 }
1326
1327 int pkg_mark_provides(pkg_t *pkg)
1328 {
1329 int provides_count = pkg->provides_count;
1330 abstract_pkg_t **provides = pkg->provides;
1331 int i;
1332 pkg->parent->state_flag |= SF_MARKED;
1333 for (i = 0; i < provides_count; i++) {
1334 provides[i]->state_flag |= SF_MARKED;
1335 }
1336 return 0;
1337 }
1338
1339 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1340 {
1341 return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 1, argc, argv);
1342 }
1343 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1344 {
1345 return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 0, argc, argv);
1346 }
1347
1348 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1349 {
1350 return opkg_what_depends_conflicts_cmd(conf, WHATSUGGESTS, 0, argc, argv);
1351 }
1352
1353 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1354 {
1355 return opkg_what_depends_conflicts_cmd(conf, WHATRECOMMENDS, 0, argc, argv);
1356 }
1357
1358 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1359 {
1360 return opkg_what_depends_conflicts_cmd(conf, WHATCONFLICTS, 0, argc, argv);
1361 }
1362
1363 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1364 {
1365
1366 if (argc > 0) {
1367 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1368 const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1369 int i;
1370
1371 pkg_info_preinstall_check(conf);
1372
1373 if (conf->query_all)
1374 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1375 else
1376 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1377 for (i = 0; i < argc; i++) {
1378 const char *target = argv[i];
1379 int j;
1380
1381 opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1382 rel_str, target);
1383 for (j = 0; j < available_pkgs->len; j++) {
1384 pkg_t *pkg = available_pkgs->pkgs[j];
1385 int k;
1386 int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1387 for (k = 0; k < count; k++) {
1388 abstract_pkg_t *apkg =
1389 ((what_field_type == WHATPROVIDES)
1390 ? pkg->provides[k]
1391 : pkg->replaces[k]);
1392 if (fnmatch(target, apkg->name, 0) == 0) {
1393 opkg_message(conf, OPKG_ERROR, " %s", pkg->name);
1394 if (strcmp(target, apkg->name) != 0)
1395 opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1396 opkg_message(conf, OPKG_ERROR, "\n");
1397 }
1398 }
1399 }
1400 }
1401 pkg_vec_free(available_pkgs);
1402 }
1403 return 0;
1404 }
1405
1406 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1407 {
1408 return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1409 }
1410
1411 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1412 {
1413 return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1414 }
1415
1416 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1417 {
1418 int i;
1419
1420 pkg_vec_t *installed;
1421 pkg_t *pkg;
1422 str_list_t *installed_files;
1423 str_list_elt_t *iter;
1424 char *installed_file;
1425
1426 if (argc < 1) {
1427 return EINVAL;
1428 }
1429
1430 installed = pkg_vec_alloc();
1431 pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1432
1433 for (i=0; i < installed->len; i++) {
1434 pkg = installed->pkgs[i];
1435
1436 installed_files = pkg_get_installed_files(pkg);
1437
1438 for (iter = installed_files->head; iter; iter = iter->next) {
1439 installed_file = iter->data;
1440 if (fnmatch(argv[0], installed_file, 0)==0) {
1441 if (opkg_cb_list) opkg_cb_list(pkg->name,
1442 installed_file,
1443 pkg_version_str_alloc(pkg),
1444 pkg->state_status, p_userdata);
1445 }
1446 }
1447
1448 pkg_free_installed_files(pkg);
1449 }
1450
1451 /* XXX: CLEANUP: It's not obvious from the name of
1452 pkg_hash_fetch_all_installed that we need to call
1453 pkg_vec_free to avoid a memory leak. */
1454 pkg_vec_free(installed);
1455
1456 return 0;
1457 }
1458
1459 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1460 {
1461 if (argc == 3) {
1462 /* this is a bit gross */
1463 struct pkg p1, p2;
1464 parseVersion(&p1, argv[0]);
1465 parseVersion(&p2, argv[2]);
1466 return pkg_version_satisfied(&p1, &p2, argv[1]);
1467 } else {
1468 opkg_message(conf, OPKG_ERROR,
1469 "opkg compare_versions <v1> <op> <v2>\n"
1470 "<op> is one of <= >= << >> =\n");
1471 return -1;
1472 }
1473 }
1474
1475 #ifndef HOST_CPU_STR
1476 #define HOST_CPU_STR__(X) #X
1477 #define HOST_CPU_STR_(X) HOST_CPU_STR__(X)
1478 #define HOST_CPU_STR HOST_CPU_STR_(HOST_CPU_FOO)
1479 #endif
1480
1481 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1482 {
1483 nv_pair_list_elt_t *l;
1484
1485 l = conf->arch_list.head;
1486 while (l) {
1487 nv_pair_t *nv = l->data;
1488 printf("arch %s %s\n", nv->name, nv->value);
1489 l = l->next;
1490 }
1491 return 0;
1492 }
1493
1494