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