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