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