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