treewrite: use Lindent to reformat to kernel coding style
[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         printf("%s - %s", pkg->name, version);
50         if (conf->size)
51                 printf(" - %lu", pkg->size);
52         if (pkg->description)
53                 printf(" - %s", pkg->description);
54         printf("\n");
55         free(version);
56 }
57
58 int opkg_state_changed;
59
60 static void write_status_files_if_changed(void)
61 {
62         if (opkg_state_changed && !conf->noaction) {
63                 opkg_msg(INFO, "Writing status file.\n");
64                 opkg_conf_write_status_files();
65                 pkg_write_changed_filelists();
66         } else {
67                 opkg_msg(DEBUG, "Nothing to be done.\n");
68         }
69 }
70
71 static void sigint_handler(int sig)
72 {
73         signal(sig, SIG_DFL);
74         opkg_msg(NOTICE, "Interrupted. Writing out status database.\n");
75         write_status_files_if_changed();
76         exit(128 + sig);
77 }
78
79 static int opkg_update_cmd(int argc, char **argv)
80 {
81         char *tmp;
82         int err;
83         int failures;
84         int pkglist_dl_error;
85         char *lists_dir;
86         pkg_src_list_elt_t *iter;
87         pkg_src_t *src;
88
89         sprintf_alloc(&lists_dir, "%s",
90                       conf->restrict_to_default_dest ? conf->default_dest->
91                       lists_dir : conf->lists_dir);
92
93         if (!file_is_dir(lists_dir)) {
94                 if (file_exists(lists_dir)) {
95                         opkg_msg(ERROR, "%s exists, but is not a directory.\n",
96                                  lists_dir);
97                         free(lists_dir);
98                         return -1;
99                 }
100                 err = file_mkdir_hier(lists_dir, 0755);
101                 if (err) {
102                         free(lists_dir);
103                         return -1;
104                 }
105         }
106
107         failures = 0;
108
109         sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir);
110         if (mkdtemp(tmp) == NULL) {
111                 opkg_perror(ERROR, "Failed to make temp dir %s", conf->tmp_dir);
112                 return -1;
113         }
114
115         for (iter = void_list_first(&conf->pkg_src_list); iter;
116              iter = void_list_next(&conf->pkg_src_list, iter)) {
117                 char *url, *list_file_name;
118
119                 src = (pkg_src_t *) iter->data;
120
121                 if (src->extra_data && strcmp(src->extra_data, "__dummy__ "))
122                         continue;
123
124                 if (src->extra_data)    /* debian style? */
125                         sprintf_alloc(&url, "%s/%s/%s", src->value,
126                                       src->extra_data,
127                                       src->gzip ? "Packages.gz" : "Packages");
128                 else
129                         sprintf_alloc(&url, "%s/%s", src->value,
130                                       src->gzip ? "Packages.gz" : "Packages");
131
132                 sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
133                 pkglist_dl_error = 0;
134                 if (opkg_download(url, list_file_name, NULL, NULL, 0)) {
135                         failures++;
136                         pkglist_dl_error = 1;
137                         opkg_msg(NOTICE,
138                                  "*** Failed to download the package list from %s\n\n",
139                                  url);
140                 } else {
141                         opkg_msg(NOTICE,
142                                  "Updated list of available packages in %s\n",
143                                  list_file_name);
144                 }
145                 free(url);
146 #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) || defined(HAVE_USIGN)
147                 if (pkglist_dl_error == 0 && conf->check_signature) {
148                         /* download detached signitures to verify the package lists */
149                         /* get the url for the sig file */
150                         if (src->extra_data)    /* debian style? */
151                                 sprintf_alloc(&url, "%s/%s/%s", src->value,
152                                               src->extra_data, "Packages.sig");
153                         else
154                                 sprintf_alloc(&url, "%s/%s", src->value,
155                                               "Packages.sig");
156
157                         /* create temporary file for it */
158                         char *tmp_file_name;
159
160                         /* Put the signature in the right place */
161                         sprintf_alloc(&tmp_file_name, "%s/%s.sig", lists_dir,
162                                       src->name);
163
164                         err = opkg_download(url, tmp_file_name, NULL, NULL, 0);
165                         if (err) {
166                                 failures++;
167                                 opkg_msg(NOTICE,
168                                          "Signature file download failed.\n");
169                         } else {
170                                 err =
171                                     opkg_verify_file(list_file_name,
172                                                      tmp_file_name);
173                                 if (err == 0)
174                                         opkg_msg(NOTICE,
175                                                  "Signature check passed.\n");
176                                 else
177                                         opkg_msg(NOTICE,
178                                                  "Signature check failed.\n");
179                         }
180                         if (err && !conf->force_signature) {
181                                 /* The signature was wrong so delete it */
182                                 opkg_msg(NOTICE,
183                                          "Remove wrong Signature file.\n");
184                                 unlink(tmp_file_name);
185                                 unlink(list_file_name);
186                         }
187                         /* We shouldn't unlink the signature ! */
188                         // unlink (tmp_file_name);
189                         free(tmp_file_name);
190                         free(url);
191                 }
192 #else
193                 // Do nothing
194 #endif
195                 free(list_file_name);
196         }
197         rmdir(tmp);
198         free(tmp);
199         free(lists_dir);
200
201         return failures;
202 }
203
204 struct opkg_intercept {
205         char *oldpath;
206         char *statedir;
207 };
208
209 typedef struct opkg_intercept *opkg_intercept_t;
210
211 static opkg_intercept_t opkg_prep_intercepts(void)
212 {
213         opkg_intercept_t ctx;
214         char *newpath;
215
216         ctx = xcalloc(1, sizeof(*ctx));
217         ctx->oldpath = xstrdup(getenv("PATH"));
218         sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
219         sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX",
220                       conf->tmp_dir);
221
222         if (mkdtemp(ctx->statedir) == NULL) {
223                 opkg_perror(ERROR, "Failed to make temp dir %s", ctx->statedir);
224                 free(ctx->oldpath);
225                 free(ctx->statedir);
226                 free(newpath);
227                 free(ctx);
228                 return NULL;
229         }
230
231         setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
232         setenv("PATH", newpath, 1);
233         free(newpath);
234
235         return ctx;
236 }
237
238 static int opkg_finalize_intercepts(opkg_intercept_t ctx)
239 {
240         DIR *dir;
241         int err = 0;
242
243         setenv("PATH", ctx->oldpath, 1);
244         free(ctx->oldpath);
245
246         dir = opendir(ctx->statedir);
247         if (dir) {
248                 struct dirent *de;
249                 while (de = readdir(dir), de != NULL) {
250                         char *path;
251
252                         if (de->d_name[0] == '.')
253                                 continue;
254
255                         sprintf_alloc(&path, "%s/%s", ctx->statedir,
256                                       de->d_name);
257                         if (access(path, X_OK) == 0) {
258                                 const char *argv[] = { "sh", "-c", path, NULL };
259                                 xsystem(argv);
260                         }
261                         free(path);
262                 }
263                 closedir(dir);
264         } else
265                 opkg_perror(ERROR, "Failed to open dir %s", ctx->statedir);
266
267         rm_r(ctx->statedir);
268         free(ctx->statedir);
269         free(ctx);
270
271         return err;
272 }
273
274 /* For package pkg do the following: If it is already visited, return. If not,
275    add it in visited list and recurse to its deps. Finally, add it to ordered
276    list.
277    pkg_vec all contains all available packages in repos.
278    pkg_vec visited contains packages already visited by this function, and is
279    used to end recursion and avoid an infinite loop on graph cycles.
280    pkg_vec ordered will finally contain the ordered set of packages.
281 */
282 static int
283 opkg_recurse_pkgs_in_order(pkg_t * pkg, pkg_vec_t * all,
284                            pkg_vec_t * visited, pkg_vec_t * ordered)
285 {
286         int j, k, l, m;
287         int count;
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         count = pkg->pre_depends_count + pkg->depends_count +
315             pkg->recommends_count + pkg->suggests_count;
316
317         opkg_msg(DEBUG, "pkg %s.\n", pkg->name);
318
319         /* Iterate over all the dependencies of pkg. For each one, find a package
320            that is either installed or unpacked and satisfies this dependency.
321            (there should only be one such package per dependency installed or
322            unpacked). Then recurse to the dependency package */
323         for (j = 0; j < count; j++) {
324                 compound_depend = &pkg->depends[j];
325                 possible_satisfiers = compound_depend->possibilities;
326                 for (k = 0; k < compound_depend->possibility_count; k++) {
327                         abpkg = possible_satisfiers[k]->pkg;
328                         dependents = abpkg->provided_by->pkgs;
329                         l = 0;
330                         if (dependents != NULL)
331                                 while (l < abpkg->provided_by->len
332                                        && dependents[l] != NULL) {
333                                         opkg_msg(DEBUG,
334                                                  "Descending on pkg %s.\n",
335                                                  dependents[l]->name);
336
337                                         /* find whether dependent l is installed or unpacked,
338                                          * and then find which package in the list satisfies it */
339                                         for (m = 0; m < all->len; m++) {
340                                                 dep = all->pkgs[m];
341                                                 if (dep->state_status !=
342                                                     SS_NOT_INSTALLED)
343                                                         if (!strcmp
344                                                             (dep->name,
345                                                              dependents[l]->
346                                                              name)) {
347                                                                 opkg_recurse_pkgs_in_order
348                                                                     (dep, all,
349                                                                      visited,
350                                                                      ordered);
351                                                                 /* Stop the outer loop */
352                                                                 l = abpkg->
353                                                                     provided_by->
354                                                                     len;
355                                                                 /* break from the inner loop */
356                                                                 break;
357                                                         }
358                                         }
359                                         l++;
360                                 }
361                 }
362         }
363
364         /* When all recursions from this node down, are over, and all
365            dependencies have been added in proper order in the ordered array, add
366            also the package pkg to ordered array */
367         pkg_vec_insert(ordered, pkg);
368
369         return 0;
370
371 }
372
373 static int opkg_configure_packages(char *pkg_name)
374 {
375         pkg_vec_t *all, *ordered, *visited;
376         int i;
377         pkg_t *pkg;
378         opkg_intercept_t ic;
379         int r, err = 0;
380
381         opkg_msg(INFO, "Configuring unpacked packages.\n");
382
383         all = pkg_vec_alloc();
384
385         pkg_hash_fetch_available(all);
386
387         /* Reorder pkgs in order to be configured according to the Depends: tag
388            order */
389         opkg_msg(INFO, "Reordering packages before configuring them...\n");
390         ordered = pkg_vec_alloc();
391         visited = pkg_vec_alloc();
392         for (i = 0; i < all->len; i++) {
393                 pkg = all->pkgs[i];
394                 opkg_recurse_pkgs_in_order(pkg, all, visited, ordered);
395         }
396
397         ic = opkg_prep_intercepts();
398         if (ic == NULL) {
399                 err = -1;
400                 goto error;
401         }
402
403         for (i = 0; i < ordered->len; i++) {
404                 pkg = ordered->pkgs[i];
405
406                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
407                         continue;
408
409                 if (pkg->state_status == SS_UNPACKED) {
410                         opkg_msg(NOTICE, "Configuring %s.\n", pkg->name);
411                         r = opkg_configure(pkg);
412                         if (r == 0) {
413                                 pkg->state_status = SS_INSTALLED;
414                                 pkg->parent->state_status = SS_INSTALLED;
415                                 pkg->state_flag &= ~SF_PREFER;
416                                 opkg_state_changed++;
417                         } else {
418                                 err = -1;
419                         }
420                 }
421         }
422
423         if (opkg_finalize_intercepts(ic))
424                 err = -1;
425
426 error:
427         pkg_vec_free(all);
428         pkg_vec_free(ordered);
429         pkg_vec_free(visited);
430
431         return err;
432 }
433
434 static int opkg_remove_cmd(int argc, char **argv);
435
436 static int opkg_install_cmd(int argc, char **argv)
437 {
438         int i;
439         char *arg;
440         int err = 0;
441
442         if (conf->force_reinstall) {
443                 int saved_force_depends = conf->force_depends;
444                 conf->force_depends = 1;
445                 (void)opkg_remove_cmd(argc, argv);
446                 conf->force_depends = saved_force_depends;
447                 conf->force_reinstall = 0;
448         }
449
450         signal(SIGINT, sigint_handler);
451
452         /*
453          * Now scan through package names and install
454          */
455         for (i = 0; i < argc; i++) {
456                 arg = argv[i];
457
458                 opkg_msg(DEBUG2, "%s\n", arg);
459                 if (opkg_prepare_url_for_install(arg, &argv[i]))
460                         return -1;
461         }
462         pkg_info_preinstall_check();
463
464         for (i = 0; i < argc; i++) {
465                 arg = argv[i];
466                 if (opkg_install_by_name(arg)) {
467                         opkg_msg(ERROR, "Cannot install package %s.\n", arg);
468                         err = -1;
469                 }
470         }
471
472         if (opkg_configure_packages(NULL))
473                 err = -1;
474
475         write_status_files_if_changed();
476
477         return err;
478 }
479
480 static int opkg_upgrade_cmd(int argc, char **argv)
481 {
482         int i;
483         pkg_t *pkg;
484         int err = 0;
485
486         signal(SIGINT, sigint_handler);
487
488         if (argc) {
489                 for (i = 0; i < argc; i++) {
490                         char *arg = argv[i];
491
492                         if (opkg_prepare_url_for_install(arg, &arg))
493                                 return -1;
494                 }
495                 pkg_info_preinstall_check();
496
497                 for (i = 0; i < argc; i++) {
498                         char *arg = argv[i];
499                         if (conf->restrict_to_default_dest) {
500                                 pkg =
501                                     pkg_hash_fetch_installed_by_name_dest(argv
502                                                                           [i],
503                                                                           conf->
504                                                                           default_dest);
505                                 if (pkg == NULL) {
506                                         opkg_msg(NOTICE,
507                                                  "Package %s not installed in %s.\n",
508                                                  argv[i],
509                                                  conf->default_dest->name);
510                                         continue;
511                                 }
512                         } else {
513                                 pkg = pkg_hash_fetch_installed_by_name(argv[i]);
514                         }
515                         if (pkg) {
516                                 if (opkg_upgrade_pkg(pkg))
517                                         err = -1;
518                         } else {
519                                 if (opkg_install_by_name(arg))
520                                         err = -1;
521                         }
522                 }
523         }
524
525         if (opkg_configure_packages(NULL))
526                 err = -1;
527
528         write_status_files_if_changed();
529
530         return err;
531 }
532
533 static int opkg_download_cmd(int argc, char **argv)
534 {
535         int i, err = 0;
536         char *arg;
537         pkg_t *pkg;
538
539         pkg_info_preinstall_check();
540         for (i = 0; i < argc; i++) {
541                 arg = argv[i];
542
543                 pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg);
544                 if (pkg == NULL) {
545                         opkg_msg(ERROR, "Cannot find package %s.\n", arg);
546                         continue;
547                 }
548
549                 if (opkg_download_pkg(pkg, "."))
550                         err = -1;
551
552                 if (err) {
553                         opkg_msg(ERROR, "Failed to download %s.\n", pkg->name);
554                 } else {
555                         opkg_msg(NOTICE, "Downloaded %s as %s.\n",
556                                  pkg->name, pkg->local_filename);
557                 }
558         }
559
560         return err;
561 }
562
563 static int opkg_list_find_cmd(int argc, char **argv, int use_desc)
564 {
565         int i;
566         pkg_vec_t *available;
567         pkg_t *pkg;
568         char *pkg_name = NULL;
569
570         if (argc > 0) {
571                 pkg_name = argv[0];
572         }
573         available = pkg_vec_alloc();
574         pkg_hash_fetch_available(available);
575         pkg_vec_sort(available, pkg_compare_names);
576         for (i = 0; i < available->len; i++) {
577                 pkg = available->pkgs[i];
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 || !pkg->description
581                      || fnmatch(pkg_name, pkg->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_t *cf;
634
635         if (argc > 0) {
636                 pkg_name = argv[0];
637         }
638         available = pkg_vec_alloc();
639         pkg_hash_fetch_all_installed(available);
640         pkg_vec_sort(available, pkg_compare_names);
641         for (i = 0; i < available->len; i++) {
642                 pkg = available->pkgs[i];
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 (nv_pair_list_empty(&pkg->conffiles))
647                         continue;
648                 for (iter = nv_pair_list_first(&pkg->conffiles); iter;
649                      iter = nv_pair_list_next(&pkg->conffiles, 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
691         if (argc > 0) {
692                 pkg_name = argv[0];
693         }
694
695         available = pkg_vec_alloc();
696         if (installed_only)
697                 pkg_hash_fetch_all_installed(available);
698         else
699                 pkg_hash_fetch_available(available);
700
701         for (i = 0; i < available->len; i++) {
702                 pkg = available->pkgs[i];
703                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase)) {
704                         continue;
705                 }
706
707                 pkg_formatted_info(stdout, pkg);
708
709                 if (conf->verbosity >= NOTICE) {
710                         conffile_list_elt_t *iter;
711                         for (iter = nv_pair_list_first(&pkg->conffiles); iter;
712                              iter = nv_pair_list_next(&pkg->conffiles, iter)) {
713                                 conffile_t *cf = (conffile_t *) iter->data;
714                                 int modified = conffile_has_been_modified(cf);
715                                 if (cf->value)
716                                         opkg_msg(INFO,
717                                                  "conffile=%s md5sum=%s modified=%d.\n",
718                                                  cf->name, cf->value, modified);
719                         }
720                 }
721         }
722         pkg_vec_free(available);
723
724         return 0;
725 }
726
727 static int opkg_info_cmd(int argc, char **argv)
728 {
729         return opkg_info_status_cmd(argc, argv, 0);
730 }
731
732 static int opkg_status_cmd(int argc, char **argv)
733 {
734         return opkg_info_status_cmd(argc, argv, 1);
735 }
736
737 static int opkg_configure_cmd(int argc, char **argv)
738 {
739         int err;
740         char *pkg_name = NULL;
741
742         if (argc > 0)
743                 pkg_name = argv[0];
744
745         err = opkg_configure_packages(pkg_name);
746
747         write_status_files_if_changed();
748
749         return err;
750 }
751
752 static int opkg_remove_cmd(int argc, char **argv)
753 {
754         int i, a, done, err = 0;
755         pkg_t *pkg;
756         pkg_t *pkg_to_remove;
757         pkg_vec_t *available;
758
759         done = 0;
760
761         signal(SIGINT, sigint_handler);
762
763         pkg_info_preinstall_check();
764
765         available = pkg_vec_alloc();
766         pkg_hash_fetch_all_installed(available);
767
768         for (i = 0; i < argc; i++) {
769                 for (a = 0; a < available->len; a++) {
770                         pkg = available->pkgs[a];
771                         if (fnmatch(argv[i], pkg->name, conf->nocase)) {
772                                 continue;
773                         }
774                         if (conf->restrict_to_default_dest) {
775                                 pkg_to_remove =
776                                     pkg_hash_fetch_installed_by_name_dest(pkg->
777                                                                           name,
778                                                                           conf->
779                                                                           default_dest);
780                         } else {
781                                 pkg_to_remove =
782                                     pkg_hash_fetch_installed_by_name(pkg->name);
783                         }
784
785                         if (pkg_to_remove == NULL) {
786                                 opkg_msg(ERROR,
787                                          "Package %s is not installed.\n",
788                                          pkg->name);
789                                 continue;
790                         }
791                         if (pkg->state_status == SS_NOT_INSTALLED) {
792                                 opkg_msg(ERROR, "Package %s not installed.\n",
793                                          pkg->name);
794                                 continue;
795                         }
796
797                         if (opkg_remove_pkg(pkg_to_remove, 0))
798                                 err = -1;
799                         else
800                                 done = 1;
801                 }
802         }
803
804         pkg_vec_free(available);
805
806         if (done == 0)
807                 opkg_msg(NOTICE, "No packages removed.\n");
808
809         write_status_files_if_changed();
810         return err;
811 }
812
813 static int opkg_flag_cmd(int argc, char **argv)
814 {
815         int i;
816         pkg_t *pkg;
817         const char *flags = argv[0];
818
819         signal(SIGINT, sigint_handler);
820
821         for (i = 1; i < argc; i++) {
822                 if (conf->restrict_to_default_dest) {
823                         pkg = pkg_hash_fetch_installed_by_name_dest(argv[i],
824                                                                     conf->
825                                                                     default_dest);
826                 } else {
827                         pkg = pkg_hash_fetch_installed_by_name(argv[i]);
828                 }
829
830                 if (pkg == NULL) {
831                         opkg_msg(ERROR, "Package %s is not installed.\n",
832                                  argv[i]);
833                         continue;
834                 }
835                 if ((strcmp(flags, "hold") == 0)
836                     || (strcmp(flags, "noprune") == 0)
837                     || (strcmp(flags, "user") == 0)
838                     || (strcmp(flags, "ok") == 0)) {
839                         pkg->state_flag = pkg_state_flag_from_str(flags);
840                 }
841
842                 /*
843                  * Useful if a package is installed in an offline_root, and
844                  * should be configured by opkg-cl configure at a later date.
845                  */
846                 if ((strcmp(flags, "installed") == 0)
847                     || (strcmp(flags, "unpacked") == 0)) {
848                         pkg->state_status = pkg_state_status_from_str(flags);
849                 }
850
851                 opkg_state_changed++;
852                 opkg_msg(NOTICE, "Setting flags for package %s to %s.\n",
853                          pkg->name, flags);
854         }
855
856         write_status_files_if_changed();
857         return 0;
858 }
859
860 static int opkg_files_cmd(int argc, char **argv)
861 {
862         pkg_t *pkg;
863         str_list_t *files;
864         str_list_elt_t *iter;
865         char *pkg_version;
866
867         if (argc < 1) {
868                 return -1;
869         }
870
871         pkg = pkg_hash_fetch_installed_by_name(argv[0]);
872         if (pkg == NULL) {
873                 opkg_msg(ERROR, "Package %s not installed.\n", argv[0]);
874                 return 0;
875         }
876
877         files = pkg_get_installed_files(pkg);
878         pkg_version = pkg_version_str_alloc(pkg);
879
880         printf
881             ("Package %s (%s) is installed on %s and has the following files:\n",
882              pkg->name, pkg_version, pkg->dest->name);
883
884         for (iter = str_list_first(files); iter;
885              iter = str_list_next(files, iter))
886                 printf("%s\n", (char *)iter->data);
887
888         free(pkg_version);
889         pkg_free_installed_files(pkg);
890
891         return 0;
892 }
893
894 static int opkg_depends_cmd(int argc, char **argv)
895 {
896         int i, j, k;
897         int depends_count;
898         pkg_vec_t *available_pkgs;
899         compound_depend_t *cdep;
900         pkg_t *pkg;
901         char *str;
902
903         pkg_info_preinstall_check();
904
905         available_pkgs = pkg_vec_alloc();
906         if (conf->query_all)
907                 pkg_hash_fetch_available(available_pkgs);
908         else
909                 pkg_hash_fetch_all_installed(available_pkgs);
910
911         for (i = 0; i < argc; i++) {
912                 for (j = 0; j < available_pkgs->len; j++) {
913                         pkg = available_pkgs->pkgs[j];
914
915                         if (fnmatch(argv[i], pkg->name, conf->nocase) != 0)
916                                 continue;
917
918                         depends_count = pkg->depends_count +
919                             pkg->pre_depends_count +
920                             pkg->recommends_count + pkg->suggests_count;
921
922                         opkg_msg(NOTICE, "%s depends on:\n", pkg->name);
923
924                         for (k = 0; k < depends_count; k++) {
925                                 cdep = &pkg->depends[k];
926
927                                 if (cdep->type != DEPEND)
928                                         continue;
929
930                                 str = pkg_depend_str(pkg, k);
931                                 opkg_msg(NOTICE, "\t%s\n", str);
932                                 free(str);
933                         }
934
935                 }
936         }
937
938         pkg_vec_free(available_pkgs);
939         return 0;
940 }
941
942 static int pkg_mark_provides(pkg_t * pkg)
943 {
944         int provides_count = pkg->provides_count;
945         abstract_pkg_t **provides = pkg->provides;
946         int i;
947         pkg->parent->state_flag |= SF_MARKED;
948         for (i = 0; i < provides_count; i++) {
949                 provides[i]->state_flag |= SF_MARKED;
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;
969         pkg_vec_t *available_pkgs;
970         pkg_t *pkg;
971         int i, j, k, l;
972         int changed, count;
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                         count = ((what_field_type == CONFLICTS)
1023                                  ? pkg->conflicts_count
1024                                  : pkg->pre_depends_count +
1025                                  pkg->depends_count +
1026                                  pkg->recommends_count + pkg->suggests_count);
1027
1028                         /* skip this package if it is already marked */
1029                         if (pkg->parent->state_flag & SF_MARKED)
1030                                 continue;
1031
1032                         for (k = 0; k < count; k++) {
1033                                 cdep = (what_field_type == CONFLICTS)
1034                                     ? &pkg->conflicts[k]
1035                                     : &pkg->depends[k];
1036
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
1116         if (argc > 0) {
1117                 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1118                 const char *rel_str =
1119                     (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1120                 int i;
1121
1122                 pkg_info_preinstall_check();
1123
1124                 if (conf->query_all)
1125                         pkg_hash_fetch_available(available_pkgs);
1126                 else
1127                         pkg_hash_fetch_all_installed(available_pkgs);
1128                 for (i = 0; i < argc; i++) {
1129                         const char *target = argv[i];
1130                         int j;
1131
1132                         opkg_msg(NOTICE, "What %s %s\n", rel_str, target);
1133                         for (j = 0; j < available_pkgs->len; j++) {
1134                                 pkg_t *pkg = available_pkgs->pkgs[j];
1135                                 int k;
1136                                 int count =
1137                                     (what_field_type ==
1138                                      WHATPROVIDES) ? pkg->provides_count : pkg->
1139                                     replaces_count;
1140                                 for (k = 0; k < count; k++) {
1141                                         abstract_pkg_t *apkg =
1142                                             ((what_field_type == WHATPROVIDES)
1143                                              ? pkg->provides[k]
1144                                              : pkg->replaces[k]);
1145                                         if (fnmatch
1146                                             (target, apkg->name,
1147                                              conf->nocase) == 0) {
1148                                                 opkg_msg(NOTICE, "    %s",
1149                                                          pkg->name);
1150                                                 if ((conf->
1151                                                      nocase ? strcasecmp(target,
1152                                                                          apkg->
1153                                                                          name) :
1154                                                      strcmp(target,
1155                                                             apkg->name)) != 0)
1156                                                         opkg_msg(NOTICE,
1157                                                                  "\t%s %s\n",
1158                                                                  rel_str,
1159                                                                  apkg->name);
1160                                                 opkg_message(NOTICE, "\n");
1161                                         }
1162                                 }
1163                         }
1164                 }
1165                 pkg_vec_free(available_pkgs);
1166         }
1167         return 0;
1168 }
1169
1170 static int opkg_whatprovides_cmd(int argc, char **argv)
1171 {
1172         return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv);
1173 }
1174
1175 static int opkg_whatreplaces_cmd(int argc, char **argv)
1176 {
1177         return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv);
1178 }
1179
1180 static int opkg_search_cmd(int argc, char **argv)
1181 {
1182         int i;
1183
1184         pkg_vec_t *installed;
1185         pkg_t *pkg;
1186         str_list_t *installed_files;
1187         str_list_elt_t *iter;
1188         char *installed_file;
1189
1190         if (argc < 1) {
1191                 return -1;
1192         }
1193
1194         installed = pkg_vec_alloc();
1195         pkg_hash_fetch_all_installed(installed);
1196         pkg_vec_sort(installed, pkg_compare_names);
1197
1198         for (i = 0; i < installed->len; i++) {
1199                 pkg = installed->pkgs[i];
1200
1201                 installed_files = pkg_get_installed_files(pkg);
1202
1203                 for (iter = str_list_first(installed_files); iter;
1204                      iter = str_list_next(installed_files, iter)) {
1205                         installed_file = (char *)iter->data;
1206                         if (fnmatch(argv[0], installed_file, conf->nocase) == 0)
1207                                 print_pkg(pkg);
1208                 }
1209
1210                 pkg_free_installed_files(pkg);
1211         }
1212
1213         pkg_vec_free(installed);
1214
1215         return 0;
1216 }
1217
1218 static int opkg_compare_versions_cmd(int argc, char **argv)
1219 {
1220         if (argc == 3) {
1221                 /* this is a bit gross */
1222                 struct pkg p1, p2;
1223                 parse_version(&p1, argv[0]);
1224                 parse_version(&p2, argv[2]);
1225                 return pkg_version_satisfied(&p1, &p2, argv[1]);
1226         } else {
1227                 opkg_msg(ERROR,
1228                          "opkg compare_versions <v1> <op> <v2>\n"
1229                          "<op> is one of <= >= << >> =\n");
1230                 return -1;
1231         }
1232 }
1233
1234 static int opkg_print_architecture_cmd(int argc, char **argv)
1235 {
1236         nv_pair_list_elt_t *l;
1237
1238         list_for_each_entry(l, &conf->arch_list.head, node) {
1239                 nv_pair_t *nv = (nv_pair_t *) l->data;
1240                 printf("arch %s %s\n", nv->name, nv->value);
1241         }
1242         return 0;
1243 }
1244
1245 /* XXX: CLEANUP: The usage strings should be incorporated into this
1246    array for easier maintenance */
1247 static opkg_cmd_t cmds[] = {
1248         {"update", 0, (opkg_cmd_fun_t) opkg_update_cmd,
1249          PFM_DESCRIPTION | PFM_SOURCE},
1250         {"upgrade", 1, (opkg_cmd_fun_t) opkg_upgrade_cmd,
1251          PFM_DESCRIPTION | PFM_SOURCE},
1252         {"list", 0, (opkg_cmd_fun_t) opkg_list_cmd, PFM_SOURCE},
1253         {"list_installed", 0, (opkg_cmd_fun_t) opkg_list_installed_cmd,
1254          PFM_SOURCE},
1255         {"list-installed", 0, (opkg_cmd_fun_t) opkg_list_installed_cmd,
1256          PFM_SOURCE},
1257         {"list_upgradable", 0, (opkg_cmd_fun_t) opkg_list_upgradable_cmd,
1258          PFM_SOURCE},
1259         {"list-upgradable", 0, (opkg_cmd_fun_t) opkg_list_upgradable_cmd,
1260          PFM_SOURCE},
1261         {"list_changed_conffiles", 0,
1262          (opkg_cmd_fun_t) opkg_list_changed_conffiles_cmd, PFM_SOURCE},
1263         {"list-changed-conffiles", 0,
1264          (opkg_cmd_fun_t) opkg_list_changed_conffiles_cmd, PFM_SOURCE},
1265         {"info", 0, (opkg_cmd_fun_t) opkg_info_cmd, 0},
1266         {"flag", 1, (opkg_cmd_fun_t) opkg_flag_cmd,
1267          PFM_DESCRIPTION | PFM_SOURCE},
1268         {"status", 0, (opkg_cmd_fun_t) opkg_status_cmd,
1269          PFM_DESCRIPTION | PFM_SOURCE},
1270         {"install", 1, (opkg_cmd_fun_t) opkg_install_cmd,
1271          PFM_DESCRIPTION | PFM_SOURCE},
1272         {"remove", 1, (opkg_cmd_fun_t) opkg_remove_cmd,
1273          PFM_DESCRIPTION | PFM_SOURCE},
1274         {"configure", 0, (opkg_cmd_fun_t) opkg_configure_cmd,
1275          PFM_DESCRIPTION | PFM_SOURCE},
1276         {"files", 1, (opkg_cmd_fun_t) opkg_files_cmd,
1277          PFM_DESCRIPTION | PFM_SOURCE},
1278         {"search", 1, (opkg_cmd_fun_t) opkg_search_cmd,
1279          PFM_DESCRIPTION | PFM_SOURCE},
1280         {"find", 1, (opkg_cmd_fun_t) opkg_find_cmd, PFM_SOURCE},
1281         {"download", 1, (opkg_cmd_fun_t) opkg_download_cmd,
1282          PFM_DESCRIPTION | PFM_SOURCE},
1283         {"compare_versions", 1, (opkg_cmd_fun_t) opkg_compare_versions_cmd,
1284          PFM_DESCRIPTION | PFM_SOURCE},
1285         {"compare-versions", 1, (opkg_cmd_fun_t) opkg_compare_versions_cmd,
1286          PFM_DESCRIPTION | PFM_SOURCE},
1287         {"print-architecture", 0, (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1288          PFM_DESCRIPTION | PFM_SOURCE},
1289         {"print_architecture", 0, (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1290          PFM_DESCRIPTION | PFM_SOURCE},
1291         {"print-installation-architecture", 0,
1292          (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1293          PFM_DESCRIPTION | PFM_SOURCE},
1294         {"print_installation_architecture", 0,
1295          (opkg_cmd_fun_t) opkg_print_architecture_cmd,
1296          PFM_DESCRIPTION | PFM_SOURCE},
1297         {"depends", 1, (opkg_cmd_fun_t) opkg_depends_cmd,
1298          PFM_DESCRIPTION | PFM_SOURCE},
1299         {"whatdepends", 1, (opkg_cmd_fun_t) opkg_whatdepends_cmd,
1300          PFM_DESCRIPTION | PFM_SOURCE},
1301         {"whatdependsrec", 1, (opkg_cmd_fun_t) opkg_whatdepends_recursively_cmd,
1302          PFM_DESCRIPTION | PFM_SOURCE},
1303         {"whatrecommends", 1, (opkg_cmd_fun_t) opkg_whatrecommends_cmd,
1304          PFM_DESCRIPTION | PFM_SOURCE},
1305         {"whatsuggests", 1, (opkg_cmd_fun_t) opkg_whatsuggests_cmd,
1306          PFM_DESCRIPTION | PFM_SOURCE},
1307         {"whatprovides", 1, (opkg_cmd_fun_t) opkg_whatprovides_cmd,
1308          PFM_DESCRIPTION | PFM_SOURCE},
1309         {"whatreplaces", 1, (opkg_cmd_fun_t) opkg_whatreplaces_cmd,
1310          PFM_DESCRIPTION | PFM_SOURCE},
1311         {"whatconflicts", 1, (opkg_cmd_fun_t) opkg_whatconflicts_cmd,
1312          PFM_DESCRIPTION | PFM_SOURCE},
1313 };
1314
1315 opkg_cmd_t *opkg_cmd_find(const char *name)
1316 {
1317         int i;
1318         opkg_cmd_t *cmd;
1319         int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
1320
1321         for (i = 0; i < num_cmds; i++) {
1322                 cmd = &cmds[i];
1323                 if (strcmp(name, cmd->name) == 0)
1324                         return cmd;
1325         }
1326
1327         return NULL;
1328 }
1329
1330 int opkg_cmd_exec(opkg_cmd_t * cmd, int argc, const char **argv)
1331 {
1332         return (cmd->fun) (argc, argv);
1333 }