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