str_list_prev: remove unused function
[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, 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_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, 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
218         sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR,
219                       ctx->oldpath ? ctx->oldpath : PATH_SPEC);
220
221         sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX",
222                       conf->tmp_dir);
223
224         if (mkdtemp(ctx->statedir) == NULL) {
225                 opkg_perror(ERROR, "Failed to make temp dir %s", ctx->statedir);
226
227                 if (ctx->oldpath)
228                         free(ctx->oldpath);
229
230                 free(ctx->statedir);
231                 free(newpath);
232                 free(ctx);
233                 return NULL;
234         }
235
236         setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
237         setenv("PATH", newpath, 1);
238         free(newpath);
239
240         return ctx;
241 }
242
243 static int opkg_finalize_intercepts(opkg_intercept_t ctx)
244 {
245         DIR *dir;
246         int err = 0;
247
248         if (ctx->oldpath) {
249                 setenv("PATH", ctx->oldpath, 1);
250                 free(ctx->oldpath);
251         }
252         else {
253                 unsetenv("PATH");
254         }
255
256         dir = opendir(ctx->statedir);
257         if (dir) {
258                 struct dirent *de;
259                 while (de = readdir(dir), de != NULL) {
260                         char *path;
261
262                         if (de->d_name[0] == '.')
263                                 continue;
264
265                         sprintf_alloc(&path, "%s/%s", ctx->statedir,
266                                       de->d_name);
267                         if (access(path, X_OK) == 0) {
268                                 const char *argv[] = { "/bin/sh", "-c", path, NULL };
269                                 xsystem(argv);
270                         }
271                         free(path);
272                 }
273                 closedir(dir);
274         } else
275                 opkg_perror(ERROR, "Failed to open dir %s", ctx->statedir);
276
277         rm_r(ctx->statedir);
278         free(ctx->statedir);
279         free(ctx);
280
281         return err;
282 }
283
284 /* For package pkg do the following: If it is already visited, return. If not,
285    add it in visited list and recurse to its deps. Finally, add it to ordered
286    list.
287    pkg_vec all contains all available packages in repos.
288    pkg_vec visited contains packages already visited by this function, and is
289    used to end recursion and avoid an infinite loop on graph cycles.
290    pkg_vec ordered will finally contain the ordered set of packages.
291 */
292 static int
293 opkg_recurse_pkgs_in_order(pkg_t * pkg, pkg_vec_t * all,
294                            pkg_vec_t * visited, pkg_vec_t * ordered)
295 {
296         int j, k, l, m;
297         pkg_t *dep;
298         compound_depend_t *compound_depend;
299         depend_t **possible_satisfiers;
300         abstract_pkg_t *abpkg;
301         abstract_pkg_t **dependents;
302
303         /* If it's just an available package, that is, not installed and not even
304            unpacked, skip it */
305         /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED
306            would do here. However, if there is an intermediate node (pkg) that is
307            configured and installed between two unpacked packages, the latter
308            won't be properly reordered, unless all installed/unpacked pkgs are
309            checked */
310         if (pkg->state_status == SS_NOT_INSTALLED)
311                 return 0;
312
313         /* If the  package has already been visited (by this function), skip it */
314         for (j = 0; j < visited->len; j++)
315                 if (!strcmp(visited->pkgs[j]->name, pkg->name)) {
316                         opkg_msg(DEBUG, "pkg %s already visited, skipping.\n",
317                                  pkg->name);
318                         return 0;
319                 }
320
321         pkg_vec_insert(visited, pkg);
322
323         opkg_msg(DEBUG, "pkg %s.\n", pkg->name);
324
325         /* Iterate over all the dependencies of pkg. For each one, find a package
326            that is either installed or unpacked and satisfies this dependency.
327            (there should only be one such package per dependency installed or
328            unpacked). Then recurse to the dependency package */
329         for (compound_depend = pkg_get_ptr(pkg, PKG_DEPENDS); compound_depend && compound_depend->type; compound_depend++) {
330                 possible_satisfiers = compound_depend->possibilities;
331                 for (k = 0; k < compound_depend->possibility_count; k++) {
332                         abpkg = possible_satisfiers[k]->pkg;
333                         dependents = abpkg->provided_by->pkgs;
334                         l = 0;
335                         if (dependents != NULL)
336                                 while (l < abpkg->provided_by->len
337                                        && dependents[l] != NULL) {
338                                         opkg_msg(DEBUG,
339                                                  "Descending on pkg %s.\n",
340                                                  dependents[l]->name);
341
342                                         /* find whether dependent l is installed or unpacked,
343                                          * and then find which package in the list satisfies it */
344                                         for (m = 0; m < all->len; m++) {
345                                                 dep = all->pkgs[m];
346                                                 if (dep->state_status !=
347                                                     SS_NOT_INSTALLED)
348                                                         if (!strcmp
349                                                             (dep->name,
350                                                              dependents[l]->
351                                                              name)) {
352                                                                 opkg_recurse_pkgs_in_order
353                                                                     (dep, all,
354                                                                      visited,
355                                                                      ordered);
356                                                                 /* Stop the outer loop */
357                                                                 l = abpkg->
358                                                                     provided_by->
359                                                                     len;
360                                                                 /* break from the inner loop */
361                                                                 break;
362                                                         }
363                                         }
364                                         l++;
365                                 }
366                 }
367         }
368
369         /* When all recursions from this node down, are over, and all
370            dependencies have been added in proper order in the ordered array, add
371            also the package pkg to ordered array */
372         pkg_vec_insert(ordered, pkg);
373
374         return 0;
375
376 }
377
378 static int opkg_configure_packages(char *pkg_name)
379 {
380         pkg_vec_t *all, *ordered, *visited;
381         int i;
382         pkg_t *pkg;
383         opkg_intercept_t ic;
384         int r, err = 0;
385
386         opkg_msg(INFO, "Configuring unpacked packages.\n");
387
388         all = pkg_vec_alloc();
389
390         pkg_hash_fetch_available(all);
391
392         /* Reorder pkgs in order to be configured according to the Depends: tag
393            order */
394         opkg_msg(INFO, "Reordering packages before configuring them...\n");
395         ordered = pkg_vec_alloc();
396         visited = pkg_vec_alloc();
397         for (i = 0; i < all->len; i++) {
398                 pkg = all->pkgs[i];
399                 opkg_recurse_pkgs_in_order(pkg, all, visited, ordered);
400         }
401
402         ic = opkg_prep_intercepts();
403         if (ic == NULL) {
404                 err = -1;
405                 goto error;
406         }
407
408         for (i = 0; i < ordered->len; i++) {
409                 pkg = ordered->pkgs[i];
410
411                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
412                         continue;
413
414                 if (pkg->state_status == SS_UNPACKED) {
415                         opkg_msg(NOTICE, "Configuring %s.\n", pkg->name);
416                         r = opkg_configure(pkg);
417                         if (r == 0) {
418                                 pkg->state_status = SS_INSTALLED;
419                                 pkg->parent->state_status = SS_INSTALLED;
420                                 pkg->state_flag &= ~SF_PREFER;
421                                 opkg_state_changed++;
422                         } else {
423                                 err = -1;
424                         }
425                 }
426         }
427
428         if (opkg_finalize_intercepts(ic))
429                 err = -1;
430
431 error:
432         pkg_vec_free(all);
433         pkg_vec_free(ordered);
434         pkg_vec_free(visited);
435
436         return err;
437 }
438
439 static int opkg_remove_cmd(int argc, char **argv);
440
441 static int opkg_install_cmd(int argc, char **argv)
442 {
443         int i;
444         char *arg;
445         int err = 0;
446
447         signal(SIGINT, sigint_handler);
448
449         /*
450          * Now scan through package names and install
451          */
452         for (i = 0; i < argc; i++) {
453                 arg = argv[i];
454
455                 opkg_msg(DEBUG2, "%s\n", arg);
456                 if (opkg_prepare_url_for_install(arg, &argv[i]))
457                         return -1;
458         }
459
460         pkg_hash_load_package_details();
461         pkg_hash_load_status_files();
462
463         if (conf->force_reinstall) {
464                 int saved_force_depends = conf->force_depends;
465                 conf->force_depends = 1;
466                 (void)opkg_remove_cmd(argc, argv);
467                 conf->force_depends = saved_force_depends;
468                 conf->force_reinstall = 0;
469         }
470
471         pkg_info_preinstall_check();
472
473         for (i = 0; i < argc; i++) {
474                 arg = argv[i];
475                 if (opkg_install_by_name(arg)) {
476                         opkg_msg(ERROR, "Cannot install package %s.\n", arg);
477                         err = -1;
478                 }
479         }
480
481         if (opkg_configure_packages(NULL))
482                 err = -1;
483
484         write_status_files_if_changed();
485
486         return err;
487 }
488
489 static int opkg_upgrade_cmd(int argc, char **argv)
490 {
491         int i;
492         pkg_t *pkg;
493         int err = 0;
494
495         signal(SIGINT, sigint_handler);
496
497         if (argc) {
498                 for (i = 0; i < argc; i++) {
499                         char *arg = argv[i];
500
501                         if (opkg_prepare_url_for_install(arg, &arg))
502                                 return -1;
503                 }
504                 pkg_info_preinstall_check();
505
506                 for (i = 0; i < argc; i++) {
507                         char *arg = argv[i];
508                         if (conf->restrict_to_default_dest) {
509                                 pkg =
510                                     pkg_hash_fetch_installed_by_name_dest(argv
511                                                                           [i],
512                                                                           conf->
513                                                                           default_dest);
514                                 if (pkg == NULL) {
515                                         opkg_msg(NOTICE,
516                                                  "Package %s not installed in %s.\n",
517                                                  argv[i],
518                                                  conf->default_dest->name);
519                                         continue;
520                                 }
521                         } else {
522                                 pkg = pkg_hash_fetch_installed_by_name(argv[i]);
523                         }
524                         if (pkg) {
525                                 if (opkg_upgrade_pkg(pkg))
526                                         err = -1;
527                         } else {
528                                 if (opkg_install_by_name(arg))
529                                         err = -1;
530                         }
531                 }
532         }
533
534         if (opkg_configure_packages(NULL))
535                 err = -1;
536
537         write_status_files_if_changed();
538
539         return err;
540 }
541
542 static int opkg_download_cmd(int argc, char **argv)
543 {
544         int i, err = 0;
545         char *arg;
546         pkg_t *pkg;
547
548         pkg_info_preinstall_check();
549         for (i = 0; i < argc; i++) {
550                 arg = argv[i];
551
552                 pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg);
553                 if (pkg == NULL) {
554                         opkg_msg(ERROR, "Cannot find package %s.\n", arg);
555                         continue;
556                 }
557
558                 if (opkg_download_pkg(pkg, "."))
559                         err = -1;
560
561                 if (err) {
562                         opkg_msg(ERROR, "Failed to download %s.\n", pkg->name);
563                 } else {
564                         opkg_msg(NOTICE, "Downloaded %s as %s.\n",
565                                  pkg->name, pkg_get_string(pkg, PKG_LOCAL_FILENAME));
566                 }
567         }
568
569         return err;
570 }
571
572 static int opkg_list_find_cmd(int argc, char **argv, int use_desc)
573 {
574         int i;
575         pkg_vec_t *available;
576         pkg_t *pkg;
577         char *pkg_name = NULL;
578         char *description;
579
580         if (argc > 0) {
581                 pkg_name = argv[0];
582         }
583         available = pkg_vec_alloc();
584         pkg_hash_fetch_available(available);
585         pkg_vec_sort(available, pkg_compare_names);
586         for (i = 0; i < available->len; i++) {
587                 pkg = available->pkgs[i];
588                 description = use_desc ? pkg_get_string(pkg, PKG_DESCRIPTION) : NULL;
589                 /* if we have package name or pattern and pkg does not match, then skip it */
590                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase) &&
591                     (!use_desc || !description
592                      || fnmatch(pkg_name, description, conf->nocase)))
593                         continue;
594                 print_pkg(pkg);
595         }
596         pkg_vec_free(available);
597
598         return 0;
599 }
600
601 static int opkg_list_cmd(int argc, char **argv)
602 {
603         return opkg_list_find_cmd(argc, argv, 0);
604 }
605
606 static int opkg_find_cmd(int argc, char **argv)
607 {
608         return opkg_list_find_cmd(argc, argv, 1);
609 }
610
611 static int opkg_list_installed_cmd(int argc, char **argv)
612 {
613         int i;
614         pkg_vec_t *available;
615         pkg_t *pkg;
616         char *pkg_name = NULL;
617
618         if (argc > 0) {
619                 pkg_name = argv[0];
620         }
621         available = pkg_vec_alloc();
622         pkg_hash_fetch_all_installed(available);
623         pkg_vec_sort(available, pkg_compare_names);
624         for (i = 0; i < available->len; i++) {
625                 pkg = available->pkgs[i];
626                 /* if we have package name or pattern and pkg does not match, then skip it */
627                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
628                         continue;
629                 print_pkg(pkg);
630         }
631
632         pkg_vec_free(available);
633
634         return 0;
635 }
636
637 static int opkg_list_changed_conffiles_cmd(int argc, char **argv)
638 {
639         int i;
640         pkg_vec_t *available;
641         pkg_t *pkg;
642         char *pkg_name = NULL;
643         conffile_list_elt_t *iter;
644         conffile_list_t *cl;
645         conffile_t *cf;
646
647         if (argc > 0) {
648                 pkg_name = argv[0];
649         }
650         available = pkg_vec_alloc();
651         pkg_hash_fetch_all_installed(available);
652         pkg_vec_sort(available, pkg_compare_names);
653         for (i = 0; i < available->len; i++) {
654                 pkg = available->pkgs[i];
655                 cl = pkg_get_ptr(pkg, PKG_CONFFILES);
656                 /* if we have package name or pattern and pkg does not match, then skip it */
657                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase))
658                         continue;
659                 if (!cl || nv_pair_list_empty(cl))
660                         continue;
661                 for (iter = nv_pair_list_first(cl); iter;
662                      iter = nv_pair_list_next(cl, iter)) {
663                         cf = (conffile_t *) iter->data;
664                         if (cf->name && cf->value
665                             && conffile_has_been_modified(cf))
666                                 printf("%s\n", cf->name);
667                 }
668         }
669         pkg_vec_free(available);
670         return 0;
671 }
672
673 static int opkg_list_upgradable_cmd(int argc, char **argv)
674 {
675         struct active_list *head = prepare_upgrade_list();
676         struct active_list *node = NULL;
677         pkg_t *_old_pkg, *_new_pkg;
678         char *old_v, *new_v;
679         for (node = active_list_next(head, head); node;
680              node = active_list_next(head, node)) {
681                 _old_pkg = node->pkg;
682                 _new_pkg =
683                     pkg_hash_fetch_best_installation_candidate_by_name
684                     (_old_pkg->name);
685                 if (_new_pkg == NULL)
686                         continue;
687                 old_v = pkg_version_str_alloc(_old_pkg);
688                 new_v = pkg_version_str_alloc(_new_pkg);
689                 printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
690                 free(old_v);
691                 free(new_v);
692         }
693         active_list_head_delete(head);
694         return 0;
695 }
696
697 static int opkg_info_status_cmd(int argc, char **argv, int installed_only)
698 {
699         int i;
700         pkg_vec_t *available;
701         pkg_t *pkg;
702         char *pkg_name = NULL;
703         conffile_list_t *cl;
704
705         if (argc > 0) {
706                 pkg_name = argv[0];
707         }
708
709         available = pkg_vec_alloc();
710         if (installed_only)
711                 pkg_hash_fetch_all_installed(available);
712         else
713                 pkg_hash_fetch_available(available);
714
715         for (i = 0; i < available->len; i++) {
716                 pkg = available->pkgs[i];
717                 if (pkg_name && fnmatch(pkg_name, pkg->name, conf->nocase)) {
718                         continue;
719                 }
720
721                 pkg_formatted_info(stdout, pkg);
722
723                 cl = pkg_get_ptr(pkg, PKG_CONFFILES);
724
725                 if (conf->verbosity >= NOTICE && cl) {
726                         conffile_list_elt_t *iter;
727                         for (iter = nv_pair_list_first(cl); iter;
728                              iter = nv_pair_list_next(cl, iter)) {
729                                 conffile_t *cf = (conffile_t *) iter->data;
730                                 int modified = conffile_has_been_modified(cf);
731                                 if (cf->value)
732                                         opkg_msg(INFO,
733                                                  "conffile=%s md5sum=%s modified=%d.\n",
734                                                  cf->name, cf->value, modified);
735                         }
736                 }
737         }
738         pkg_vec_free(available);
739
740         return 0;
741 }
742
743 static int opkg_info_cmd(int argc, char **argv)
744 {
745         return opkg_info_status_cmd(argc, argv, 0);
746 }
747
748 static int opkg_status_cmd(int argc, char **argv)
749 {
750         return opkg_info_status_cmd(argc, argv, 1);
751 }
752
753 static int opkg_configure_cmd(int argc, char **argv)
754 {
755         int err;
756         char *pkg_name = NULL;
757
758         if (argc > 0)
759                 pkg_name = argv[0];
760
761         err = opkg_configure_packages(pkg_name);
762
763         write_status_files_if_changed();
764
765         return err;
766 }
767
768 static int opkg_remove_cmd(int argc, char **argv)
769 {
770         int i, a, done, err = 0;
771         pkg_t *pkg;
772         pkg_t *pkg_to_remove;
773         pkg_vec_t *available;
774
775         done = 0;
776
777         signal(SIGINT, sigint_handler);
778
779         pkg_info_preinstall_check();
780
781         available = pkg_vec_alloc();
782         pkg_hash_fetch_all_installed(available);
783
784         for (i = 0; i < argc; i++) {
785                 for (a = 0; a < available->len; a++) {
786                         pkg = available->pkgs[a];
787                         if (fnmatch(argv[i], pkg->name, conf->nocase)) {
788                                 continue;
789                         }
790                         if (conf->restrict_to_default_dest) {
791                                 pkg_to_remove =
792                                     pkg_hash_fetch_installed_by_name_dest(pkg->
793                                                                           name,
794                                                                           conf->
795                                                                           default_dest);
796                         } else {
797                                 pkg_to_remove =
798                                     pkg_hash_fetch_installed_by_name(pkg->name);
799                         }
800
801                         if (pkg_to_remove == NULL) {
802                                 opkg_msg(ERROR,
803                                          "Package %s is not installed.\n",
804                                          pkg->name);
805                                 continue;
806                         }
807                         if (pkg->state_status == SS_NOT_INSTALLED) {
808                                 opkg_msg(ERROR, "Package %s not installed.\n",
809                                          pkg->name);
810                                 continue;
811                         }
812
813                         if (opkg_remove_pkg(pkg_to_remove, 0))
814                                 err = -1;
815                         else
816                                 done = 1;
817                 }
818         }
819
820         pkg_vec_free(available);
821
822         if (done == 0)
823                 opkg_msg(NOTICE, "No packages removed.\n");
824
825         write_status_files_if_changed();
826         return err;
827 }
828
829 static int opkg_flag_cmd(int argc, char **argv)
830 {
831         int i;
832         pkg_t *pkg;
833         const char *flags = argv[0];
834
835         signal(SIGINT, sigint_handler);
836
837         for (i = 1; i < argc; i++) {
838                 if (conf->restrict_to_default_dest) {
839                         pkg = pkg_hash_fetch_installed_by_name_dest(argv[i],
840                                                                     conf->
841                                                                     default_dest);
842                 } else {
843                         pkg = pkg_hash_fetch_installed_by_name(argv[i]);
844                 }
845
846                 if (pkg == NULL) {
847                         opkg_msg(ERROR, "Package %s is not installed.\n",
848                                  argv[i]);
849                         continue;
850                 }
851                 if ((strcmp(flags, "hold") == 0)
852                     || (strcmp(flags, "noprune") == 0)
853                     || (strcmp(flags, "user") == 0)
854                     || (strcmp(flags, "ok") == 0)) {
855                         pkg->state_flag = pkg_state_flag_from_str(flags);
856                 }
857
858                 /*
859                  * Useful if a package is installed in an offline_root, and
860                  * should be configured by opkg-cl configure at a later date.
861                  */
862                 if ((strcmp(flags, "installed") == 0)
863                     || (strcmp(flags, "unpacked") == 0)) {
864                         pkg->state_status = pkg_state_status_from_str(flags);
865                 }
866
867                 opkg_state_changed++;
868                 opkg_msg(NOTICE, "Setting flags for package %s to %s.\n",
869                          pkg->name, flags);
870         }
871
872         write_status_files_if_changed();
873         return 0;
874 }
875
876 static int opkg_files_cmd(int argc, char **argv)
877 {
878         pkg_t *pkg;
879         str_list_t *files;
880         str_list_elt_t *iter;
881         char *pkg_version;
882
883         if (argc < 1) {
884                 return -1;
885         }
886
887         pkg = pkg_hash_fetch_installed_by_name(argv[0]);
888         if (pkg == NULL) {
889                 opkg_msg(ERROR, "Package %s not installed.\n", argv[0]);
890                 return 0;
891         }
892
893         files = pkg_get_installed_files(pkg);
894         pkg_version = pkg_version_str_alloc(pkg);
895
896         printf
897             ("Package %s (%s) is installed on %s and has the following files:\n",
898              pkg->name, pkg_version, pkg->dest->name);
899
900         for (iter = str_list_first(files); iter;
901              iter = str_list_next(files, iter))
902                 printf("%s\n", (char *)iter->data);
903
904         free(pkg_version);
905         pkg_free_installed_files(pkg);
906
907         return 0;
908 }
909
910 static int opkg_depends_cmd(int argc, char **argv)
911 {
912         int i, j, k;
913         pkg_vec_t *available_pkgs;
914         compound_depend_t *cdep;
915         pkg_t *pkg;
916         char *str;
917
918         pkg_info_preinstall_check();
919
920         available_pkgs = pkg_vec_alloc();
921         if (conf->query_all)
922                 pkg_hash_fetch_available(available_pkgs);
923         else
924                 pkg_hash_fetch_all_installed(available_pkgs);
925
926         for (i = 0; i < argc; i++) {
927                 for (j = 0; j < available_pkgs->len; j++) {
928                         pkg = available_pkgs->pkgs[j];
929
930                         if (fnmatch(argv[i], pkg->name, conf->nocase) != 0)
931                                 continue;
932
933                         opkg_msg(NOTICE, "%s depends on:\n", pkg->name);
934
935                         for (k = 0, cdep = pkg_get_ptr(pkg, PKG_DEPENDS); cdep && cdep->type; k++, cdep++) {
936                                 if (cdep->type != DEPEND)
937                                         continue;
938
939                                 str = pkg_depend_str(pkg, k);
940                                 opkg_msg(NOTICE, "\t%s\n", str);
941                                 free(str);
942                         }
943
944                 }
945         }
946
947         pkg_vec_free(available_pkgs);
948         return 0;
949 }
950
951 static int pkg_mark_provides(pkg_t * pkg)
952 {
953         abstract_pkg_t **provider = pkg_get_ptr(pkg, PKG_PROVIDES);
954
955         pkg->parent->state_flag |= SF_MARKED;
956
957         while (provider && *provider) {
958                 (*provider)->state_flag |= SF_MARKED;
959                 provider++;
960         }
961
962         return 0;
963 }
964
965 enum what_field_type {
966         WHATDEPENDS,
967         WHATCONFLICTS,
968         WHATPROVIDES,
969         WHATREPLACES,
970         WHATRECOMMENDS,
971         WHATSUGGESTS
972 };
973
974 static int
975 opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive,
976                                 int argc, char **argv)
977 {
978         depend_t *possibility;
979         compound_depend_t *cdep, *deps;
980         pkg_vec_t *available_pkgs;
981         pkg_t *pkg;
982         int i, j, l;
983         int changed;
984         const char *rel_str = NULL;
985         char *ver;
986
987         switch (what_field_type) {
988         case DEPEND:
989                 rel_str = "depends on";
990                 break;
991         case CONFLICTS:
992                 rel_str = "conflicts with";
993                 break;
994         case SUGGEST:
995                 rel_str = "suggests";
996                 break;
997         case RECOMMEND:
998                 rel_str = "recommends";
999                 break;
1000         default:
1001                 return -1;
1002         }
1003
1004         available_pkgs = pkg_vec_alloc();
1005
1006         if (conf->query_all)
1007                 pkg_hash_fetch_available(available_pkgs);
1008         else
1009                 pkg_hash_fetch_all_installed(available_pkgs);
1010
1011         /* mark the root set */
1012         pkg_vec_clear_marks(available_pkgs);
1013         opkg_msg(NOTICE, "Root set:\n");
1014         for (i = 0; i < argc; i++)
1015                 pkg_vec_mark_if_matches(available_pkgs, argv[i]);
1016
1017         for (i = 0; i < available_pkgs->len; i++) {
1018                 pkg = available_pkgs->pkgs[i];
1019                 if (pkg->state_flag & SF_MARKED) {
1020                         /* mark the parent (abstract) package */
1021                         pkg_mark_provides(pkg);
1022                         opkg_msg(NOTICE, "  %s\n", pkg->name);
1023                 }
1024         }
1025
1026         opkg_msg(NOTICE, "What %s root set\n", rel_str);
1027         do {
1028                 changed = 0;
1029
1030                 for (j = 0; j < available_pkgs->len; j++) {
1031
1032                         pkg = available_pkgs->pkgs[j];
1033                         /*
1034                         count = ((what_field_type == CONFLICTS)
1035                                  ? pkg->conflicts_count
1036                                  : pkg->pre_depends_count +
1037                                  pkg->depends_count +
1038                                  pkg->recommends_count + pkg->suggests_count);
1039                                  */
1040
1041                         /* skip this package if it is already marked */
1042                         if (pkg->parent->state_flag & SF_MARKED)
1043                                 continue;
1044
1045                         deps = pkg_get_ptr(pkg, (what_field_type == CONFLICTS) ? PKG_CONFLICTS : PKG_DEPENDS);
1046
1047                         for (cdep = deps; cdep && cdep->type; cdep++) {
1048                                 if (what_field_type != cdep->type)
1049                                         continue;
1050
1051                                 for (l = 0; l < cdep->possibility_count; l++) {
1052                                         possibility = cdep->possibilities[l];
1053
1054                                         if ((possibility->pkg->state_flag
1055                                              & SF_MARKED)
1056                                             != SF_MARKED)
1057                                                 continue;
1058
1059                                         /* mark the depending package so we
1060                                          * won't visit it again */
1061                                         pkg->state_flag |= SF_MARKED;
1062                                         pkg_mark_provides(pkg);
1063                                         changed++;
1064
1065                                         ver = pkg_version_str_alloc(pkg);
1066                                         opkg_msg(NOTICE, "\t%s %s\t%s %s",
1067                                                  pkg->name,
1068                                                  ver,
1069                                                  rel_str,
1070                                                  possibility->pkg->name);
1071                                         free(ver);
1072                                         if (possibility->version) {
1073                                                 opkg_msg(NOTICE, " (%s%s)",
1074                                                          constraint_to_str
1075                                                          (possibility->
1076                                                           constraint),
1077                                                          possibility->version);
1078                                         }
1079                                         if (!pkg_dependence_satisfiable
1080                                             (possibility))
1081                                                 opkg_msg(NOTICE,
1082                                                          " unsatisfiable");
1083                                         opkg_message(NOTICE, "\n");
1084                                         goto next_package;
1085                                 }
1086                         }
1087 next_package:
1088                         ;
1089                 }
1090         } while (changed && recursive);
1091
1092         pkg_vec_free(available_pkgs);
1093
1094         return 0;
1095 }
1096
1097 static int opkg_whatdepends_recursively_cmd(int argc, char **argv)
1098 {
1099         return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv);
1100 }
1101
1102 static int opkg_whatdepends_cmd(int argc, char **argv)
1103 {
1104         return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv);
1105 }
1106
1107 static int opkg_whatsuggests_cmd(int argc, char **argv)
1108 {
1109         return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv);
1110 }
1111
1112 static int opkg_whatrecommends_cmd(int argc, char **argv)
1113 {
1114         return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv);
1115 }
1116
1117 static int opkg_whatconflicts_cmd(int argc, char **argv)
1118 {
1119         return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv);
1120 }
1121
1122 static int
1123 opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc,
1124                                 char **argv)
1125 {
1126         abstract_pkg_t *apkg, **abpkgs;
1127
1128         if (argc > 0) {
1129                 pkg_vec_t *available_pkgs = pkg_vec_alloc();
1130                 const char *rel_str =
1131                     (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1132                 int i;
1133
1134                 pkg_info_preinstall_check();
1135
1136                 if (conf->query_all)
1137                         pkg_hash_fetch_available(available_pkgs);
1138                 else
1139                         pkg_hash_fetch_all_installed(available_pkgs);
1140                 for (i = 0; i < argc; i++) {
1141                         const char *target = argv[i];
1142                         int j;
1143
1144                         opkg_msg(NOTICE, "What %s %s\n", rel_str, target);
1145                         for (j = 0; j < available_pkgs->len; j++) {
1146                                 pkg_t *pkg = available_pkgs->pkgs[j];
1147                                 abpkgs = pkg_get_ptr(pkg, (what_field_type == WHATPROVIDES) ? PKG_PROVIDES : PKG_REPLACES);
1148
1149                                 while (abpkgs && *abpkgs) {
1150                                         apkg = *abpkgs++;
1151
1152                                         if (fnmatch(target, apkg->name, conf->nocase))
1153                                                 continue;
1154
1155                                         opkg_msg(NOTICE, "    %s", pkg->name);
1156
1157                                         if ((conf->nocase ? strcasecmp(target, apkg->name)
1158                                             : strcmp(target, apkg->name)))
1159                                                 opkg_msg(NOTICE, "\t%s %s\n", rel_str, apkg->name);
1160
1161                                         opkg_message(NOTICE, "\n");
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 }