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