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