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