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