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