libopkg: selectively load package feeds in opkg_info_status_cmd()
[oweals/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 #include "config.h"
19
20 #include <stdio.h>
21 #include <dirent.h>
22 #include <glob.h>
23 #include <fnmatch.h>
24 #include <signal.h>
25 #include <unistd.h>
26
27 #include "opkg_conf.h"
28 #include "opkg_cmd.h"
29 #include "opkg_message.h"
30 #include "pkg.h"
31 #include "pkg_dest.h"
32 #include "pkg_parse.h"
33 #include "sprintf_alloc.h"
34 #include "pkg.h"
35 #include "file_util.h"
36 #include "libbb/libbb.h"
37 #include "opkg_utils.h"
38 #include "opkg_defines.h"
39 #include "opkg_download.h"
40 #include "opkg_install.h"
41 #include "opkg_upgrade.h"
42 #include "opkg_remove.h"
43 #include "opkg_configure.h"
44 #include "xsystem.h"
45
46 static void print_pkg(pkg_t * pkg)
47 {
48         char *version = pkg_version_str_alloc(pkg);
49         char *description = pkg_get_string(pkg, PKG_DESCRIPTION);
50         printf("%s - %s", pkg->name, version);
51         if (conf->size)
52                 printf(" - %lu", (unsigned long) pkg_get_int(pkg, PKG_SIZE));
53         if (description)
54                 printf(" - %s", description);
55         printf("\n");
56         free(version);
57 }
58
59 int opkg_state_changed;
60
61 static void write_status_files_if_changed(void)
62 {
63         if (opkg_state_changed && !conf->noaction) {
64                 opkg_msg(INFO, "Writing status file.\n");
65                 opkg_conf_write_status_files();
66                 pkg_write_changed_filelists();
67         } else {
68                 opkg_msg(DEBUG, "Nothing to be done.\n");
69         }
70 }
71
72 static void sigint_handler(int sig)
73 {
74         signal(sig, SIG_DFL);
75         opkg_msg(NOTICE, "Interrupted. Writing out status database.\n");
76         write_status_files_if_changed();
77         exit(128 + sig);
78 }
79
80 static int opkg_update_cmd(int argc, char **argv)
81 {
82         char *tmp;
83         int err;
84         int failures;
85         int pkglist_dl_error;
86         char *lists_dir;
87         pkg_src_list_elt_t *iter;
88         pkg_src_t *src;
89
90         sprintf_alloc(&lists_dir, "%s",
91                       conf->restrict_to_default_dest ? conf->default_dest->
92                       lists_dir : conf->lists_dir);
93
94         if (!file_is_dir(lists_dir)) {
95                 if (file_exists(lists_dir)) {
96                         opkg_msg(ERROR, "%s exists, but is not a directory.\n",
97                                  lists_dir);
98                         free(lists_dir);
99                         return -1;
100                 }
101                 err = file_mkdir_hier(lists_dir, 0755);
102                 if (err) {
103                         free(lists_dir);
104                         return -1;
105                 }
106         }
107
108         failures = 0;
109
110         sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir);
111         if (mkdtemp(tmp) == NULL) {
112                 opkg_perror(ERROR, "Failed to make temp dir %s", conf->tmp_dir);
113                 return -1;
114         }
115
116         for (iter = void_list_first(&conf->pkg_src_list); iter;
117              iter = void_list_next(&conf->pkg_src_list, iter)) {
118                 char *url, *list_file_name;
119
120                 src = (pkg_src_t *) iter->data;
121
122                 if (src->extra_data && strcmp(src->extra_data, "__dummy__ "))
123                         continue;
124
125                 if (src->extra_data)    /* debian style? */
126                         sprintf_alloc(&url, "%s/%s/%s", src->value,
127                                       src->extra_data,
128                                       src->gzip ? "Packages.gz" : "Packages");
129                 else
130                         sprintf_alloc(&url, "%s/%s", src->value,
131                                       src->gzip ? "Packages.gz" : "Packages");
132
133                 sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
134                 pkglist_dl_error = 0;
135                 if (opkg_download(url, list_file_name, NULL, NULL, 0)) {
136                         failures++;
137                         pkglist_dl_error = 1;
138                         opkg_msg(NOTICE,
139                                  "*** Failed to download the package list from %s\n\n",
140                                  url);
141                 } else {
142                         opkg_msg(NOTICE,
143                                  "Updated list of available packages in %s\n",
144                                  list_file_name);
145                 }
146                 free(url);
147 #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) || defined(HAVE_USIGN)
148                 if (pkglist_dl_error == 0 && conf->check_signature) {
149                         /* download detached signitures to verify the package lists */
150                         /* get the url for the sig file */
151                         if (src->extra_data)    /* debian style? */
152                                 sprintf_alloc(&url, "%s/%s/%s", src->value,
153                                               src->extra_data, "Packages.sig");
154                         else
155                                 sprintf_alloc(&url, "%s/%s", src->value,
156                                               "Packages.sig");
157
158                         /* create temporary file for it */
159                         char *tmp_file_name;
160
161                         /* Put the signature in the right place */
162                         sprintf_alloc(&tmp_file_name, "%s/%s.sig", lists_dir,
163                                       src->name);
164
165                         err = opkg_download(url, tmp_file_name, NULL, NULL, 0);
166                         if (err) {
167                                 failures++;
168                                 opkg_msg(NOTICE,
169                                          "Signature file download failed.\n");
170                         } else {
171                                 err =
172                                     opkg_verify_file(list_file_name,
173                                                      tmp_file_name);
174                                 if (err == 0)
175                                         opkg_msg(NOTICE,
176                                                  "Signature check passed.\n");
177                                 else
178                                         opkg_msg(NOTICE,
179                                                  "Signature check failed.\n");
180                         }
181                         if (err && !conf->force_signature) {
182                                 /* The signature was wrong so delete it */
183                                 opkg_msg(NOTICE,
184                                          "Remove wrong Signature file.\n");
185                                 unlink(tmp_file_name);
186                                 unlink(list_file_name);
187                         }
188                         /* We shouldn't unlink the signature ! */
189                         // unlink (tmp_file_name);
190                         free(tmp_file_name);
191                         free(url);
192                 }
193 #else
194                 // Do nothing
195 #endif
196                 free(list_file_name);
197         }
198         rmdir(tmp);
199         free(tmp);
200         free(lists_dir);
201
202         return failures;
203 }
204
205 struct opkg_intercept {
206         char *oldpath;
207         char *statedir;
208 };
209
210 typedef struct opkg_intercept *opkg_intercept_t;
211
212 static opkg_intercept_t opkg_prep_intercepts(void)
213 {
214         opkg_intercept_t ctx;
215         char *newpath;
216
217         ctx = xcalloc(1, sizeof(*ctx));
218         ctx->oldpath = xstrdup(getenv("PATH"));
219         sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
220         sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX",
221                       conf->tmp_dir);
222
223         if (mkdtemp(ctx->statedir) == NULL) {
224                 opkg_perror(ERROR, "Failed to make temp dir %s", ctx->statedir);
225                 free(ctx->oldpath);
226                 free(ctx->statedir);
227                 free(newpath);
228                 free(ctx);
229                 return NULL;
230         }
231
232         setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
233         setenv("PATH", newpath, 1);
234         free(newpath);
235
236         return ctx;
237 }
238
239 static int opkg_finalize_intercepts(opkg_intercept_t ctx)
240 {
241         DIR *dir;
242         int err = 0;
243
244         setenv("PATH", ctx->oldpath, 1);
245         free(ctx->oldpath);
246
247         dir = opendir(ctx->statedir);
248         if (dir) {
249                 struct dirent *de;
250                 while (de = readdir(dir), de != NULL) {
251                         char *path;
252
253                         if (de->d_name[0] == '.')
254                                 continue;
255
256                         sprintf_alloc(&path, "%s/%s", ctx->statedir,
257                                       de->d_name);
258                         if (access(path, X_OK) == 0) {
259                                 const char *argv[] = { "sh", "-c", path, NULL };
260                                 xsystem(argv);
261                         }
262                         free(path);
263                 }
264                 closedir(dir);
265         } else
266                 opkg_perror(ERROR, "Failed to open dir %s", ctx->statedir);
267
268         rm_r(ctx->statedir);
269         free(ctx->statedir);
270         free(ctx);
271
272         return err;
273 }
274
275 /* For package pkg do the following: If it is already visited, return. If not,
276    add it in visited list and recurse to its deps. Finally, add it to ordered
277    list.
278    pkg_vec all contains all available packages in repos.
279    pkg_vec visited contains packages already visited by this function, and is
280    used to end recursion and avoid an infinite loop on graph cycles.
281    pkg_vec ordered will finally contain the ordered set of packages.
282 */
283 static int
284 opkg_recurse_pkgs_in_order(pkg_t * pkg, pkg_vec_t * all,
285                            pkg_vec_t * visited, pkg_vec_t * ordered)
286 {
287         int j, k, l, m;
288         pkg_t *dep;
289         compound_depend_t *compound_depend;
290         depend_t **possible_satisfiers;
291         abstract_pkg_t *abpkg;
292         abstract_pkg_t **dependents;
293
294         /* If it's just an available package, that is, not installed and not even
295            unpacked, skip it */
296         /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED
297            would do here. However, if there is an intermediate node (pkg) that is
298            configured and installed between two unpacked packages, the latter
299            won't be properly reordered, unless all installed/unpacked pkgs are
300            checked */
301         if (pkg->state_status == SS_NOT_INSTALLED)
302                 return 0;
303
304         /* If the  package has already been visited (by this function), skip it */
305         for (j = 0; j < visited->len; j++)
306                 if (!strcmp(visited->pkgs[j]->name, pkg->name)) {
307                         opkg_msg(DEBUG, "pkg %s already visited, skipping.\n",
308                                  pkg->name);
309                         return 0;
310                 }
311
312         pkg_vec_insert(visited, pkg);
313
314         opkg_msg(DEBUG, "pkg %s.\n", pkg->name);
315
316         /* Iterate over all the dependencies of pkg. For each one, find a package
317            that is either installed or unpacked and satisfies this dependency.
318            (there should only be one such package per dependency installed or
319            unpacked). Then recurse to the dependency package */
320         for (compound_depend = pkg_get_ptr(pkg, PKG_DEPENDS); compound_depend && compound_depend->type; compound_depend++) {
321                 possible_satisfiers = compound_depend->possibilities;
322                 for (k = 0; k < compound_depend->possibility_count; k++) {
323                         abpkg = possible_satisfiers[k]->pkg;
324                         dependents = abpkg->provided_by->pkgs;
325                         l = 0;
326                         if (dependents != NULL)
327                                 while (l < abpkg->provided_by->len
328                                        && dependents[l] != NULL) {
329                                         opkg_msg(DEBUG,
330                                                  "Descending on pkg %s.\n",
331                                                  dependents[l]->name);
332
333                                         /* find whether dependent l is installed or unpacked,
334                                          * and then find which package in the list satisfies it */
335                                         for (m = 0; m < all->len; m++) {
336                                                 dep = all->pkgs[m];
337                                                 if (dep->state_status !=
338                                                     SS_NOT_INSTALLED)
339                                                         if (!strcmp
340                                                             (dep->name,
341                                                              dependents[l]->
342                                                              name)) {
343                                                                 opkg_recurse_pkgs_in_order
344                                                                     (dep, all,
345                                                                      visited,
346                                                                      ordered);
347                                                                 /* Stop the outer loop */
348                                                                 l = abpkg->
349                                                                     provided_by->
350                                                                     len;
351                                                                 /* break from the inner loop */
352                                                                 break;
353                                                         }
354                                         }
355                                         l++;
356                                 }
357                 }
358         }
359
360         /* When all recursions from this node down, are over, and all
361            dependencies have been added in proper order in the ordered array, add
362            also the package pkg to ordered array */
363         pkg_vec_insert(ordered, pkg);
364
365         return 0;
366
367 }
368
369 static int opkg_configure_packages(char *pkg_name)
370 {
371         pkg_vec_t *all, *ordered, *visited;
372         int i;
373         pkg_t *pkg;
374         opkg_intercept_t ic;
375         int r, err = 0;
376
377         opkg_msg(INFO, "Configuring unpacked packages.\n");
378
379         all = pkg_vec_alloc();
380
381         pkg_hash_fetch_available(all);
382
383         /* Reorder pkgs in order to be configured according to the Depends: tag
384            order */
385         opkg_msg(INFO, "Reordering packages before configuring them...\n");
386         ordered = pkg_vec_alloc();
387         visited = pkg_vec_alloc();
388         for (i = 0; i < all->len; i++) {
389                 pkg = all->pkgs[i];
390                 opkg_recurse_pkgs_in_order(pkg, all, visited, ordered);
391         }
392
393         ic = opkg_prep_intercepts();
394         if (ic == NULL) {
395                 err = -1;
396                 goto error;
397         }
398
399         for (i = 0; i < ordered->len; i++) {
400                 pkg = ordered->pkgs[i];
401
402                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
403                         continue;
404
405                 if (pkg->state_status == SS_UNPACKED) {
406                         opkg_msg(NOTICE, "Configuring %s.\n", pkg->name);
407                         r = opkg_configure(pkg);
408                         if (r == 0) {
409                                 pkg->state_status = SS_INSTALLED;
410                                 pkg->parent->state_status = SS_INSTALLED;
411                                 pkg->state_flag &= ~SF_PREFER;
412                                 opkg_state_changed++;
413                         } else {
414                                 err = -1;
415                         }
416                 }
417         }
418
419         if (opkg_finalize_intercepts(ic))
420                 err = -1;
421
422 error:
423         pkg_vec_free(all);
424         pkg_vec_free(ordered);
425         pkg_vec_free(visited);
426
427         return err;
428 }
429
430 static int opkg_remove_cmd(int argc, char **argv);
431
432 static int opkg_install_cmd(int argc, char **argv)
433 {
434         int i;
435         char *arg;
436         int err = 0;
437
438         signal(SIGINT, sigint_handler);
439
440         /*
441          * Now scan through package names and install
442          */
443         for (i = 0; i < argc; i++) {
444                 arg = argv[i];
445
446                 opkg_msg(DEBUG2, "%s\n", arg);
447                 if (opkg_prepare_url_for_install(arg, &argv[i]))
448                         return -1;
449         }
450
451         pkg_hash_load_package_details();
452         pkg_hash_load_status_files();
453
454         if (conf->force_reinstall) {
455                 int saved_force_depends = conf->force_depends;
456                 conf->force_depends = 1;
457                 (void)opkg_remove_cmd(argc, argv);
458                 conf->force_depends = saved_force_depends;
459                 conf->force_reinstall = 0;
460         }
461
462         pkg_info_preinstall_check();
463
464         for (i = 0; i < argc; i++) {
465                 arg = argv[i];
466                 if (opkg_install_by_name(arg)) {
467                         opkg_msg(ERROR, "Cannot install package %s.\n", arg);
468                         err = -1;
469                 }
470         }
471
472         if (opkg_configure_packages(NULL))
473                 err = -1;
474
475         write_status_files_if_changed();
476
477         return err;
478 }
479
480 static int opkg_upgrade_cmd(int argc, char **argv)
481 {
482         int i;
483         pkg_t *pkg;
484         int err = 0;
485
486         signal(SIGINT, sigint_handler);
487
488         if (argc) {
489                 for (i = 0; i < argc; i++) {
490                         char *arg = argv[i];
491
492                         if (opkg_prepare_url_for_install(arg, &arg))
493                                 return -1;
494                 }
495                 pkg_info_preinstall_check();
496
497                 for (i = 0; i < argc; i++) {
498                         char *arg = argv[i];
499                         if (conf->restrict_to_default_dest) {
500                                 pkg =
501                                     pkg_hash_fetch_installed_by_name_dest(argv
502                                                                           [i],
503                                                                           conf->
504                                                                           default_dest);
505                                 if (pkg == NULL) {
506                                         opkg_msg(NOTICE,
507                                                  "Package %s not installed in %s.\n",
508                                                  argv[i],
509                                                  conf->default_dest->name);
510                                         continue;
511                                 }
512                         } else {
513                                 pkg = pkg_hash_fetch_installed_by_name(argv[i]);
514                         }
515                         if (pkg) {
516                                 if (opkg_upgrade_pkg(pkg))
517                                         err = -1;
518                         } else {
519                                 if (opkg_install_by_name(arg))
520                                         err = -1;
521                         }
522                 }
523         }
524
525         if (opkg_configure_packages(NULL))
526                 err = -1;
527
528         write_status_files_if_changed();
529
530         return err;
531 }
532
533 static int opkg_download_cmd(int argc, char **argv)
534 {
535         int i, err = 0;
536         char *arg;
537         pkg_t *pkg;
538
539         pkg_info_preinstall_check();
540         for (i = 0; i < argc; i++) {
541                 arg = argv[i];
542
543                 pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg);
544                 if (pkg == NULL) {
545                         opkg_msg(ERROR, "Cannot find package %s.\n", arg);
546                         continue;
547                 }
548
549                 if (opkg_download_pkg(pkg, "."))
550                         err = -1;
551
552                 if (err) {
553                         opkg_msg(ERROR, "Failed to download %s.\n", pkg->name);
554                 } else {
555                         opkg_msg(NOTICE, "Downloaded %s as %s.\n",
556                                  pkg->name, pkg_get_string(pkg, PKG_LOCAL_FILENAME));
557                 }
558         }
559
560         return err;
561 }
562
563 static int opkg_list_find_cmd(int argc, char **argv, int use_desc)
564 {
565         int i;
566         pkg_vec_t *available;
567         pkg_t *pkg;
568         char *pkg_name = NULL;
569         char *description;
570
571         if (argc > 0) {
572                 pkg_name = argv[0];
573         }
574         available = pkg_vec_alloc();
575         pkg_hash_fetch_available(available);
576         pkg_vec_sort(available, pkg_compare_names);
577         for (i = 0; i < available->len; i++) {
578                 pkg = available->pkgs[i];
579                 description = use_desc ? pkg_get_string(pkg, PKG_DESCRIPTION) : NULL;
580                 /* if we have package name or pattern and pkg does not match, then skip it */
581                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase) &&
582                     (!use_desc || !description
583                      || fnmatch(pkg_name, description, conf->nocase)))
584                         continue;
585                 print_pkg(pkg);
586         }
587         pkg_vec_free(available);
588
589         return 0;
590 }
591
592 static int opkg_list_cmd(int argc, char **argv)
593 {
594         return opkg_list_find_cmd(argc, argv, 0);
595 }
596
597 static int opkg_find_cmd(int argc, char **argv)
598 {
599         return opkg_list_find_cmd(argc, argv, 1);
600 }
601
602 static int opkg_list_installed_cmd(int argc, char **argv)
603 {
604         int i;
605         pkg_vec_t *available;
606         pkg_t *pkg;
607         char *pkg_name = NULL;
608
609         if (argc > 0) {
610                 pkg_name = argv[0];
611         }
612         available = pkg_vec_alloc();
613         pkg_hash_fetch_all_installed(available);
614         pkg_vec_sort(available, pkg_compare_names);
615         for (i = 0; i < available->len; i++) {
616                 pkg = available->pkgs[i];
617                 /* if we have package name or pattern and pkg does not match, then skip it */
618                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
619                         continue;
620                 print_pkg(pkg);
621         }
622
623         pkg_vec_free(available);
624
625         return 0;
626 }
627
628 static int opkg_list_changed_conffiles_cmd(int argc, char **argv)
629 {
630         int i;
631         pkg_vec_t *available;
632         pkg_t *pkg;
633         char *pkg_name = NULL;
634         conffile_list_elt_t *iter;
635         conffile_list_t *cl;
636         conffile_t *cf;
637
638         if (argc > 0) {
639                 pkg_name = argv[0];
640         }
641         available = pkg_vec_alloc();
642         pkg_hash_fetch_all_installed(available);
643         pkg_vec_sort(available, pkg_compare_names);
644         for (i = 0; i < available->len; i++) {
645                 pkg = available->pkgs[i];
646                 cl = pkg_get_ptr(pkg, PKG_CONFFILES);
647                 /* if we have package name or pattern and pkg does not match, then skip it */
648                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
649                         continue;
650                 if (!cl || nv_pair_list_empty(cl))
651                         continue;
652                 for (iter = nv_pair_list_first(cl); iter;
653                      iter = nv_pair_list_next(cl, iter)) {
654                         cf = (conffile_t *) iter->data;
655                         if (cf->name && cf->value
656                             && conffile_has_been_modified(cf))
657                                 printf("%s\n", cf->name);
658                 }
659         }
660         pkg_vec_free(available);
661         return 0;
662 }
663
664 static int opkg_list_upgradable_cmd(int argc, char **argv)
665 {
666         struct active_list *head = prepare_upgrade_list();
667         struct active_list *node = NULL;
668         pkg_t *_old_pkg, *_new_pkg;
669         char *old_v, *new_v;
670         for (node = active_list_next(head, head); node;
671              node = active_list_next(head, node)) {
672                 _old_pkg = node->pkg;
673                 _new_pkg =
674                     pkg_hash_fetch_best_installation_candidate_by_name
675                     (_old_pkg->name);
676                 if (_new_pkg == NULL)
677                         continue;
678                 old_v = pkg_version_str_alloc(_old_pkg);
679                 new_v = pkg_version_str_alloc(_new_pkg);
680                 printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
681                 free(old_v);
682                 free(new_v);
683         }
684         active_list_head_delete(head);
685         return 0;
686 }
687
688 static int opkg_info_status_cmd(int argc, char **argv, int installed_only)
689 {
690         int i;
691         pkg_vec_t *available;
692         pkg_t *pkg;
693         char *pkg_name = NULL;
694         conffile_list_t *cl;
695
696         if (argc > 0) {
697                 pkg_name = argv[0];
698         }
699
700         available = pkg_vec_alloc();
701         if (installed_only)
702                 pkg_hash_fetch_all_installed(available);
703         else
704                 pkg_hash_fetch_available(available);
705
706         for (i = 0; i < available->len; i++) {
707                 pkg = available->pkgs[i];
708                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase)) {
709                         continue;
710                 }
711
712                 pkg_formatted_info(stdout, pkg);
713
714                 cl = pkg_get_ptr(pkg, PKG_CONFFILES);
715
716                 if (conf->verbosity >= NOTICE && cl) {
717                         conffile_list_elt_t *iter;
718                         for (iter = nv_pair_list_first(cl); iter;
719                              iter = nv_pair_list_next(cl, iter)) {
720                                 conffile_t *cf = (conffile_t *) iter->data;
721                                 int modified = conffile_has_been_modified(cf);
722                                 if (cf->value)
723                                         opkg_msg(INFO,
724                                                  "conffile=%s md5sum=%s modified=%d.\n",
725                                                  cf->name, cf->value, modified);
726                         }
727                 }
728         }
729         pkg_vec_free(available);
730
731         return 0;
732 }
733
734 static int opkg_info_cmd(int argc, char **argv)
735 {
736         return opkg_info_status_cmd(argc, argv, 0);
737 }
738
739 static int opkg_status_cmd(int argc, char **argv)
740 {
741         return opkg_info_status_cmd(argc, argv, 1);
742 }
743
744 static int opkg_configure_cmd(int argc, char **argv)
745 {
746         int err;
747         char *pkg_name = NULL;
748
749         if (argc > 0)
750                 pkg_name = argv[0];
751
752         err = opkg_configure_packages(pkg_name);
753
754         write_status_files_if_changed();
755
756         return err;
757 }
758
759 static int opkg_remove_cmd(int argc, char **argv)
760 {
761         int i, a, done, err = 0;
762         pkg_t *pkg;
763         pkg_t *pkg_to_remove;
764         pkg_vec_t *available;
765
766         done = 0;
767
768         signal(SIGINT, sigint_handler);
769
770         pkg_info_preinstall_check();
771
772         available = pkg_vec_alloc();
773         pkg_hash_fetch_all_installed(available);
774
775         for (i = 0; i < argc; i++) {
776                 for (a = 0; a < available->len; a++) {
777                         pkg = available->pkgs[a];
778                         if (fnmatch(argv[i], pkg->name, conf->nocase)) {
779                                 continue;
780                         }
781                         if (conf->restrict_to_default_dest) {
782                                 pkg_to_remove =
783                                     pkg_hash_fetch_installed_by_name_dest(pkg->
784                                                                           name,
785                                                                           conf->
786                                                                           default_dest);
787                         } else {
788                                 pkg_to_remove =
789                                     pkg_hash_fetch_installed_by_name(pkg->name);
790                         }
791
792                         if (pkg_to_remove == NULL) {
793                                 opkg_msg(ERROR,
794                                          "Package %s is not installed.\n",
795                                          pkg->name);
796                                 continue;
797                         }
798                         if (pkg->state_status == SS_NOT_INSTALLED) {
799                                 opkg_msg(ERROR, "Package %s not installed.\n",
800                                          pkg->name);
801                                 continue;
802                         }
803
804                         if (opkg_remove_pkg(pkg_to_remove, 0))
805                                 err = -1;
806                         else
807                                 done = 1;
808                 }
809         }
810
811         pkg_vec_free(available);
812
813         if (done == 0)
814                 opkg_msg(NOTICE, "No packages removed.\n");
815
816         write_status_files_if_changed();
817         return err;
818 }
819
820 static int opkg_flag_cmd(int argc, char **argv)
821 {
822         int i;
823         pkg_t *pkg;
824         const char *flags = argv[0];
825
826         signal(SIGINT, sigint_handler);
827
828         for (i = 1; i < argc; i++) {
829                 if (conf->restrict_to_default_dest) {
830                         pkg = pkg_hash_fetch_installed_by_name_dest(argv[i],
831                                                                     conf->
832                                                                     default_dest);
833                 } else {
834                         pkg = pkg_hash_fetch_installed_by_name(argv[i]);
835                 }
836
837                 if (pkg == NULL) {
838                         opkg_msg(ERROR, "Package %s is not installed.\n",
839                                  argv[i]);
840                         continue;
841                 }
842                 if ((strcmp(flags, "hold") == 0)
843                     || (strcmp(flags, "noprune") == 0)
844                     || (strcmp(flags, "user") == 0)
845                     || (strcmp(flags, "ok") == 0)) {
846                         pkg->state_flag = pkg_state_flag_from_str(flags);
847                 }
848
849                 /*
850                  * Useful if a package is installed in an offline_root, and
851                  * should be configured by opkg-cl configure at a later date.
852                  */
853                 if ((strcmp(flags, "installed") == 0)
854                     || (strcmp(flags, "unpacked") == 0)) {
855                         pkg->state_status = pkg_state_status_from_str(flags);
856                 }
857
858                 opkg_state_changed++;
859                 opkg_msg(NOTICE, "Setting flags for package %s to %s.\n",
860                          pkg->name, flags);
861         }
862
863         write_status_files_if_changed();
864         return 0;
865 }
866
867 static int opkg_files_cmd(int argc, char **argv)
868 {
869         pkg_t *pkg;
870         str_list_t *files;
871         str_list_elt_t *iter;
872         char *pkg_version;
873
874         if (argc < 1) {
875                 return -1;
876         }
877
878         pkg = pkg_hash_fetch_installed_by_name(argv[0]);
879         if (pkg == NULL) {
880                 opkg_msg(ERROR, "Package %s not installed.\n", argv[0]);
881                 return 0;
882         }
883
884         files = pkg_get_installed_files(pkg);
885         pkg_version = pkg_version_str_alloc(pkg);
886
887         printf
888             ("Package %s (%s) is installed on %s and has the following files:\n",
889              pkg->name, pkg_version, pkg->dest->name);
890
891         for (iter = str_list_first(files); iter;
892              iter = str_list_next(files, iter))
893                 printf("%s\n", (char *)iter->data);
894
895         free(pkg_version);
896         pkg_free_installed_files(pkg);
897
898         return 0;
899 }
900
901 static int opkg_depends_cmd(int argc, char **argv)
902 {
903         int i, j, k;
904         pkg_vec_t *available_pkgs;
905         compound_depend_t *cdep;
906         pkg_t *pkg;
907         char *str;
908
909         pkg_info_preinstall_check();
910
911         available_pkgs = pkg_vec_alloc();
912         if (conf->query_all)
913                 pkg_hash_fetch_available(available_pkgs);
914         else
915                 pkg_hash_fetch_all_installed(available_pkgs);
916
917         for (i = 0; i < argc; i++) {
918                 for (j = 0; j < available_pkgs->len; j++) {
919                         pkg = available_pkgs->pkgs[j];
920
921                         if (fnmatch(argv[i], pkg->name, conf->nocase) != 0)
922                                 continue;
923
924                         opkg_msg(NOTICE, "%s depends on:\n", pkg->name);
925
926                         for (k = 0, cdep = pkg_get_ptr(pkg, PKG_DEPENDS); cdep && cdep->type; k++, cdep++) {
927                                 if (cdep->type != DEPEND)
928                                         continue;
929
930                                 str = pkg_depend_str(pkg, k);
931                                 opkg_msg(NOTICE, "\t%s\n", str);
932                                 free(str);
933                         }
934
935                 }
936         }
937
938         pkg_vec_free(available_pkgs);
939         return 0;
940 }
941
942 static int pkg_mark_provides(pkg_t * pkg)
943 {
944         abstract_pkg_t **provider = pkg_get_ptr(pkg, PKG_PROVIDES);
945
946         pkg->parent->state_flag |= SF_MARKED;
947
948         while (provider && *provider) {
949                 (*provider)->state_flag |= SF_MARKED;
950                 provider++;
951         }
952
953         return 0;
954 }
955
956 enum what_field_type {
957         WHATDEPENDS,
958         WHATCONFLICTS,
959         WHATPROVIDES,
960         WHATREPLACES,
961         WHATRECOMMENDS,
962         WHATSUGGESTS
963 };
964
965 static int
966 opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive,
967                                 int argc, char **argv)
968 {
969         depend_t *possibility;
970         compound_depend_t *cdep, *deps;
971         pkg_vec_t *available_pkgs;
972         pkg_t *pkg;
973         int i, j, l;
974         int changed;
975         const char *rel_str = NULL;
976         char *ver;
977
978         switch (what_field_type) {
979         case DEPEND:
980                 rel_str = "depends on";
981                 break;
982         case CONFLICTS:
983                 rel_str = "conflicts with";
984                 break;
985         case SUGGEST:
986                 rel_str = "suggests";
987                 break;
988         case RECOMMEND:
989                 rel_str = "recommends";
990                 break;
991         default:
992                 return -1;
993         }
994
995         available_pkgs = pkg_vec_alloc();
996
997         if (conf->query_all)
998                 pkg_hash_fetch_available(available_pkgs);
999         else
1000                 pkg_hash_fetch_all_installed(available_pkgs);
1001
1002         /* mark the root set */
1003         pkg_vec_clear_marks(available_pkgs);
1004         opkg_msg(NOTICE, "Root set:\n");
1005         for (i = 0; i < argc; i++)
1006                 pkg_vec_mark_if_matches(available_pkgs, argv[i]);
1007
1008         for (i = 0; i < available_pkgs->len; i++) {
1009                 pkg = available_pkgs->pkgs[i];
1010                 if (pkg->state_flag & SF_MARKED) {
1011                         /* mark the parent (abstract) package */
1012                         pkg_mark_provides(pkg);
1013                         opkg_msg(NOTICE, "  %s\n", pkg->name);
1014                 }
1015         }
1016
1017         opkg_msg(NOTICE, "What %s root set\n", rel_str);
1018         do {
1019                 changed = 0;
1020
1021                 for (j = 0; j < available_pkgs->len; j++) {
1022
1023                         pkg = available_pkgs->pkgs[j];
1024                         /*
1025                         count = ((what_field_type == CONFLICTS)
1026                                  ? pkg->conflicts_count
1027                                  : pkg->pre_depends_count +
1028                                  pkg->depends_count +
1029                                  pkg->recommends_count + pkg->suggests_count);
1030                                  */
1031
1032                         /* skip this package if it is already marked */
1033                         if (pkg->parent->state_flag & SF_MARKED)
1034                                 continue;
1035
1036                         deps = pkg_get_ptr(pkg, (what_field_type == CONFLICTS) ? PKG_CONFLICTS : PKG_DEPENDS);
1037
1038                         for (cdep = deps; cdep->type; cdep++) {
1039                                 if (what_field_type != cdep->type)
1040                                         continue;
1041
1042                                 for (l = 0; l < cdep->possibility_count; l++) {
1043                                         possibility = cdep->possibilities[l];
1044
1045                                         if ((possibility->pkg->state_flag
1046                                              & SF_MARKED)
1047                                             != SF_MARKED)
1048                                                 continue;
1049
1050                                         /* mark the depending package so we
1051                                          * won't visit it again */
1052                                         pkg->state_flag |= SF_MARKED;
1053                                         pkg_mark_provides(pkg);
1054                                         changed++;
1055
1056                                         ver = pkg_version_str_alloc(pkg);
1057                                         opkg_msg(NOTICE, "\t%s %s\t%s %s",
1058                                                  pkg->name,
1059                                                  ver,
1060                                                  rel_str,
1061                                                  possibility->pkg->name);
1062                                         free(ver);
1063                                         if (possibility->version) {
1064                                                 opkg_msg(NOTICE, " (%s%s)",
1065                                                          constraint_to_str
1066                                                          (possibility->
1067                                                           constraint),
1068                                                          possibility->version);
1069                                         }
1070                                         if (!pkg_dependence_satisfiable
1071                                             (possibility))
1072                                                 opkg_msg(NOTICE,
1073                                                          " unsatisfiable");
1074                                         opkg_message(NOTICE, "\n");
1075                                         goto next_package;
1076                                 }
1077                         }
1078 next_package:
1079                         ;
1080                 }
1081         } while (changed && recursive);
1082
1083         pkg_vec_free(available_pkgs);
1084
1085         return 0;
1086 }
1087
1088 static int opkg_whatdepends_recursively_cmd(int argc, char **argv)
1089 {
1090         return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv);
1091 }
1092
1093 static int opkg_whatdepends_cmd(int argc, char **argv)
1094 {
1095         return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv);
1096 }
1097
1098 static int opkg_whatsuggests_cmd(int argc, char **argv)
1099 {
1100         return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv);
1101 }
1102
1103 static int opkg_whatrecommends_cmd(int argc, char **argv)
1104 {
1105         return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv);
1106 }
1107
1108 static int opkg_whatconflicts_cmd(int argc, char **argv)
1109 {
1110         return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv);
1111 }
1112
1113 static int
1114 opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc,
1115                                 char **argv)
1116 {
1117         abstract_pkg_t *apkg, **abpkgs;
1118
1119         if (argc > 0) {
1120                 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1121                 const char *rel_str =
1122                     (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1123                 int i;
1124
1125                 pkg_info_preinstall_check();
1126
1127                 if (conf->query_all)
1128                         pkg_hash_fetch_available(available_pkgs);
1129                 else
1130                         pkg_hash_fetch_all_installed(available_pkgs);
1131                 for (i = 0; i < argc; i++) {
1132                         const char *target = argv[i];
1133                         int j;
1134
1135                         opkg_msg(NOTICE, "What %s %s\n", rel_str, target);
1136                         for (j = 0; j < available_pkgs->len; j++) {
1137                                 pkg_t *pkg = available_pkgs->pkgs[j];
1138                                 abpkgs = pkg_get_ptr(pkg, (what_field_type == WHATPROVIDES) ? PKG_PROVIDES : PKG_REPLACES);
1139
1140                                 while (abpkgs && *abpkgs) {
1141                                         apkg = *abpkgs;
1142
1143                                         if (fnmatch(target, apkg->name, conf->nocase))
1144                                                 continue;
1145
1146                                         opkg_msg(NOTICE, "    %s", pkg->name);
1147
1148                                         if ((conf->nocase ? strcasecmp(target, apkg->name)
1149                                             : strcmp(target, apkg->name)))
1150                                                 opkg_msg(NOTICE, "\t%s %s\n", rel_str, apkg->name);
1151
1152                                         opkg_message(NOTICE, "\n");
1153                                         abpkgs++;
1154                                 }
1155                         }
1156                 }
1157                 pkg_vec_free(available_pkgs);
1158         }
1159         return 0;
1160 }
1161
1162 static int opkg_whatprovides_cmd(int argc, char **argv)
1163 {
1164         return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv);
1165 }
1166
1167 static int opkg_whatreplaces_cmd(int argc, char **argv)
1168 {
1169         return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv);
1170 }
1171
1172 static int opkg_search_cmd(int argc, char **argv)
1173 {
1174         int i;
1175
1176         pkg_vec_t *installed;
1177         pkg_t *pkg;
1178         str_list_t *installed_files;
1179         str_list_elt_t *iter;
1180         char *installed_file;
1181
1182         if (argc < 1) {
1183                 return -1;
1184         }
1185
1186         installed = pkg_vec_alloc();
1187         pkg_hash_fetch_all_installed(installed);
1188         pkg_vec_sort(installed, pkg_compare_names);
1189
1190         for (i = 0; i < installed->len; i++) {
1191                 pkg = installed->pkgs[i];
1192
1193                 installed_files = pkg_get_installed_files(pkg);
1194
1195                 for (iter = str_list_first(installed_files); iter;
1196                      iter = str_list_next(installed_files, iter)) {
1197                         installed_file = (char *)iter->data;
1198                         if (fnmatch(argv[0], installed_file, conf->nocase) == 0)
1199                                 print_pkg(pkg);
1200                 }
1201
1202                 pkg_free_installed_files(pkg);
1203         }
1204
1205         pkg_vec_free(installed);
1206
1207         return 0;
1208 }
1209
1210 static int opkg_compare_versions_cmd(int argc, char **argv)
1211 {
1212         if (argc == 3) {
1213                 /* this is a bit gross */
1214                 struct pkg p1, p2;
1215                 parse_version(&p1, argv[0]);
1216                 parse_version(&p2, argv[2]);
1217                 return pkg_version_satisfied(&p1, &p2, argv[1]);
1218         } else {
1219                 opkg_msg(ERROR,
1220                          "opkg compare_versions <v1> <op> <v2>\n"
1221                          "<op> is one of <= >= << >> =\n");
1222                 return -1;
1223         }
1224 }
1225
1226 static int opkg_print_architecture_cmd(int argc, char **argv)
1227 {
1228         nv_pair_list_elt_t *l;
1229
1230         list_for_each_entry(l, &conf->arch_list.head, node) {
1231                 nv_pair_t *nv = (nv_pair_t *) l->data;
1232                 printf("arch %s %s\n", nv->name, nv->value);
1233         }
1234         return 0;
1235 }
1236
1237 /* XXX: CLEANUP: The usage strings should be incorporated into this
1238    array for easier maintenance */
1239 static opkg_cmd_t cmds[] = {
1240         {"update", 0, (opkg_cmd_fun_t) opkg_update_cmd,
1241          PFM_DESCRIPTION | PFM_SOURCE},
1242         {"upgrade", 1, (opkg_cmd_fun_t) opkg_upgrade_cmd,
1243          PFM_DESCRIPTION | PFM_SOURCE},
1244         {"list", 0, (opkg_cmd_fun_t) opkg_list_cmd, PFM_SOURCE},
1245         {"list_installed", 0, (opkg_cmd_fun_t) opkg_list_installed_cmd,
1246          PFM_SOURCE},
1247         {"list-installed", 0, (opkg_cmd_fun_t) opkg_list_installed_cmd,
1248          PFM_SOURCE},
1249         {"list_upgradable", 0, (opkg_cmd_fun_t) opkg_list_upgradable_cmd,
1250          PFM_SOURCE},
1251         {"list-upgradable", 0, (opkg_cmd_fun_t) opkg_list_upgradable_cmd,
1252          PFM_SOURCE},
1253         {"list_changed_conffiles", 0,
1254          (opkg_cmd_fun_t) opkg_list_changed_conffiles_cmd, PFM_SOURCE},
1255         {"list-changed-conffiles", 0,
1256          (opkg_cmd_fun_t) opkg_list_changed_conffiles_cmd, PFM_SOURCE},
1257         {"info", 0, (opkg_cmd_fun_t) opkg_info_cmd, 0},
1258         {"flag", 1, (opkg_cmd_fun_t) opkg_flag_cmd,
1259          PFM_DESCRIPTION | PFM_SOURCE},
1260         {"status", 0, (opkg_cmd_fun_t) opkg_status_cmd,
1261          PFM_DESCRIPTION | PFM_SOURCE},
1262         {"install", 1, (opkg_cmd_fun_t) opkg_install_cmd,
1263          PFM_DESCRIPTION | PFM_SOURCE},
1264         {"remove", 1, (opkg_cmd_fun_t) opkg_remove_cmd,
1265          PFM_DESCRIPTION | PFM_SOURCE},
1266         {"configure", 0, (opkg_cmd_fun_t) opkg_configure_cmd,
1267          PFM_DESCRIPTION | PFM_SOURCE},
1268         {"files", 1, (opkg_cmd_fun_t) opkg_files_cmd,
1269          PFM_DESCRIPTION | PFM_SOURCE},
1270         {"search", 1, (opkg_cmd_fun_t) opkg_search_cmd,
1271          PFM_DESCRIPTION | PFM_SOURCE},
1272         {"find", 1, (opkg_cmd_fun_t) opkg_find_cmd, PFM_SOURCE},
1273         {"download", 1, (opkg_cmd_fun_t) opkg_download_cmd,
1274          PFM_DESCRIPTION | PFM_SOURCE},
1275         {"compare_versions", 1, (opkg_cmd_fun_t) opkg_compare_versions_cmd,
1276          PFM_DESCRIPTION | PFM_SOURCE},
1277         {"compare-versions", 1, (opkg_cmd_fun_t) opkg_compare_versions_cmd,
1278          PFM_DESCRIPTION | PFM_SOURCE},
1279         {"print-architecture", 0, (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1280          PFM_DESCRIPTION | PFM_SOURCE},
1281         {"print_architecture", 0, (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1282          PFM_DESCRIPTION | PFM_SOURCE},
1283         {"print-installation-architecture", 0,
1284          (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1285          PFM_DESCRIPTION | PFM_SOURCE},
1286         {"print_installation_architecture", 0,
1287          (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1288          PFM_DESCRIPTION | PFM_SOURCE},
1289         {"depends", 1, (opkg_cmd_fun_t) opkg_depends_cmd,
1290          PFM_DESCRIPTION | PFM_SOURCE},
1291         {"whatdepends", 1, (opkg_cmd_fun_t) opkg_whatdepends_cmd,
1292          PFM_DESCRIPTION | PFM_SOURCE},
1293         {"whatdependsrec", 1, (opkg_cmd_fun_t) opkg_whatdepends_recursively_cmd,
1294          PFM_DESCRIPTION | PFM_SOURCE},
1295         {"whatrecommends", 1, (opkg_cmd_fun_t) opkg_whatrecommends_cmd,
1296          PFM_DESCRIPTION | PFM_SOURCE},
1297         {"whatsuggests", 1, (opkg_cmd_fun_t) opkg_whatsuggests_cmd,
1298          PFM_DESCRIPTION | PFM_SOURCE},
1299         {"whatprovides", 1, (opkg_cmd_fun_t) opkg_whatprovides_cmd,
1300          PFM_DESCRIPTION | PFM_SOURCE},
1301         {"whatreplaces", 1, (opkg_cmd_fun_t) opkg_whatreplaces_cmd,
1302          PFM_DESCRIPTION | PFM_SOURCE},
1303         {"whatconflicts", 1, (opkg_cmd_fun_t) opkg_whatconflicts_cmd,
1304          PFM_DESCRIPTION | PFM_SOURCE},
1305 };
1306
1307 opkg_cmd_t *opkg_cmd_find(const char *name)
1308 {
1309         int i;
1310         opkg_cmd_t *cmd;
1311         int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
1312
1313         for (i = 0; i < num_cmds; i++) {
1314                 cmd = &cmds[i];
1315                 if (strcmp(name, cmd->name) == 0)
1316                         return cmd;
1317         }
1318
1319         return NULL;
1320 }
1321
1322 int opkg_cmd_exec(opkg_cmd_t * cmd, int argc, const char **argv)
1323 {
1324         return (cmd->fun) (argc, argv);
1325 }