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