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