pkg: convert most other struct members into dynamic blob buffer fields
[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         if (conf->force_reinstall) {
439                 int saved_force_depends = conf->force_depends;
440                 conf->force_depends = 1;
441                 (void)opkg_remove_cmd(argc, argv);
442                 conf->force_depends = saved_force_depends;
443                 conf->force_reinstall = 0;
444         }
445
446         signal(SIGINT, sigint_handler);
447
448         /*
449          * Now scan through package names and install
450          */
451         for (i = 0; i < argc; i++) {
452                 arg = argv[i];
453
454                 opkg_msg(DEBUG2, "%s\n", arg);
455                 if (opkg_prepare_url_for_install(arg, &argv[i]))
456                         return -1;
457         }
458         pkg_info_preinstall_check();
459
460         for (i = 0; i < argc; i++) {
461                 arg = argv[i];
462                 if (opkg_install_by_name(arg)) {
463                         opkg_msg(ERROR, "Cannot install package %s.\n", arg);
464                         err = -1;
465                 }
466         }
467
468         if (opkg_configure_packages(NULL))
469                 err = -1;
470
471         write_status_files_if_changed();
472
473         return err;
474 }
475
476 static int opkg_upgrade_cmd(int argc, char **argv)
477 {
478         int i;
479         pkg_t *pkg;
480         int err = 0;
481
482         signal(SIGINT, sigint_handler);
483
484         if (argc) {
485                 for (i = 0; i < argc; i++) {
486                         char *arg = argv[i];
487
488                         if (opkg_prepare_url_for_install(arg, &arg))
489                                 return -1;
490                 }
491                 pkg_info_preinstall_check();
492
493                 for (i = 0; i < argc; i++) {
494                         char *arg = argv[i];
495                         if (conf->restrict_to_default_dest) {
496                                 pkg =
497                                     pkg_hash_fetch_installed_by_name_dest(argv
498                                                                           [i],
499                                                                           conf->
500                                                                           default_dest);
501                                 if (pkg == NULL) {
502                                         opkg_msg(NOTICE,
503                                                  "Package %s not installed in %s.\n",
504                                                  argv[i],
505                                                  conf->default_dest->name);
506                                         continue;
507                                 }
508                         } else {
509                                 pkg = pkg_hash_fetch_installed_by_name(argv[i]);
510                         }
511                         if (pkg) {
512                                 if (opkg_upgrade_pkg(pkg))
513                                         err = -1;
514                         } else {
515                                 if (opkg_install_by_name(arg))
516                                         err = -1;
517                         }
518                 }
519         }
520
521         if (opkg_configure_packages(NULL))
522                 err = -1;
523
524         write_status_files_if_changed();
525
526         return err;
527 }
528
529 static int opkg_download_cmd(int argc, char **argv)
530 {
531         int i, err = 0;
532         char *arg;
533         pkg_t *pkg;
534
535         pkg_info_preinstall_check();
536         for (i = 0; i < argc; i++) {
537                 arg = argv[i];
538
539                 pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg);
540                 if (pkg == NULL) {
541                         opkg_msg(ERROR, "Cannot find package %s.\n", arg);
542                         continue;
543                 }
544
545                 if (opkg_download_pkg(pkg, "."))
546                         err = -1;
547
548                 if (err) {
549                         opkg_msg(ERROR, "Failed to download %s.\n", pkg->name);
550                 } else {
551                         opkg_msg(NOTICE, "Downloaded %s as %s.\n",
552                                  pkg->name, pkg_get_string(pkg, PKG_LOCAL_FILENAME));
553                 }
554         }
555
556         return err;
557 }
558
559 static int opkg_list_find_cmd(int argc, char **argv, int use_desc)
560 {
561         int i;
562         pkg_vec_t *available;
563         pkg_t *pkg;
564         char *pkg_name = NULL;
565         char *description;
566
567         if (argc > 0) {
568                 pkg_name = argv[0];
569         }
570         available = pkg_vec_alloc();
571         pkg_hash_fetch_available(available);
572         pkg_vec_sort(available, pkg_compare_names);
573         for (i = 0; i < available->len; i++) {
574                 pkg = available->pkgs[i];
575                 description = use_desc ? pkg_get_string(pkg, PKG_DESCRIPTION) : NULL;
576                 /* if we have package name or pattern and pkg does not match, then skip it */
577                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase) &&
578                     (!use_desc || !description
579                      || fnmatch(pkg_name, description, conf->nocase)))
580                         continue;
581                 print_pkg(pkg);
582         }
583         pkg_vec_free(available);
584
585         return 0;
586 }
587
588 static int opkg_list_cmd(int argc, char **argv)
589 {
590         return opkg_list_find_cmd(argc, argv, 0);
591 }
592
593 static int opkg_find_cmd(int argc, char **argv)
594 {
595         return opkg_list_find_cmd(argc, argv, 1);
596 }
597
598 static int opkg_list_installed_cmd(int argc, char **argv)
599 {
600         int i;
601         pkg_vec_t *available;
602         pkg_t *pkg;
603         char *pkg_name = NULL;
604
605         if (argc > 0) {
606                 pkg_name = argv[0];
607         }
608         available = pkg_vec_alloc();
609         pkg_hash_fetch_all_installed(available);
610         pkg_vec_sort(available, pkg_compare_names);
611         for (i = 0; i < available->len; i++) {
612                 pkg = available->pkgs[i];
613                 /* if we have package name or pattern and pkg does not match, then skip it */
614                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
615                         continue;
616                 print_pkg(pkg);
617         }
618
619         pkg_vec_free(available);
620
621         return 0;
622 }
623
624 static int opkg_list_changed_conffiles_cmd(int argc, char **argv)
625 {
626         int i;
627         pkg_vec_t *available;
628         pkg_t *pkg;
629         char *pkg_name = NULL;
630         conffile_list_elt_t *iter;
631         conffile_list_t *cl;
632         conffile_t *cf;
633
634         if (argc > 0) {
635                 pkg_name = argv[0];
636         }
637         available = pkg_vec_alloc();
638         pkg_hash_fetch_all_installed(available);
639         pkg_vec_sort(available, pkg_compare_names);
640         for (i = 0; i < available->len; i++) {
641                 pkg = available->pkgs[i];
642                 cl = pkg_get_ptr(pkg, PKG_CONFFILES);
643                 /* if we have package name or pattern and pkg does not match, then skip it */
644                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
645                         continue;
646                 if (!cl || nv_pair_list_empty(cl))
647                         continue;
648                 for (iter = nv_pair_list_first(cl); iter;
649                      iter = nv_pair_list_next(cl, iter)) {
650                         cf = (conffile_t *) iter->data;
651                         if (cf->name && cf->value
652                             && conffile_has_been_modified(cf))
653                                 printf("%s\n", cf->name);
654                 }
655         }
656         pkg_vec_free(available);
657         return 0;
658 }
659
660 static int opkg_list_upgradable_cmd(int argc, char **argv)
661 {
662         struct active_list *head = prepare_upgrade_list();
663         struct active_list *node = NULL;
664         pkg_t *_old_pkg, *_new_pkg;
665         char *old_v, *new_v;
666         for (node = active_list_next(head, head); node;
667              node = active_list_next(head, node)) {
668                 _old_pkg = list_entry(node, pkg_t, list);
669                 _new_pkg =
670                     pkg_hash_fetch_best_installation_candidate_by_name
671                     (_old_pkg->name);
672                 if (_new_pkg == NULL)
673                         continue;
674                 old_v = pkg_version_str_alloc(_old_pkg);
675                 new_v = pkg_version_str_alloc(_new_pkg);
676                 printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
677                 free(old_v);
678                 free(new_v);
679         }
680         active_list_head_delete(head);
681         return 0;
682 }
683
684 static int opkg_info_status_cmd(int argc, char **argv, int installed_only)
685 {
686         int i;
687         pkg_vec_t *available;
688         pkg_t *pkg;
689         char *pkg_name = NULL;
690         conffile_list_t *cl;
691
692         if (argc > 0) {
693                 pkg_name = argv[0];
694         }
695
696         available = pkg_vec_alloc();
697         if (installed_only)
698                 pkg_hash_fetch_all_installed(available);
699         else
700                 pkg_hash_fetch_available(available);
701
702         for (i = 0; i < available->len; i++) {
703                 pkg = available->pkgs[i];
704                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase)) {
705                         continue;
706                 }
707
708                 pkg_formatted_info(stdout, pkg);
709
710                 cl = pkg_get_ptr(pkg, PKG_CONFFILES);
711
712                 if (conf->verbosity >= NOTICE && cl) {
713                         conffile_list_elt_t *iter;
714                         for (iter = nv_pair_list_first(cl); iter;
715                              iter = nv_pair_list_next(cl, iter)) {
716                                 conffile_t *cf = (conffile_t *) iter->data;
717                                 int modified = conffile_has_been_modified(cf);
718                                 if (cf->value)
719                                         opkg_msg(INFO,
720                                                  "conffile=%s md5sum=%s modified=%d.\n",
721                                                  cf->name, cf->value, modified);
722                         }
723                 }
724         }
725         pkg_vec_free(available);
726
727         return 0;
728 }
729
730 static int opkg_info_cmd(int argc, char **argv)
731 {
732         return opkg_info_status_cmd(argc, argv, 0);
733 }
734
735 static int opkg_status_cmd(int argc, char **argv)
736 {
737         return opkg_info_status_cmd(argc, argv, 1);
738 }
739
740 static int opkg_configure_cmd(int argc, char **argv)
741 {
742         int err;
743         char *pkg_name = NULL;
744
745         if (argc > 0)
746                 pkg_name = argv[0];
747
748         err = opkg_configure_packages(pkg_name);
749
750         write_status_files_if_changed();
751
752         return err;
753 }
754
755 static int opkg_remove_cmd(int argc, char **argv)
756 {
757         int i, a, done, err = 0;
758         pkg_t *pkg;
759         pkg_t *pkg_to_remove;
760         pkg_vec_t *available;
761
762         done = 0;
763
764         signal(SIGINT, sigint_handler);
765
766         pkg_info_preinstall_check();
767
768         available = pkg_vec_alloc();
769         pkg_hash_fetch_all_installed(available);
770
771         for (i = 0; i < argc; i++) {
772                 for (a = 0; a < available->len; a++) {
773                         pkg = available->pkgs[a];
774                         if (fnmatch(argv[i], pkg->name, conf->nocase)) {
775                                 continue;
776                         }
777                         if (conf->restrict_to_default_dest) {
778                                 pkg_to_remove =
779                                     pkg_hash_fetch_installed_by_name_dest(pkg->
780                                                                           name,
781                                                                           conf->
782                                                                           default_dest);
783                         } else {
784                                 pkg_to_remove =
785                                     pkg_hash_fetch_installed_by_name(pkg->name);
786                         }
787
788                         if (pkg_to_remove == NULL) {
789                                 opkg_msg(ERROR,
790                                          "Package %s is not installed.\n",
791                                          pkg->name);
792                                 continue;
793                         }
794                         if (pkg->state_status == SS_NOT_INSTALLED) {
795                                 opkg_msg(ERROR, "Package %s not installed.\n",
796                                          pkg->name);
797                                 continue;
798                         }
799
800                         if (opkg_remove_pkg(pkg_to_remove, 0))
801                                 err = -1;
802                         else
803                                 done = 1;
804                 }
805         }
806
807         pkg_vec_free(available);
808
809         if (done == 0)
810                 opkg_msg(NOTICE, "No packages removed.\n");
811
812         write_status_files_if_changed();
813         return err;
814 }
815
816 static int opkg_flag_cmd(int argc, char **argv)
817 {
818         int i;
819         pkg_t *pkg;
820         const char *flags = argv[0];
821
822         signal(SIGINT, sigint_handler);
823
824         for (i = 1; i < argc; i++) {
825                 if (conf->restrict_to_default_dest) {
826                         pkg = pkg_hash_fetch_installed_by_name_dest(argv[i],
827                                                                     conf->
828                                                                     default_dest);
829                 } else {
830                         pkg = pkg_hash_fetch_installed_by_name(argv[i]);
831                 }
832
833                 if (pkg == NULL) {
834                         opkg_msg(ERROR, "Package %s is not installed.\n",
835                                  argv[i]);
836                         continue;
837                 }
838                 if ((strcmp(flags, "hold") == 0)
839                     || (strcmp(flags, "noprune") == 0)
840                     || (strcmp(flags, "user") == 0)
841                     || (strcmp(flags, "ok") == 0)) {
842                         pkg->state_flag = pkg_state_flag_from_str(flags);
843                 }
844
845                 /*
846                  * Useful if a package is installed in an offline_root, and
847                  * should be configured by opkg-cl configure at a later date.
848                  */
849                 if ((strcmp(flags, "installed") == 0)
850                     || (strcmp(flags, "unpacked") == 0)) {
851                         pkg->state_status = pkg_state_status_from_str(flags);
852                 }
853
854                 opkg_state_changed++;
855                 opkg_msg(NOTICE, "Setting flags for package %s to %s.\n",
856                          pkg->name, flags);
857         }
858
859         write_status_files_if_changed();
860         return 0;
861 }
862
863 static int opkg_files_cmd(int argc, char **argv)
864 {
865         pkg_t *pkg;
866         str_list_t *files;
867         str_list_elt_t *iter;
868         char *pkg_version;
869
870         if (argc < 1) {
871                 return -1;
872         }
873
874         pkg = pkg_hash_fetch_installed_by_name(argv[0]);
875         if (pkg == NULL) {
876                 opkg_msg(ERROR, "Package %s not installed.\n", argv[0]);
877                 return 0;
878         }
879
880         files = pkg_get_installed_files(pkg);
881         pkg_version = pkg_version_str_alloc(pkg);
882
883         printf
884             ("Package %s (%s) is installed on %s and has the following files:\n",
885              pkg->name, pkg_version, pkg->dest->name);
886
887         for (iter = str_list_first(files); iter;
888              iter = str_list_next(files, iter))
889                 printf("%s\n", (char *)iter->data);
890
891         free(pkg_version);
892         pkg_free_installed_files(pkg);
893
894         return 0;
895 }
896
897 static int opkg_depends_cmd(int argc, char **argv)
898 {
899         int i, j, k;
900         pkg_vec_t *available_pkgs;
901         compound_depend_t *cdep;
902         pkg_t *pkg;
903         char *str;
904
905         pkg_info_preinstall_check();
906
907         available_pkgs = pkg_vec_alloc();
908         if (conf->query_all)
909                 pkg_hash_fetch_available(available_pkgs);
910         else
911                 pkg_hash_fetch_all_installed(available_pkgs);
912
913         for (i = 0; i < argc; i++) {
914                 for (j = 0; j < available_pkgs->len; j++) {
915                         pkg = available_pkgs->pkgs[j];
916
917                         if (fnmatch(argv[i], pkg->name, conf->nocase) != 0)
918                                 continue;
919
920                         opkg_msg(NOTICE, "%s depends on:\n", pkg->name);
921
922                         for (k = 0, cdep = pkg_get_ptr(pkg, PKG_DEPENDS); cdep && cdep->type; k++, cdep++) {
923                                 if (cdep->type != DEPEND)
924                                         continue;
925
926                                 str = pkg_depend_str(pkg, k);
927                                 opkg_msg(NOTICE, "\t%s\n", str);
928                                 free(str);
929                         }
930
931                 }
932         }
933
934         pkg_vec_free(available_pkgs);
935         return 0;
936 }
937
938 static int pkg_mark_provides(pkg_t * pkg)
939 {
940         abstract_pkg_t **provider = pkg_get_ptr(pkg, PKG_PROVIDES);
941
942         pkg->parent->state_flag |= SF_MARKED;
943
944         while (provider && *provider) {
945                 (*provider)->state_flag |= SF_MARKED;
946                 provider++;
947         }
948
949         return 0;
950 }
951
952 enum what_field_type {
953         WHATDEPENDS,
954         WHATCONFLICTS,
955         WHATPROVIDES,
956         WHATREPLACES,
957         WHATRECOMMENDS,
958         WHATSUGGESTS
959 };
960
961 static int
962 opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive,
963                                 int argc, char **argv)
964 {
965         depend_t *possibility;
966         compound_depend_t *cdep, *deps;
967         pkg_vec_t *available_pkgs;
968         pkg_t *pkg;
969         int i, j, l;
970         int changed;
971         const char *rel_str = NULL;
972         char *ver;
973
974         switch (what_field_type) {
975         case DEPEND:
976                 rel_str = "depends on";
977                 break;
978         case CONFLICTS:
979                 rel_str = "conflicts with";
980                 break;
981         case SUGGEST:
982                 rel_str = "suggests";
983                 break;
984         case RECOMMEND:
985                 rel_str = "recommends";
986                 break;
987         default:
988                 return -1;
989         }
990
991         available_pkgs = pkg_vec_alloc();
992
993         if (conf->query_all)
994                 pkg_hash_fetch_available(available_pkgs);
995         else
996                 pkg_hash_fetch_all_installed(available_pkgs);
997
998         /* mark the root set */
999         pkg_vec_clear_marks(available_pkgs);
1000         opkg_msg(NOTICE, "Root set:\n");
1001         for (i = 0; i < argc; i++)
1002                 pkg_vec_mark_if_matches(available_pkgs, argv[i]);
1003
1004         for (i = 0; i < available_pkgs->len; i++) {
1005                 pkg = available_pkgs->pkgs[i];
1006                 if (pkg->state_flag & SF_MARKED) {
1007                         /* mark the parent (abstract) package */
1008                         pkg_mark_provides(pkg);
1009                         opkg_msg(NOTICE, "  %s\n", pkg->name);
1010                 }
1011         }
1012
1013         opkg_msg(NOTICE, "What %s root set\n", rel_str);
1014         do {
1015                 changed = 0;
1016
1017                 for (j = 0; j < available_pkgs->len; j++) {
1018
1019                         pkg = available_pkgs->pkgs[j];
1020                         /*
1021                         count = ((what_field_type == CONFLICTS)
1022                                  ? pkg->conflicts_count
1023                                  : pkg->pre_depends_count +
1024                                  pkg->depends_count +
1025                                  pkg->recommends_count + pkg->suggests_count);
1026                                  */
1027
1028                         /* skip this package if it is already marked */
1029                         if (pkg->parent->state_flag & SF_MARKED)
1030                                 continue;
1031
1032                         deps = pkg_get_ptr(pkg, (what_field_type == CONFLICTS) ? PKG_CONFLICTS : PKG_DEPENDS);
1033
1034                         for (cdep = deps; cdep->type; cdep++) {
1035                                 if (what_field_type != cdep->type)
1036                                         continue;
1037
1038                                 for (l = 0; l < cdep->possibility_count; l++) {
1039                                         possibility = cdep->possibilities[l];
1040
1041                                         if ((possibility->pkg->state_flag
1042                                              & SF_MARKED)
1043                                             != SF_MARKED)
1044                                                 continue;
1045
1046                                         /* mark the depending package so we
1047                                          * won't visit it again */
1048                                         pkg->state_flag |= SF_MARKED;
1049                                         pkg_mark_provides(pkg);
1050                                         changed++;
1051
1052                                         ver = pkg_version_str_alloc(pkg);
1053                                         opkg_msg(NOTICE, "\t%s %s\t%s %s",
1054                                                  pkg->name,
1055                                                  ver,
1056                                                  rel_str,
1057                                                  possibility->pkg->name);
1058                                         free(ver);
1059                                         if (possibility->version) {
1060                                                 opkg_msg(NOTICE, " (%s%s)",
1061                                                          constraint_to_str
1062                                                          (possibility->
1063                                                           constraint),
1064                                                          possibility->version);
1065                                         }
1066                                         if (!pkg_dependence_satisfiable
1067                                             (possibility))
1068                                                 opkg_msg(NOTICE,
1069                                                          " unsatisfiable");
1070                                         opkg_message(NOTICE, "\n");
1071                                         goto next_package;
1072                                 }
1073                         }
1074 next_package:
1075                         ;
1076                 }
1077         } while (changed && recursive);
1078
1079         pkg_vec_free(available_pkgs);
1080
1081         return 0;
1082 }
1083
1084 static int opkg_whatdepends_recursively_cmd(int argc, char **argv)
1085 {
1086         return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv);
1087 }
1088
1089 static int opkg_whatdepends_cmd(int argc, char **argv)
1090 {
1091         return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv);
1092 }
1093
1094 static int opkg_whatsuggests_cmd(int argc, char **argv)
1095 {
1096         return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv);
1097 }
1098
1099 static int opkg_whatrecommends_cmd(int argc, char **argv)
1100 {
1101         return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv);
1102 }
1103
1104 static int opkg_whatconflicts_cmd(int argc, char **argv)
1105 {
1106         return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv);
1107 }
1108
1109 static int
1110 opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc,
1111                                 char **argv)
1112 {
1113         abstract_pkg_t *apkg, **abpkgs;
1114
1115         if (argc > 0) {
1116                 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1117                 const char *rel_str =
1118                     (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1119                 int i;
1120
1121                 pkg_info_preinstall_check();
1122
1123                 if (conf->query_all)
1124                         pkg_hash_fetch_available(available_pkgs);
1125                 else
1126                         pkg_hash_fetch_all_installed(available_pkgs);
1127                 for (i = 0; i < argc; i++) {
1128                         const char *target = argv[i];
1129                         int j;
1130
1131                         opkg_msg(NOTICE, "What %s %s\n", rel_str, target);
1132                         for (j = 0; j < available_pkgs->len; j++) {
1133                                 pkg_t *pkg = available_pkgs->pkgs[j];
1134                                 abpkgs = pkg_get_ptr(pkg, (what_field_type == WHATPROVIDES) ? PKG_PROVIDES : PKG_REPLACES);
1135
1136                                 while (abpkgs && *abpkgs) {
1137                                         apkg = *abpkgs;
1138
1139                                         if (fnmatch(target, apkg->name, conf->nocase))
1140                                                 continue;
1141
1142                                         opkg_msg(NOTICE, "    %s", pkg->name);
1143
1144                                         if ((conf->nocase ? strcasecmp(target, apkg->name)
1145                                             : strcmp(target, apkg->name)))
1146                                                 opkg_msg(NOTICE, "\t%s %s\n", rel_str, apkg->name);
1147
1148                                         opkg_message(NOTICE, "\n");
1149                                         abpkgs++;
1150                                 }
1151                         }
1152                 }
1153                 pkg_vec_free(available_pkgs);
1154         }
1155         return 0;
1156 }
1157
1158 static int opkg_whatprovides_cmd(int argc, char **argv)
1159 {
1160         return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv);
1161 }
1162
1163 static int opkg_whatreplaces_cmd(int argc, char **argv)
1164 {
1165         return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv);
1166 }
1167
1168 static int opkg_search_cmd(int argc, char **argv)
1169 {
1170         int i;
1171
1172         pkg_vec_t *installed;
1173         pkg_t *pkg;
1174         str_list_t *installed_files;
1175         str_list_elt_t *iter;
1176         char *installed_file;
1177
1178         if (argc < 1) {
1179                 return -1;
1180         }
1181
1182         installed = pkg_vec_alloc();
1183         pkg_hash_fetch_all_installed(installed);
1184         pkg_vec_sort(installed, pkg_compare_names);
1185
1186         for (i = 0; i < installed->len; i++) {
1187                 pkg = installed->pkgs[i];
1188
1189                 installed_files = pkg_get_installed_files(pkg);
1190
1191                 for (iter = str_list_first(installed_files); iter;
1192                      iter = str_list_next(installed_files, iter)) {
1193                         installed_file = (char *)iter->data;
1194                         if (fnmatch(argv[0], installed_file, conf->nocase) == 0)
1195                                 print_pkg(pkg);
1196                 }
1197
1198                 pkg_free_installed_files(pkg);
1199         }
1200
1201         pkg_vec_free(installed);
1202
1203         return 0;
1204 }
1205
1206 static int opkg_compare_versions_cmd(int argc, char **argv)
1207 {
1208         if (argc == 3) {
1209                 /* this is a bit gross */
1210                 struct pkg p1, p2;
1211                 parse_version(&p1, argv[0]);
1212                 parse_version(&p2, argv[2]);
1213                 return pkg_version_satisfied(&p1, &p2, argv[1]);
1214         } else {
1215                 opkg_msg(ERROR,
1216                          "opkg compare_versions <v1> <op> <v2>\n"
1217                          "<op> is one of <= >= << >> =\n");
1218                 return -1;
1219         }
1220 }
1221
1222 static int opkg_print_architecture_cmd(int argc, char **argv)
1223 {
1224         nv_pair_list_elt_t *l;
1225
1226         list_for_each_entry(l, &conf->arch_list.head, node) {
1227                 nv_pair_t *nv = (nv_pair_t *) l->data;
1228                 printf("arch %s %s\n", nv->name, nv->value);
1229         }
1230         return 0;
1231 }
1232
1233 /* XXX: CLEANUP: The usage strings should be incorporated into this
1234    array for easier maintenance */
1235 static opkg_cmd_t cmds[] = {
1236         {"update", 0, (opkg_cmd_fun_t) opkg_update_cmd,
1237          PFM_DESCRIPTION | PFM_SOURCE},
1238         {"upgrade", 1, (opkg_cmd_fun_t) opkg_upgrade_cmd,
1239          PFM_DESCRIPTION | PFM_SOURCE},
1240         {"list", 0, (opkg_cmd_fun_t) opkg_list_cmd, PFM_SOURCE},
1241         {"list_installed", 0, (opkg_cmd_fun_t) opkg_list_installed_cmd,
1242          PFM_SOURCE},
1243         {"list-installed", 0, (opkg_cmd_fun_t) opkg_list_installed_cmd,
1244          PFM_SOURCE},
1245         {"list_upgradable", 0, (opkg_cmd_fun_t) opkg_list_upgradable_cmd,
1246          PFM_SOURCE},
1247         {"list-upgradable", 0, (opkg_cmd_fun_t) opkg_list_upgradable_cmd,
1248          PFM_SOURCE},
1249         {"list_changed_conffiles", 0,
1250          (opkg_cmd_fun_t) opkg_list_changed_conffiles_cmd, PFM_SOURCE},
1251         {"list-changed-conffiles", 0,
1252          (opkg_cmd_fun_t) opkg_list_changed_conffiles_cmd, PFM_SOURCE},
1253         {"info", 0, (opkg_cmd_fun_t) opkg_info_cmd, 0},
1254         {"flag", 1, (opkg_cmd_fun_t) opkg_flag_cmd,
1255          PFM_DESCRIPTION | PFM_SOURCE},
1256         {"status", 0, (opkg_cmd_fun_t) opkg_status_cmd,
1257          PFM_DESCRIPTION | PFM_SOURCE},
1258         {"install", 1, (opkg_cmd_fun_t) opkg_install_cmd,
1259          PFM_DESCRIPTION | PFM_SOURCE},
1260         {"remove", 1, (opkg_cmd_fun_t) opkg_remove_cmd,
1261          PFM_DESCRIPTION | PFM_SOURCE},
1262         {"configure", 0, (opkg_cmd_fun_t) opkg_configure_cmd,
1263          PFM_DESCRIPTION | PFM_SOURCE},
1264         {"files", 1, (opkg_cmd_fun_t) opkg_files_cmd,
1265          PFM_DESCRIPTION | PFM_SOURCE},
1266         {"search", 1, (opkg_cmd_fun_t) opkg_search_cmd,
1267          PFM_DESCRIPTION | PFM_SOURCE},
1268         {"find", 1, (opkg_cmd_fun_t) opkg_find_cmd, PFM_SOURCE},
1269         {"download", 1, (opkg_cmd_fun_t) opkg_download_cmd,
1270          PFM_DESCRIPTION | PFM_SOURCE},
1271         {"compare_versions", 1, (opkg_cmd_fun_t) opkg_compare_versions_cmd,
1272          PFM_DESCRIPTION | PFM_SOURCE},
1273         {"compare-versions", 1, (opkg_cmd_fun_t) opkg_compare_versions_cmd,
1274          PFM_DESCRIPTION | PFM_SOURCE},
1275         {"print-architecture", 0, (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1276          PFM_DESCRIPTION | PFM_SOURCE},
1277         {"print_architecture", 0, (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1278          PFM_DESCRIPTION | PFM_SOURCE},
1279         {"print-installation-architecture", 0,
1280          (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1281          PFM_DESCRIPTION | PFM_SOURCE},
1282         {"print_installation_architecture", 0,
1283          (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1284          PFM_DESCRIPTION | PFM_SOURCE},
1285         {"depends", 1, (opkg_cmd_fun_t) opkg_depends_cmd,
1286          PFM_DESCRIPTION | PFM_SOURCE},
1287         {"whatdepends", 1, (opkg_cmd_fun_t) opkg_whatdepends_cmd,
1288          PFM_DESCRIPTION | PFM_SOURCE},
1289         {"whatdependsrec", 1, (opkg_cmd_fun_t) opkg_whatdepends_recursively_cmd,
1290          PFM_DESCRIPTION | PFM_SOURCE},
1291         {"whatrecommends", 1, (opkg_cmd_fun_t) opkg_whatrecommends_cmd,
1292          PFM_DESCRIPTION | PFM_SOURCE},
1293         {"whatsuggests", 1, (opkg_cmd_fun_t) opkg_whatsuggests_cmd,
1294          PFM_DESCRIPTION | PFM_SOURCE},
1295         {"whatprovides", 1, (opkg_cmd_fun_t) opkg_whatprovides_cmd,
1296          PFM_DESCRIPTION | PFM_SOURCE},
1297         {"whatreplaces", 1, (opkg_cmd_fun_t) opkg_whatreplaces_cmd,
1298          PFM_DESCRIPTION | PFM_SOURCE},
1299         {"whatconflicts", 1, (opkg_cmd_fun_t) opkg_whatconflicts_cmd,
1300          PFM_DESCRIPTION | PFM_SOURCE},
1301 };
1302
1303 opkg_cmd_t *opkg_cmd_find(const char *name)
1304 {
1305         int i;
1306         opkg_cmd_t *cmd;
1307         int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
1308
1309         for (i = 0; i < num_cmds; i++) {
1310                 cmd = &cmds[i];
1311                 if (strcmp(name, cmd->name) == 0)
1312                         return cmd;
1313         }
1314
1315         return NULL;
1316 }
1317
1318 int opkg_cmd_exec(opkg_cmd_t * cmd, int argc, const char **argv)
1319 {
1320         return (cmd->fun) (argc, argv);
1321 }