Use ordered list when configuring packages.
[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                     if (!err)
409                         err = r;
410                }
411           }
412      }
413
414      r = opkg_finalize_intercepts (ic);
415      if (r && !err)
416          err = r;
417
418 error:
419      pkg_vec_free(all);
420      pkg_vec_free(ordered);
421      pkg_vec_free(visited);
422
423      return err;
424 }
425
426 static int
427 opkg_install_cmd(int argc, char **argv)
428 {
429      int i, r;
430      char *arg;
431      int err=0;
432
433      signal(SIGINT, sigint_handler);
434
435      /*
436       * Now scan through package names and install
437       */
438      for (i=0; i < argc; i++) {
439           arg = argv[i];
440
441           opkg_msg(DEBUG2, "%s\n", arg);
442           err = opkg_prepare_url_for_install(arg, &argv[i]);
443           if (err)
444               return err;
445      }
446      pkg_info_preinstall_check();
447
448      for (i=0; i < argc; i++) {
449           arg = argv[i];
450           err = opkg_install_by_name(arg);
451           if (err) {
452                opkg_msg(ERROR, "Cannot install package %s.\n", arg);
453           }
454      }
455
456      r = opkg_configure_packages(NULL);
457      if (!err)
458           err = r;
459
460      write_status_files_if_changed();
461
462      return err;
463 }
464
465 static int
466 opkg_upgrade_cmd(int argc, char **argv)
467 {
468      int i, r;
469      pkg_t *pkg;
470      int err;
471
472      signal(SIGINT, sigint_handler);
473
474      if (argc) {
475           for (i=0; i < argc; i++) {
476                char *arg = argv[i];
477
478                err = opkg_prepare_url_for_install(arg, &arg);
479                if (err)
480                    return err;
481           }
482           pkg_info_preinstall_check();
483
484           for (i=0; i < argc; i++) {
485                char *arg = argv[i];
486                if (conf->restrict_to_default_dest) {
487                     pkg = pkg_hash_fetch_installed_by_name_dest(argv[i],
488                                                         conf->default_dest);
489                     if (pkg == NULL) {
490                          opkg_msg(NOTICE, "Package %s not installed in %s.\n",
491                                       argv[i], conf->default_dest->name);
492                          continue;
493                     }
494                } else {
495                     pkg = pkg_hash_fetch_installed_by_name(argv[i]);
496                }
497                if (pkg)
498                     opkg_upgrade_pkg(pkg);
499                else {
500                     opkg_install_by_name(arg);
501                }
502           }
503      } else {
504           pkg_vec_t *installed = pkg_vec_alloc();
505
506           pkg_info_preinstall_check();
507
508           pkg_hash_fetch_all_installed(installed);
509           for (i = 0; i < installed->len; i++) {
510                pkg = installed->pkgs[i];
511                opkg_upgrade_pkg(pkg);
512           }
513           pkg_vec_free(installed);
514      }
515
516      r = opkg_configure_packages(NULL);
517      if (!err)
518           err = r;
519
520      write_status_files_if_changed();
521
522      return 0;
523 }
524
525 static int
526 opkg_download_cmd(int argc, char **argv)
527 {
528      int i, err = 0;
529      char *arg;
530      pkg_t *pkg;
531
532      pkg_info_preinstall_check();
533      for (i = 0; i < argc; i++) {
534           arg = argv[i];
535
536           pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg);
537           if (pkg == NULL) {
538                opkg_msg(ERROR, "Cannot find package %s.\n", arg);
539                continue;
540           }
541
542           err = opkg_download_pkg(pkg, ".");
543
544           if (err) {
545                opkg_msg(ERROR, "Failed to download %s.\n", pkg->name);
546           } else {
547                opkg_msg(NOTICE, "Downloaded %s as %s.\n",
548                             pkg->name, pkg->local_filename);
549           }
550      }
551
552      return err;
553 }
554
555
556 static int
557 opkg_list_cmd(int argc, char **argv)
558 {
559      int i;
560      pkg_vec_t *available;
561      pkg_t *pkg;
562      char *pkg_name = NULL;
563
564      if (argc > 0) {
565           pkg_name = argv[0];
566      }
567      available = pkg_vec_alloc();
568      pkg_hash_fetch_available(available);
569      pkg_vec_sort(available, pkg_compare_names);
570      for (i=0; i < available->len; i++) {
571           pkg = available->pkgs[i];
572           /* if we have package name or pattern and pkg does not match, then skip it */
573           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
574                continue;
575           print_pkg(pkg);
576      }
577      pkg_vec_free(available);
578
579      return 0;
580 }
581
582
583 static int
584 opkg_list_installed_cmd(int argc, char **argv)
585 {
586      int i ;
587      pkg_vec_t *available;
588      pkg_t *pkg;
589      char *pkg_name = NULL;
590
591      if (argc > 0) {
592           pkg_name = argv[0];
593      }
594      available = pkg_vec_alloc();
595      pkg_hash_fetch_all_installed(available);
596      pkg_vec_sort(available, pkg_compare_names);
597      for (i=0; i < available->len; i++) {
598           pkg = available->pkgs[i];
599           /* if we have package name or pattern and pkg does not match, then skip it */
600           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
601                continue;
602           print_pkg(pkg);
603      }
604
605      pkg_vec_free(available);
606
607      return 0;
608 }
609
610 static int
611 opkg_list_upgradable_cmd(int argc, char **argv)
612 {
613     struct active_list *head = prepare_upgrade_list();
614     struct active_list *node=NULL;
615     pkg_t *_old_pkg, *_new_pkg;
616     char *old_v, *new_v;
617     for (node = active_list_next(head, head); node;node = active_list_next(head,node)) {
618         _old_pkg = list_entry(node, pkg_t, list);
619         _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(_old_pkg->name);
620         if (_new_pkg == NULL)
621                 continue;
622         old_v = pkg_version_str_alloc(_old_pkg);
623         new_v = pkg_version_str_alloc(_new_pkg);
624         printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
625         free(old_v);
626         free(new_v);
627     }
628     active_list_head_delete(head);
629     return 0;
630 }
631
632 static int
633 opkg_info_status_cmd(int argc, char **argv, int installed_only)
634 {
635      int i;
636      pkg_vec_t *available;
637      pkg_t *pkg;
638      char *pkg_name = NULL;
639
640      if (argc > 0) {
641           pkg_name = argv[0];
642      }
643
644      available = pkg_vec_alloc();
645      if (installed_only)
646           pkg_hash_fetch_all_installed(available);
647      else
648           pkg_hash_fetch_available(available);
649
650      for (i=0; i < available->len; i++) {
651           pkg = available->pkgs[i];
652           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
653                continue;
654           }
655
656           pkg_formatted_info(stdout, pkg);
657
658           if (conf->verbosity >= NOTICE) {
659                conffile_list_elt_t *iter;
660                for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
661                     conffile_t *cf = (conffile_t *)iter->data;
662                     int modified = conffile_has_been_modified(cf);
663                     if (cf->value)
664                         opkg_msg(INFO, "conffile=%s md5sum=%s modified=%d.\n",
665                                  cf->name, cf->value, modified);
666                }
667           }
668      }
669      pkg_vec_free(available);
670
671      return 0;
672 }
673
674 static int
675 opkg_info_cmd(int argc, char **argv)
676 {
677      return opkg_info_status_cmd(argc, argv, 0);
678 }
679
680 static int
681 opkg_status_cmd(int argc, char **argv)
682 {
683      return opkg_info_status_cmd(argc, argv, 1);
684 }
685
686 static int
687 opkg_configure_cmd(int argc, char **argv)
688 {
689         int err;
690         char *pkg_name = NULL;
691
692         if (argc > 0)
693                 pkg_name = argv[0];
694
695         err = opkg_configure_packages(pkg_name);
696
697         write_status_files_if_changed();
698
699         return err;
700 }
701
702 static int
703 opkg_remove_cmd(int argc, char **argv)
704 {
705      int i, a, done, r, err = 0;
706      pkg_t *pkg;
707      pkg_t *pkg_to_remove;
708      pkg_vec_t *available;
709
710      done = 0;
711
712      signal(SIGINT, sigint_handler);
713
714      pkg_info_preinstall_check();
715
716      available = pkg_vec_alloc();
717      pkg_hash_fetch_all_installed(available);
718
719      for (i=0; i<argc; i++) {
720         for (a=0; a<available->len; a++) {
721             pkg = available->pkgs[a];
722             if (fnmatch(argv[i], pkg->name, 0)) {
723                continue;
724             }
725             if (conf->restrict_to_default_dest) {
726                  pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(
727                                         pkg->name,
728                                         conf->default_dest);
729             } else {
730                  pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name);
731             }
732         
733             if (pkg_to_remove == NULL) {
734                  opkg_msg(ERROR, "Package %s is not installed.\n", pkg->name);
735                  continue;
736             }
737             if (pkg->state_status == SS_NOT_INSTALLED) {    // Added the control, so every already removed package could be skipped
738                  opkg_msg(ERROR, "Package %s not installed.\n", pkg->name);
739                  continue;
740             }
741             r = opkg_remove_pkg(pkg_to_remove, 0);
742             if (!err)
743                  err = r;
744
745             done = 1;
746         }
747      }
748
749      pkg_vec_free(available);
750
751      if (done == 0)
752         opkg_msg(NOTICE, "No packages removed.\n");
753
754      write_status_files_if_changed();
755      return err;
756 }
757
758 static int
759 opkg_flag_cmd(int argc, char **argv)
760 {
761      int i;
762      pkg_t *pkg;
763      const char *flags = argv[0];
764     
765      signal(SIGINT, sigint_handler);
766
767      for (i=1; i < argc; i++) {
768           if (conf->restrict_to_default_dest) {
769                pkg = pkg_hash_fetch_installed_by_name_dest(argv[i],
770                                                            conf->default_dest);
771           } else {
772                pkg = pkg_hash_fetch_installed_by_name(argv[i]);
773           }
774
775           if (pkg == NULL) {
776                opkg_msg(ERROR, "Package %s is not installed.\n", argv[i]);
777                continue;
778           }
779           if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
780               ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
781               pkg->state_flag = pkg_state_flag_from_str(flags);
782           }
783
784           /* 
785            * Useful if a package is installed in an offline_root, and
786            * should be configured by opkg-cl configure at a later date.
787            */
788           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
789               pkg->state_status = pkg_state_status_from_str(flags);
790           }
791
792           opkg_state_changed++;
793           opkg_msg(NOTICE, "Setting flags for package %s to %s.\n",
794                        pkg->name, flags);
795      }
796
797      write_status_files_if_changed();
798      return 0;
799 }
800
801 static int
802 opkg_files_cmd(int argc, char **argv)
803 {
804      pkg_t *pkg;
805      str_list_t *files;
806      str_list_elt_t *iter;
807      char *pkg_version;
808
809      if (argc < 1) {
810           return -1;
811      }
812
813      pkg = pkg_hash_fetch_installed_by_name(argv[0]);
814      if (pkg == NULL) {
815           opkg_msg(ERROR, "Package %s not installed.\n", argv[0]);
816           return 0;
817      }
818
819      files = pkg_get_installed_files(pkg);
820      pkg_version = pkg_version_str_alloc(pkg);
821
822      printf("Package %s (%s) is installed on %s and has the following files:\n",
823                 pkg->name, pkg_version, pkg->dest->name);
824
825      for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
826           printf("%s\n", (char *)iter->data);
827
828      free(pkg_version);
829      pkg_free_installed_files(pkg);
830
831      return 0;
832 }
833
834 static int
835 opkg_depends_cmd(int argc, char **argv)
836 {
837         int i, j, k;
838         int depends_count;
839         pkg_vec_t *available_pkgs;
840         compound_depend_t *cdep;
841         pkg_t *pkg;
842         char *str;
843
844         pkg_info_preinstall_check();
845
846         available_pkgs = pkg_vec_alloc();
847         if (conf->query_all)
848                pkg_hash_fetch_available(available_pkgs);
849         else
850                pkg_hash_fetch_all_installed(available_pkgs);
851
852         for (i=0; i<argc; i++) {
853                 for (j=0; j<available_pkgs->len; j++) {
854                         pkg = available_pkgs->pkgs[j];
855
856                         if (fnmatch(argv[i], pkg->name, 0) != 0)
857                                 continue;
858
859                         depends_count = pkg->depends_count +
860                                         pkg->pre_depends_count +
861                                         pkg->recommends_count +
862                                         pkg->suggests_count;
863
864                         opkg_msg(NOTICE, "%s depends on:\n", pkg->name);
865
866                         for (k=0; k<depends_count; k++) {
867                                 cdep = &pkg->depends[k];
868
869                                 if (cdep->type != DEPEND)
870                                       continue;
871
872                                 str = pkg_depend_str(pkg, k);
873                                 opkg_msg(NOTICE, "\t%s\n", str);
874                                 free(str);
875                         }
876
877                }
878         }
879
880         pkg_vec_free(available_pkgs);
881         return 0;
882 }
883
884 static int
885 pkg_mark_provides(pkg_t *pkg)
886 {
887      int provides_count = pkg->provides_count;
888      abstract_pkg_t **provides = pkg->provides;
889      int i;
890      pkg->parent->state_flag |= SF_MARKED;
891      for (i = 0; i < provides_count; i++) {
892           provides[i]->state_flag |= SF_MARKED;
893      }
894      return 0;
895 }
896
897 enum what_field_type {
898   WHATDEPENDS,
899   WHATCONFLICTS,
900   WHATPROVIDES,
901   WHATREPLACES,
902   WHATRECOMMENDS,
903   WHATSUGGESTS
904 };
905
906 static int
907 opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive, int argc, char **argv)
908 {
909         depend_t *possibility;
910         compound_depend_t *cdep;
911         pkg_vec_t *available_pkgs;
912         pkg_t *pkg;
913         int i, j, k, l;
914         int changed, count;
915         const char *rel_str = NULL;
916         char *ver;
917
918         switch (what_field_type) {
919         case DEPEND: rel_str = "depends on"; break;
920         case CONFLICTS: rel_str = "conflicts with"; break;
921         case SUGGEST: rel_str = "suggests"; break;
922         case RECOMMEND: rel_str = "recommends"; break;
923         default: return -1;
924         }
925      
926         available_pkgs = pkg_vec_alloc();
927
928         if (conf->query_all)
929                pkg_hash_fetch_available(available_pkgs);
930         else
931                pkg_hash_fetch_all_installed(available_pkgs);
932
933         /* mark the root set */
934         pkg_vec_clear_marks(available_pkgs);
935         opkg_msg(NOTICE, "Root set:\n");
936         for (i = 0; i < argc; i++)
937                pkg_vec_mark_if_matches(available_pkgs, argv[i]);
938
939         for (i = 0; i < available_pkgs->len; i++) {
940                pkg = available_pkgs->pkgs[i];
941                if (pkg->state_flag & SF_MARKED) {
942                     /* mark the parent (abstract) package */
943                     pkg_mark_provides(pkg);
944                     opkg_msg(NOTICE, "  %s\n", pkg->name);
945                }
946         }
947
948         opkg_msg(NOTICE, "What %s root set\n", rel_str);
949         do {
950                 changed = 0;
951
952                 for (j=0; j<available_pkgs->len; j++) {
953
954                         pkg = available_pkgs->pkgs[j];
955                         count = ((what_field_type == CONFLICTS)
956                                  ? pkg->conflicts_count
957                                  : pkg->pre_depends_count +
958                                  pkg->depends_count +
959                                  pkg->recommends_count +
960                                  pkg->suggests_count);
961
962                         /* skip this package if it is already marked */
963                         if (pkg->parent->state_flag & SF_MARKED)
964                                 continue;
965
966                         for (k=0; k<count; k++) {
967                                 cdep = (what_field_type == CONFLICTS)
968                                         ? &pkg->conflicts[k]
969                                         : &pkg->depends[k];
970
971                                 if (what_field_type != cdep->type)
972                                         continue;
973
974                                 for (l=0; l<cdep->possibility_count; l++) {
975                                         possibility = cdep->possibilities[l];
976
977                                         if ((possibility->pkg->state_flag
978                                                                 & SF_MARKED)
979                                                         != SF_MARKED)
980                                                 continue;
981                                         
982                                         /* mark the depending package so we
983                                         * won't visit it again */
984                                         pkg->state_flag |= SF_MARKED;
985                                         pkg_mark_provides(pkg);
986                                         changed++;
987
988                                         ver = pkg_version_str_alloc(pkg); 
989                                         opkg_msg(NOTICE, "\t%s %s\t%s %s",
990                                                         pkg->name,
991                                                         ver,
992                                                         rel_str,
993                                                         possibility->pkg->name);
994                                         free(ver);
995                                         if (possibility->version) {
996                                                 opkg_msg(NOTICE, " (%s%s)",
997                                                         constraint_to_str(possibility->constraint),
998                                                         possibility->version);
999                                         }
1000                                         if (!pkg_dependence_satisfiable(possibility))
1001                                                 opkg_msg(NOTICE,
1002                                                         " unsatisfiable");
1003                                         opkg_msg(NOTICE, "\n");
1004                                         goto next_package;
1005                                 }
1006                         }
1007 next_package:
1008                         ;
1009                 }
1010         } while (changed && recursive);
1011
1012         pkg_vec_free(available_pkgs);
1013
1014         return 0;
1015 }
1016
1017 static int
1018 opkg_whatdepends_recursively_cmd(int argc, char **argv)
1019 {
1020      return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv);
1021 }
1022
1023 static int
1024 opkg_whatdepends_cmd(int argc, char **argv)
1025 {
1026      return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv);
1027 }
1028
1029 static int
1030 opkg_whatsuggests_cmd(int argc, char **argv)
1031 {
1032      return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv);
1033 }
1034
1035 static int
1036 opkg_whatrecommends_cmd(int argc, char **argv)
1037 {
1038      return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv);
1039 }
1040
1041 static int
1042 opkg_whatconflicts_cmd(int argc, char **argv)
1043 {
1044      return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv);
1045 }
1046
1047 static int
1048 opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc, char **argv)
1049 {
1050
1051      if (argc > 0) {
1052           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1053           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1054           int i;
1055      
1056           pkg_info_preinstall_check();
1057
1058           if (conf->query_all)
1059                pkg_hash_fetch_available(available_pkgs);
1060           else
1061                pkg_hash_fetch_all_installed(available_pkgs);
1062           for (i = 0; i < argc; i++) {
1063                const char *target = argv[i];
1064                int j;
1065
1066                opkg_msg(NOTICE, "What %s %s\n",
1067                             rel_str, target);
1068                for (j = 0; j < available_pkgs->len; j++) {
1069                     pkg_t *pkg = available_pkgs->pkgs[j];
1070                     int k;
1071                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1072                     for (k = 0; k < count; k++) {
1073                          abstract_pkg_t *apkg = 
1074                               ((what_field_type == WHATPROVIDES) 
1075                                ? pkg->provides[k]
1076                                : pkg->replaces[k]);
1077                          if (fnmatch(target, apkg->name, 0) == 0) {
1078                               opkg_msg(NOTICE, "    %s", pkg->name);
1079                               if (strcmp(target, apkg->name) != 0)
1080                                    opkg_msg(NOTICE, "\t%s %s\n",
1081                                                    rel_str, apkg->name);
1082                               opkg_msg(NOTICE, "\n");
1083                          }
1084                     }
1085                }
1086           }
1087           pkg_vec_free(available_pkgs);
1088      }
1089      return 0;
1090 }
1091
1092 static int
1093 opkg_whatprovides_cmd(int argc, char **argv)
1094 {
1095      return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv);
1096 }
1097
1098 static int
1099 opkg_whatreplaces_cmd(int argc, char **argv)
1100 {
1101      return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv);
1102 }
1103
1104 static int
1105 opkg_search_cmd(int argc, char **argv)
1106 {
1107      int i;
1108
1109      pkg_vec_t *installed;
1110      pkg_t *pkg;
1111      str_list_t *installed_files;
1112      str_list_elt_t *iter;
1113      char *installed_file;
1114
1115      if (argc < 1) {
1116           return -1;
1117      }
1118  
1119      installed = pkg_vec_alloc();
1120      pkg_hash_fetch_all_installed(installed);
1121      pkg_vec_sort(installed, pkg_compare_names);
1122
1123      for (i=0; i < installed->len; i++) {
1124           pkg = installed->pkgs[i];
1125
1126           installed_files = pkg_get_installed_files(pkg);
1127
1128           for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1129                installed_file = (char *)iter->data;
1130                if (fnmatch(argv[0], installed_file, 0)==0)
1131                     print_pkg(pkg);
1132           }
1133
1134           pkg_free_installed_files(pkg);
1135      }
1136
1137      pkg_vec_free(installed);
1138
1139      return 0;
1140 }
1141
1142 static int
1143 opkg_compare_versions_cmd(int argc, char **argv)
1144 {
1145      if (argc == 3) {
1146           /* this is a bit gross */
1147           struct pkg p1, p2;
1148           parse_version(&p1, argv[0]); 
1149           parse_version(&p2, argv[2]); 
1150           return pkg_version_satisfied(&p1, &p2, argv[1]);
1151      } else {
1152           opkg_msg(ERROR,
1153                        "opkg compare_versions <v1> <op> <v2>\n"
1154                        "<op> is one of <= >= << >> =\n");
1155           return -1;
1156      }
1157 }
1158
1159 static int
1160 opkg_print_architecture_cmd(int argc, char **argv)
1161 {
1162      nv_pair_list_elt_t *l;
1163
1164      list_for_each_entry(l, &conf->arch_list.head, node) {
1165           nv_pair_t *nv = (nv_pair_t *)l->data;
1166           printf("arch %s %s\n", nv->name, nv->value);
1167      }
1168      return 0;
1169 }
1170
1171
1172 /* XXX: CLEANUP: The usage strings should be incorporated into this
1173    array for easier maintenance */
1174 static opkg_cmd_t cmds[] = {
1175      {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1176      {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1177      {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd, PFM_SOURCE},
1178      {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE},
1179      {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE},
1180      {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE},
1181      {"list-upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE},
1182      {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd, 0},
1183      {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1184      {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1185      {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1186      {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1187      {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1188      {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1189      {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1190      {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1191      {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1192      {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1193      {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1194      {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1195      {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1196      {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1197      {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1198      {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1199      {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1200      {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1201      {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1202      {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1203      {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1204      {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1205 };
1206
1207 opkg_cmd_t *
1208 opkg_cmd_find(const char *name)
1209 {
1210         int i;
1211         opkg_cmd_t *cmd;
1212         int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
1213
1214         for (i=0; i < num_cmds; i++) {
1215                 cmd = &cmds[i];
1216                 if (strcmp(name, cmd->name) == 0)
1217                         return cmd;
1218         }
1219
1220         return NULL;
1221 }
1222
1223 int
1224 opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv)
1225 {
1226         return (cmd->fun)(argc, argv);
1227 }