9a490828c7bb9d17f714c72837b8b3a52601984e
[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 char *cmd;
327 DIR *dir;
328 int err = 0;
329
330 setenv ("PATH", ctx->oldpath, 1);
331 free (ctx->oldpath);
332
333 dir = opendir (ctx->statedir);
334 if (dir) {
335 struct dirent *de;
336 while (de = readdir (dir), de != NULL) {
337 char *path;
338
339 if (de->d_name[0] == '.')
340 continue;
341
342 sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name);
343 if (access (path, X_OK) == 0) {
344 xsystem (path);
345 }
346 free (path);
347 }
348 closedir(dir);
349 } else
350 perror (ctx->statedir);
351
352 sprintf_alloc (&cmd, "rm -rf %s", ctx->statedir);
353 err = xsystem (cmd);
354 free (cmd);
355
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 char *pkg_name = NULL;
853 global_conf = conf;
854 signal(SIGINT, sigint_handler);
855
856 // ENH: Add the "no pkg removed" just in case.
857
858 done = 0;
859
860 pkg_info_preinstall_check(conf);
861 if ( argc > 0 ) {
862 available = pkg_vec_alloc();
863 pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
864 for (i=0; i < argc; i++) {
865 pkg_name = xcalloc(1, strlen(argv[i])+2);
866 strcpy(pkg_name,argv[i]);
867 for (a=0; a < available->len; a++) {
868 pkg = available->pkgs[a];
869 if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
870 continue;
871 }
872 if (conf->restrict_to_default_dest) {
873 pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
874 pkg->name,
875 conf->default_dest);
876 } else {
877 pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
878 }
879
880 if (pkg_to_remove == NULL) {
881 opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
882 continue;
883 }
884 if (pkg->state_status == SS_NOT_INSTALLED) { // Added the control, so every already removed package could be skipped
885 opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
886 continue;
887 }
888 opkg_remove_pkg(conf, pkg_to_remove,0);
889 done = 1;
890 }
891 free (pkg_name);
892 }
893 pkg_vec_free(available);
894 } else {
895 pkg_vec_t *installed_pkgs = pkg_vec_alloc();
896 int i;
897 int flagged_pkg_count = 0;
898 int removed;
899
900 pkg_hash_fetch_all_installed(&conf->pkg_hash, installed_pkgs);
901
902 for (i = 0; i < installed_pkgs->len; i++) {
903 pkg_t *pkg = installed_pkgs->pkgs[i];
904 if (pkg->state_flag & SF_USER) {
905 flagged_pkg_count++;
906 } else {
907 if (!pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL))
908 opkg_message(conf, OPKG_NOTICE, "Non-user leaf package: %s\n", pkg->name);
909 }
910 }
911 if (!flagged_pkg_count) {
912 opkg_message(conf, OPKG_NOTICE, "No packages flagged as installed by user, \n"
913 "so refusing to uninstall unflagged non-leaf packages\n");
914 return 0;
915 }
916
917 /* find packages not flagged SF_USER (i.e., installed to
918 * satisfy a dependence) and not having any dependents, and
919 * remove them */
920 do {
921 removed = 0;
922 for (i = 0; i < installed_pkgs->len; i++) {
923 pkg_t *pkg = installed_pkgs->pkgs[i];
924 if (!(pkg->state_flag & SF_USER)
925 && !pkg_has_installed_dependents(conf, pkg->parent, pkg, NULL)) {
926 removed++;
927 opkg_message(conf, OPKG_NOTICE, "Removing non-user leaf package %s\n");
928 opkg_remove_pkg(conf, pkg,0);
929 done = 1;
930 }
931 }
932 } while (removed);
933 pkg_vec_free(installed_pkgs);
934 }
935
936 if ( done == 0 )
937 opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
938
939 write_status_files_if_changed(conf);
940 return 0;
941 }
942
943 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv)
944 {
945 int i;
946 pkg_t *pkg;
947
948 global_conf = conf;
949 signal(SIGINT, sigint_handler);
950
951 pkg_info_preinstall_check(conf);
952
953 for (i=0; i < argc; i++) {
954 if (conf->restrict_to_default_dest) {
955 pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
956 argv[i],
957 conf->default_dest);
958 } else {
959 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
960 }
961
962 if (pkg == NULL) {
963 opkg_message(conf, OPKG_ERROR,
964 "Package %s is not installed.\n", argv[i]);
965 continue;
966 }
967 opkg_purge_pkg(conf, pkg);
968 }
969
970 write_status_files_if_changed(conf);
971 return 0;
972 }
973
974 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
975 {
976 int i;
977 pkg_t *pkg;
978 const char *flags = argv[0];
979
980 global_conf = conf;
981 signal(SIGINT, sigint_handler);
982
983 for (i=1; i < argc; i++) {
984 if (conf->restrict_to_default_dest) {
985 pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
986 argv[i],
987 conf->default_dest);
988 } else {
989 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
990 }
991
992 if (pkg == NULL) {
993 opkg_message(conf, OPKG_ERROR,
994 "Package %s is not installed.\n", argv[i]);
995 continue;
996 }
997 if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
998 ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
999 pkg->state_flag = pkg_state_flag_from_str(flags);
1000 }
1001 /* pb_ asked this feature 03292004 */
1002 /* Actually I will use only this two, but this is an open for various status */
1003 if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
1004 pkg->state_status = pkg_state_status_from_str(flags);
1005 }
1006 opkg_state_changed++;
1007 opkg_message(conf, OPKG_NOTICE,
1008 "Setting flags for package %s to %s\n",
1009 pkg->name, flags);
1010 }
1011
1012 write_status_files_if_changed(conf);
1013 return 0;
1014 }
1015
1016 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
1017 {
1018 pkg_t *pkg;
1019 str_list_t *files;
1020 str_list_elt_t *iter;
1021 char *pkg_version;
1022
1023 if (argc < 1) {
1024 return EINVAL;
1025 }
1026
1027 pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
1028 argv[0]);
1029 if (pkg == NULL) {
1030 opkg_message(conf, OPKG_ERROR,
1031 "Package %s not installed.\n", argv[0]);
1032 return 0;
1033 }
1034
1035 files = pkg_get_installed_files(pkg);
1036 pkg_version = pkg_version_str_alloc(pkg);
1037
1038 printf("Package %s (%s) is installed on %s and has the following files:\n",
1039 pkg->name, pkg_version, pkg->dest->name);
1040
1041 for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
1042 printf("%s\n", (char *)iter->data);
1043
1044 free(pkg_version);
1045 pkg_free_installed_files(pkg);
1046
1047 return 0;
1048 }
1049
1050 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
1051 {
1052
1053 if (argc > 0) {
1054 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1055 const char *rel_str = "depends on";
1056 int i;
1057
1058 pkg_info_preinstall_check(conf);
1059
1060 if (conf->query_all)
1061 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1062 else
1063 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1064 for (i = 0; i < argc; i++) {
1065 const char *target = argv[i];
1066 int j;
1067
1068 opkg_message(conf, OPKG_ERROR, "target=%s\n", target);
1069
1070 for (j = 0; j < available_pkgs->len; j++) {
1071 pkg_t *pkg = available_pkgs->pkgs[j];
1072 if (fnmatch(target, pkg->name, 0) == 0) {
1073 int k;
1074 int count = pkg->depends_count + pkg->pre_depends_count;
1075 opkg_message(conf, OPKG_ERROR, "What %s (arch=%s) %s\n",
1076 target, pkg->architecture, rel_str);
1077 for (k = 0; k < count; k++) {
1078 compound_depend_t *cdepend = &pkg->depends[k];
1079 int l;
1080 for (l = 0; l < cdepend->possibility_count; l++) {
1081 depend_t *possibility = cdepend->possibilities[l];
1082 opkg_message(conf, OPKG_ERROR, " %s", possibility->pkg->name);
1083 if (conf->verbosity >= OPKG_NOTICE) {
1084 opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
1085 if (possibility->version) {
1086 char *typestr = NULL;
1087 switch (possibility->constraint) {
1088 case NONE: typestr = "none"; break;
1089 case EARLIER: typestr = "<"; break;
1090 case EARLIER_EQUAL: typestr = "<="; break;
1091 case EQUAL: typestr = "="; break;
1092 case LATER_EQUAL: typestr = ">="; break;
1093 case LATER: typestr = ">"; break;
1094 }
1095 opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1096 }
1097 }
1098 opkg_message(conf, OPKG_ERROR, "\n");
1099 }
1100 }
1101 }
1102 }
1103 }
1104 pkg_vec_free(available_pkgs);
1105 }
1106 return 0;
1107 }
1108
1109 enum what_field_type {
1110 WHATDEPENDS,
1111 WHATCONFLICTS,
1112 WHATPROVIDES,
1113 WHATREPLACES,
1114 WHATRECOMMENDS,
1115 WHATSUGGESTS
1116 };
1117
1118 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int recursive, int argc, char **argv)
1119 {
1120
1121 if (argc > 0) {
1122 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1123 const char *rel_str = NULL;
1124 int i;
1125 int changed;
1126
1127 switch (what_field_type) {
1128 case WHATDEPENDS: rel_str = "depends on"; break;
1129 case WHATCONFLICTS: rel_str = "conflicts with"; break;
1130 case WHATSUGGESTS: rel_str = "suggests"; break;
1131 case WHATRECOMMENDS: rel_str = "recommends"; break;
1132 case WHATPROVIDES: rel_str = "provides"; break;
1133 case WHATREPLACES: rel_str = "replaces"; break;
1134 }
1135
1136 if (conf->query_all)
1137 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1138 else
1139 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1140
1141 /* mark the root set */
1142 pkg_vec_clear_marks(available_pkgs);
1143 opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1144 for (i = 0; i < argc; i++) {
1145 const char *dependee_pattern = argv[i];
1146 pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1147 }
1148 for (i = 0; i < available_pkgs->len; i++) {
1149 pkg_t *pkg = available_pkgs->pkgs[i];
1150 if (pkg->state_flag & SF_MARKED) {
1151 /* mark the parent (abstract) package */
1152 pkg_mark_provides(pkg);
1153 opkg_message(conf, OPKG_NOTICE, " %s\n", pkg->name);
1154 }
1155 }
1156
1157 opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1158 do {
1159 int j;
1160 changed = 0;
1161
1162 for (j = 0; j < available_pkgs->len; j++) {
1163 pkg_t *pkg = available_pkgs->pkgs[j];
1164 int k;
1165 int count = ((what_field_type == WHATCONFLICTS)
1166 ? pkg->conflicts_count
1167 : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1168 /* skip this package if it is already marked */
1169 if (pkg->parent->state_flag & SF_MARKED) {
1170 continue;
1171 }
1172 for (k = 0; k < count; k++) {
1173 compound_depend_t *cdepend =
1174 (what_field_type == WHATCONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1175 int l;
1176 for (l = 0; l < cdepend->possibility_count; l++) {
1177 depend_t *possibility = cdepend->possibilities[l];
1178 if (possibility->pkg->state_flag & SF_MARKED) {
1179 /* mark the depending package so we won't visit it again */
1180 pkg->state_flag |= SF_MARKED;
1181 pkg_mark_provides(pkg);
1182 changed++;
1183
1184 if (conf->verbosity >= OPKG_NOTICE) {
1185 char *ver = pkg_version_str_alloc(pkg);
1186 opkg_message(conf, OPKG_NOTICE, " %s", pkg->name);
1187 opkg_message(conf, OPKG_NOTICE, " %s", ver);
1188 opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1189 if (possibility->version) {
1190 char *typestr = NULL;
1191 switch (possibility->constraint) {
1192 case NONE: typestr = "none"; break;
1193 case EARLIER: typestr = "<"; break;
1194 case EARLIER_EQUAL: typestr = "<="; break;
1195 case EQUAL: typestr = "="; break;
1196 case LATER_EQUAL: typestr = ">="; break;
1197 case LATER: typestr = ">"; break;
1198 }
1199 opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1200 }
1201 free(ver);
1202 if (!pkg_dependence_satisfiable(conf, possibility))
1203 opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1204 }
1205 opkg_message(conf, OPKG_NOTICE, "\n");
1206 goto next_package;
1207 }
1208 }
1209 }
1210 next_package:
1211 ;
1212 }
1213 } while (changed && recursive);
1214 pkg_vec_free(available_pkgs);
1215 }
1216
1217 return 0;
1218 }
1219
1220 static int pkg_mark_provides(pkg_t *pkg)
1221 {
1222 int provides_count = pkg->provides_count;
1223 abstract_pkg_t **provides = pkg->provides;
1224 int i;
1225 pkg->parent->state_flag |= SF_MARKED;
1226 for (i = 0; i < provides_count; i++) {
1227 provides[i]->state_flag |= SF_MARKED;
1228 }
1229 return 0;
1230 }
1231
1232 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1233 {
1234 return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 1, argc, argv);
1235 }
1236 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1237 {
1238 return opkg_what_depends_conflicts_cmd(conf, WHATDEPENDS, 0, argc, argv);
1239 }
1240
1241 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1242 {
1243 return opkg_what_depends_conflicts_cmd(conf, WHATSUGGESTS, 0, argc, argv);
1244 }
1245
1246 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1247 {
1248 return opkg_what_depends_conflicts_cmd(conf, WHATRECOMMENDS, 0, argc, argv);
1249 }
1250
1251 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1252 {
1253 return opkg_what_depends_conflicts_cmd(conf, WHATCONFLICTS, 0, argc, argv);
1254 }
1255
1256 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1257 {
1258
1259 if (argc > 0) {
1260 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1261 const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1262 int i;
1263
1264 pkg_info_preinstall_check(conf);
1265
1266 if (conf->query_all)
1267 pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1268 else
1269 pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1270 for (i = 0; i < argc; i++) {
1271 const char *target = argv[i];
1272 int j;
1273
1274 opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1275 rel_str, target);
1276 for (j = 0; j < available_pkgs->len; j++) {
1277 pkg_t *pkg = available_pkgs->pkgs[j];
1278 int k;
1279 int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1280 for (k = 0; k < count; k++) {
1281 abstract_pkg_t *apkg =
1282 ((what_field_type == WHATPROVIDES)
1283 ? pkg->provides[k]
1284 : pkg->replaces[k]);
1285 if (fnmatch(target, apkg->name, 0) == 0) {
1286 opkg_message(conf, OPKG_ERROR, " %s", pkg->name);
1287 if (strcmp(target, apkg->name) != 0)
1288 opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1289 opkg_message(conf, OPKG_ERROR, "\n");
1290 }
1291 }
1292 }
1293 }
1294 pkg_vec_free(available_pkgs);
1295 }
1296 return 0;
1297 }
1298
1299 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1300 {
1301 return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1302 }
1303
1304 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1305 {
1306 return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1307 }
1308
1309 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1310 {
1311 int i;
1312
1313 pkg_vec_t *installed;
1314 pkg_t *pkg;
1315 str_list_t *installed_files;
1316 str_list_elt_t *iter;
1317 char *installed_file;
1318
1319 if (argc < 1) {
1320 return EINVAL;
1321 }
1322
1323 installed = pkg_vec_alloc();
1324 pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1325 pkg_vec_sort(installed, pkg_compare_names);
1326
1327 for (i=0; i < installed->len; i++) {
1328 pkg = installed->pkgs[i];
1329
1330 installed_files = pkg_get_installed_files(pkg);
1331
1332 for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1333 installed_file = (char *)iter->data;
1334 if (fnmatch(argv[0], installed_file, 0)==0)
1335 print_pkg(pkg);
1336 }
1337
1338 pkg_free_installed_files(pkg);
1339 }
1340
1341 pkg_vec_free(installed);
1342
1343 return 0;
1344 }
1345
1346 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1347 {
1348 if (argc == 3) {
1349 /* this is a bit gross */
1350 struct pkg p1, p2;
1351 parse_version(&p1, argv[0]);
1352 parse_version(&p2, argv[2]);
1353 return pkg_version_satisfied(&p1, &p2, argv[1]);
1354 } else {
1355 opkg_message(conf, OPKG_ERROR,
1356 "opkg compare_versions <v1> <op> <v2>\n"
1357 "<op> is one of <= >= << >> =\n");
1358 return -1;
1359 }
1360 }
1361
1362 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1363 {
1364 nv_pair_list_elt_t *l;
1365
1366 list_for_each_entry(l, &conf->arch_list.head, node) {
1367 nv_pair_t *nv = (nv_pair_t *)l->data;
1368 printf("arch %s %s\n", nv->name, nv->value);
1369 }
1370 return 0;
1371 }