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