584d05d11102c8e6497f941d3aaa615ee6725d5d
[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_changed_conffiles_cmd(int argc, char **argv)
621 {
622      int i ;
623      pkg_vec_t *available;
624      pkg_t *pkg;
625      char *pkg_name = NULL;
626      conffile_list_elt_t *iter;
627      conffile_t *cf;
628
629      if (argc > 0) {
630           pkg_name = argv[0];
631      }
632      available = pkg_vec_alloc();
633      pkg_hash_fetch_all_installed(available);
634      pkg_vec_sort(available, pkg_compare_names);
635      for (i=0; i < available->len; i++) {
636           pkg = available->pkgs[i];
637           /* if we have package name or pattern and pkg does not match, then skip it */
638           if (pkg_name && fnmatch(pkg_name, pkg->name, 0))
639             continue;
640           if (nv_pair_list_empty(&pkg->conffiles))
641             continue;
642           for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
643             cf = (conffile_t *)iter->data;
644             if (cf->name && cf->value && conffile_has_been_modified(cf))
645               printf("%s\n", cf->name);
646           }
647      }
648      pkg_vec_free(available);
649      return 0;
650 }
651
652 static int
653 opkg_list_upgradable_cmd(int argc, char **argv)
654 {
655     struct active_list *head = prepare_upgrade_list();
656     struct active_list *node=NULL;
657     pkg_t *_old_pkg, *_new_pkg;
658     char *old_v, *new_v;
659     for (node = active_list_next(head, head); node;node = active_list_next(head,node)) {
660         _old_pkg = list_entry(node, pkg_t, list);
661         _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(_old_pkg->name);
662         if (_new_pkg == NULL)
663                 continue;
664         old_v = pkg_version_str_alloc(_old_pkg);
665         new_v = pkg_version_str_alloc(_new_pkg);
666         printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
667         free(old_v);
668         free(new_v);
669     }
670     active_list_head_delete(head);
671     return 0;
672 }
673
674 static int
675 opkg_info_status_cmd(int argc, char **argv, int installed_only)
676 {
677      int i;
678      pkg_vec_t *available;
679      pkg_t *pkg;
680      char *pkg_name = NULL;
681
682      if (argc > 0) {
683           pkg_name = argv[0];
684      }
685
686      available = pkg_vec_alloc();
687      if (installed_only)
688           pkg_hash_fetch_all_installed(available);
689      else
690           pkg_hash_fetch_available(available);
691
692      for (i=0; i < available->len; i++) {
693           pkg = available->pkgs[i];
694           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
695                continue;
696           }
697
698           pkg_formatted_info(stdout, pkg);
699
700           if (conf->verbosity >= NOTICE) {
701                conffile_list_elt_t *iter;
702                for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
703                     conffile_t *cf = (conffile_t *)iter->data;
704                     int modified = conffile_has_been_modified(cf);
705                     if (cf->value)
706                         opkg_msg(INFO, "conffile=%s md5sum=%s modified=%d.\n",
707                                  cf->name, cf->value, modified);
708                }
709           }
710      }
711      pkg_vec_free(available);
712
713      return 0;
714 }
715
716 static int
717 opkg_info_cmd(int argc, char **argv)
718 {
719      return opkg_info_status_cmd(argc, argv, 0);
720 }
721
722 static int
723 opkg_status_cmd(int argc, char **argv)
724 {
725      return opkg_info_status_cmd(argc, argv, 1);
726 }
727
728 static int
729 opkg_configure_cmd(int argc, char **argv)
730 {
731         int err;
732         char *pkg_name = NULL;
733
734         if (argc > 0)
735                 pkg_name = argv[0];
736
737         err = opkg_configure_packages(pkg_name);
738
739         write_status_files_if_changed();
740
741         return err;
742 }
743
744 static int
745 opkg_remove_cmd(int argc, char **argv)
746 {
747      int i, a, done, err = 0;
748      pkg_t *pkg;
749      pkg_t *pkg_to_remove;
750      pkg_vec_t *available;
751
752      done = 0;
753
754      signal(SIGINT, sigint_handler);
755
756      pkg_info_preinstall_check();
757
758      available = pkg_vec_alloc();
759      pkg_hash_fetch_all_installed(available);
760
761      for (i=0; i<argc; i++) {
762         for (a=0; a<available->len; a++) {
763             pkg = available->pkgs[a];
764             if (fnmatch(argv[i], pkg->name, 0)) {
765                continue;
766             }
767             if (conf->restrict_to_default_dest) {
768                  pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(
769                                         pkg->name,
770                                         conf->default_dest);
771             } else {
772                  pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name);
773             }
774
775             if (pkg_to_remove == NULL) {
776                  opkg_msg(ERROR, "Package %s is not installed.\n", pkg->name);
777                  continue;
778             }
779             if (pkg->state_status == SS_NOT_INSTALLED) {
780                  opkg_msg(ERROR, "Package %s not installed.\n", pkg->name);
781                  continue;
782             }
783
784             if (opkg_remove_pkg(pkg_to_remove, 0))
785                  err = -1;
786             else
787                  done = 1;
788         }
789      }
790
791      pkg_vec_free(available);
792
793      if (done == 0)
794         opkg_msg(NOTICE, "No packages removed.\n");
795
796      write_status_files_if_changed();
797      return err;
798 }
799
800 static int
801 opkg_flag_cmd(int argc, char **argv)
802 {
803      int i;
804      pkg_t *pkg;
805      const char *flags = argv[0];
806
807      signal(SIGINT, sigint_handler);
808
809      for (i=1; i < argc; i++) {
810           if (conf->restrict_to_default_dest) {
811                pkg = pkg_hash_fetch_installed_by_name_dest(argv[i],
812                                                            conf->default_dest);
813           } else {
814                pkg = pkg_hash_fetch_installed_by_name(argv[i]);
815           }
816
817           if (pkg == NULL) {
818                opkg_msg(ERROR, "Package %s is not installed.\n", argv[i]);
819                continue;
820           }
821           if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
822               ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
823               pkg->state_flag = pkg_state_flag_from_str(flags);
824           }
825
826           /*
827            * Useful if a package is installed in an offline_root, and
828            * should be configured by opkg-cl configure at a later date.
829            */
830           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
831               pkg->state_status = pkg_state_status_from_str(flags);
832           }
833
834           opkg_state_changed++;
835           opkg_msg(NOTICE, "Setting flags for package %s to %s.\n",
836                        pkg->name, flags);
837      }
838
839      write_status_files_if_changed();
840      return 0;
841 }
842
843 static int
844 opkg_files_cmd(int argc, char **argv)
845 {
846      pkg_t *pkg;
847      str_list_t *files;
848      str_list_elt_t *iter;
849      char *pkg_version;
850
851      if (argc < 1) {
852           return -1;
853      }
854
855      pkg = pkg_hash_fetch_installed_by_name(argv[0]);
856      if (pkg == NULL) {
857           opkg_msg(ERROR, "Package %s not installed.\n", argv[0]);
858           return 0;
859      }
860
861      files = pkg_get_installed_files(pkg);
862      pkg_version = pkg_version_str_alloc(pkg);
863
864      printf("Package %s (%s) is installed on %s and has the following files:\n",
865                 pkg->name, pkg_version, pkg->dest->name);
866
867      for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
868           printf("%s\n", (char *)iter->data);
869
870      free(pkg_version);
871      pkg_free_installed_files(pkg);
872
873      return 0;
874 }
875
876 static int
877 opkg_depends_cmd(int argc, char **argv)
878 {
879         int i, j, k;
880         int depends_count;
881         pkg_vec_t *available_pkgs;
882         compound_depend_t *cdep;
883         pkg_t *pkg;
884         char *str;
885
886         pkg_info_preinstall_check();
887
888         available_pkgs = pkg_vec_alloc();
889         if (conf->query_all)
890                pkg_hash_fetch_available(available_pkgs);
891         else
892                pkg_hash_fetch_all_installed(available_pkgs);
893
894         for (i=0; i<argc; i++) {
895                 for (j=0; j<available_pkgs->len; j++) {
896                         pkg = available_pkgs->pkgs[j];
897
898                         if (fnmatch(argv[i], pkg->name, 0) != 0)
899                                 continue;
900
901                         depends_count = pkg->depends_count +
902                                         pkg->pre_depends_count +
903                                         pkg->recommends_count +
904                                         pkg->suggests_count;
905
906                         opkg_msg(NOTICE, "%s depends on:\n", pkg->name);
907
908                         for (k=0; k<depends_count; k++) {
909                                 cdep = &pkg->depends[k];
910
911                                 if (cdep->type != DEPEND)
912                                       continue;
913
914                                 str = pkg_depend_str(pkg, k);
915                                 opkg_msg(NOTICE, "\t%s\n", str);
916                                 free(str);
917                         }
918
919                }
920         }
921
922         pkg_vec_free(available_pkgs);
923         return 0;
924 }
925
926 static int
927 pkg_mark_provides(pkg_t *pkg)
928 {
929      int provides_count = pkg->provides_count;
930      abstract_pkg_t **provides = pkg->provides;
931      int i;
932      pkg->parent->state_flag |= SF_MARKED;
933      for (i = 0; i < provides_count; i++) {
934           provides[i]->state_flag |= SF_MARKED;
935      }
936      return 0;
937 }
938
939 enum what_field_type {
940   WHATDEPENDS,
941   WHATCONFLICTS,
942   WHATPROVIDES,
943   WHATREPLACES,
944   WHATRECOMMENDS,
945   WHATSUGGESTS
946 };
947
948 static int
949 opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive, int argc, char **argv)
950 {
951         depend_t *possibility;
952         compound_depend_t *cdep;
953         pkg_vec_t *available_pkgs;
954         pkg_t *pkg;
955         int i, j, k, l;
956         int changed, count;
957         const char *rel_str = NULL;
958         char *ver;
959
960         switch (what_field_type) {
961         case DEPEND: rel_str = "depends on"; break;
962         case CONFLICTS: rel_str = "conflicts with"; break;
963         case SUGGEST: rel_str = "suggests"; break;
964         case RECOMMEND: rel_str = "recommends"; break;
965         default: return -1;
966         }
967
968         available_pkgs = pkg_vec_alloc();
969
970         if (conf->query_all)
971                pkg_hash_fetch_available(available_pkgs);
972         else
973                pkg_hash_fetch_all_installed(available_pkgs);
974
975         /* mark the root set */
976         pkg_vec_clear_marks(available_pkgs);
977         opkg_msg(NOTICE, "Root set:\n");
978         for (i = 0; i < argc; i++)
979                pkg_vec_mark_if_matches(available_pkgs, argv[i]);
980
981         for (i = 0; i < available_pkgs->len; i++) {
982                pkg = available_pkgs->pkgs[i];
983                if (pkg->state_flag & SF_MARKED) {
984                     /* mark the parent (abstract) package */
985                     pkg_mark_provides(pkg);
986                     opkg_msg(NOTICE, "  %s\n", pkg->name);
987                }
988         }
989
990         opkg_msg(NOTICE, "What %s root set\n", rel_str);
991         do {
992                 changed = 0;
993
994                 for (j=0; j<available_pkgs->len; j++) {
995
996                         pkg = available_pkgs->pkgs[j];
997                         count = ((what_field_type == CONFLICTS)
998                                  ? pkg->conflicts_count
999                                  : pkg->pre_depends_count +
1000                                  pkg->depends_count +
1001                                  pkg->recommends_count +
1002                                  pkg->suggests_count);
1003
1004                         /* skip this package if it is already marked */
1005                         if (pkg->parent->state_flag & SF_MARKED)
1006                                 continue;
1007
1008                         for (k=0; k<count; k++) {
1009                                 cdep = (what_field_type == CONFLICTS)
1010                                         ? &pkg->conflicts[k]
1011                                         : &pkg->depends[k];
1012
1013                                 if (what_field_type != cdep->type)
1014                                         continue;
1015
1016                                 for (l=0; l<cdep->possibility_count; l++) {
1017                                         possibility = cdep->possibilities[l];
1018
1019                                         if ((possibility->pkg->state_flag
1020                                                                 & SF_MARKED)
1021                                                         != SF_MARKED)
1022                                                 continue;
1023
1024                                         /* mark the depending package so we
1025                                         * won't visit it again */
1026                                         pkg->state_flag |= SF_MARKED;
1027                                         pkg_mark_provides(pkg);
1028                                         changed++;
1029
1030                                         ver = pkg_version_str_alloc(pkg);
1031                                         opkg_msg(NOTICE, "\t%s %s\t%s %s",
1032                                                         pkg->name,
1033                                                         ver,
1034                                                         rel_str,
1035                                                         possibility->pkg->name);
1036                                         free(ver);
1037                                         if (possibility->version) {
1038                                                 opkg_msg(NOTICE, " (%s%s)",
1039                                                         constraint_to_str(possibility->constraint),
1040                                                         possibility->version);
1041                                         }
1042                                         if (!pkg_dependence_satisfiable(possibility))
1043                                                 opkg_msg(NOTICE,
1044                                                         " unsatisfiable");
1045                                         opkg_msg(NOTICE, "\n");
1046                                         goto next_package;
1047                                 }
1048                         }
1049 next_package:
1050                         ;
1051                 }
1052         } while (changed && recursive);
1053
1054         pkg_vec_free(available_pkgs);
1055
1056         return 0;
1057 }
1058
1059 static int
1060 opkg_whatdepends_recursively_cmd(int argc, char **argv)
1061 {
1062      return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv);
1063 }
1064
1065 static int
1066 opkg_whatdepends_cmd(int argc, char **argv)
1067 {
1068      return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv);
1069 }
1070
1071 static int
1072 opkg_whatsuggests_cmd(int argc, char **argv)
1073 {
1074      return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv);
1075 }
1076
1077 static int
1078 opkg_whatrecommends_cmd(int argc, char **argv)
1079 {
1080      return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv);
1081 }
1082
1083 static int
1084 opkg_whatconflicts_cmd(int argc, char **argv)
1085 {
1086      return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv);
1087 }
1088
1089 static int
1090 opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc, char **argv)
1091 {
1092
1093      if (argc > 0) {
1094           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1095           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1096           int i;
1097
1098           pkg_info_preinstall_check();
1099
1100           if (conf->query_all)
1101                pkg_hash_fetch_available(available_pkgs);
1102           else
1103                pkg_hash_fetch_all_installed(available_pkgs);
1104           for (i = 0; i < argc; i++) {
1105                const char *target = argv[i];
1106                int j;
1107
1108                opkg_msg(NOTICE, "What %s %s\n",
1109                             rel_str, target);
1110                for (j = 0; j < available_pkgs->len; j++) {
1111                     pkg_t *pkg = available_pkgs->pkgs[j];
1112                     int k;
1113                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1114                     for (k = 0; k < count; k++) {
1115                          abstract_pkg_t *apkg =
1116                               ((what_field_type == WHATPROVIDES)
1117                                ? pkg->provides[k]
1118                                : pkg->replaces[k]);
1119                          if (fnmatch(target, apkg->name, 0) == 0) {
1120                               opkg_msg(NOTICE, "    %s", pkg->name);
1121                               if (strcmp(target, apkg->name) != 0)
1122                                    opkg_msg(NOTICE, "\t%s %s\n",
1123                                                    rel_str, apkg->name);
1124                               opkg_msg(NOTICE, "\n");
1125                          }
1126                     }
1127                }
1128           }
1129           pkg_vec_free(available_pkgs);
1130      }
1131      return 0;
1132 }
1133
1134 static int
1135 opkg_whatprovides_cmd(int argc, char **argv)
1136 {
1137      return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv);
1138 }
1139
1140 static int
1141 opkg_whatreplaces_cmd(int argc, char **argv)
1142 {
1143      return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv);
1144 }
1145
1146 static int
1147 opkg_search_cmd(int argc, char **argv)
1148 {
1149      int i;
1150
1151      pkg_vec_t *installed;
1152      pkg_t *pkg;
1153      str_list_t *installed_files;
1154      str_list_elt_t *iter;
1155      char *installed_file;
1156
1157      if (argc < 1) {
1158           return -1;
1159      }
1160
1161      installed = pkg_vec_alloc();
1162      pkg_hash_fetch_all_installed(installed);
1163      pkg_vec_sort(installed, pkg_compare_names);
1164
1165      for (i=0; i < installed->len; i++) {
1166           pkg = installed->pkgs[i];
1167
1168           installed_files = pkg_get_installed_files(pkg);
1169
1170           for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1171                installed_file = (char *)iter->data;
1172                if (fnmatch(argv[0], installed_file, 0)==0)
1173                     print_pkg(pkg);
1174           }
1175
1176           pkg_free_installed_files(pkg);
1177      }
1178
1179      pkg_vec_free(installed);
1180
1181      return 0;
1182 }
1183
1184 static int
1185 opkg_compare_versions_cmd(int argc, char **argv)
1186 {
1187      if (argc == 3) {
1188           /* this is a bit gross */
1189           struct pkg p1, p2;
1190           parse_version(&p1, argv[0]);
1191           parse_version(&p2, argv[2]);
1192           return pkg_version_satisfied(&p1, &p2, argv[1]);
1193      } else {
1194           opkg_msg(ERROR,
1195                        "opkg compare_versions <v1> <op> <v2>\n"
1196                        "<op> is one of <= >= << >> =\n");
1197           return -1;
1198      }
1199 }
1200
1201 static int
1202 opkg_print_architecture_cmd(int argc, char **argv)
1203 {
1204      nv_pair_list_elt_t *l;
1205
1206      list_for_each_entry(l, &conf->arch_list.head, node) {
1207           nv_pair_t *nv = (nv_pair_t *)l->data;
1208           printf("arch %s %s\n", nv->name, nv->value);
1209      }
1210      return 0;
1211 }
1212
1213
1214 /* XXX: CLEANUP: The usage strings should be incorporated into this
1215    array for easier maintenance */
1216 static opkg_cmd_t cmds[] = {
1217      {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1218      {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1219      {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd, PFM_SOURCE},
1220      {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE},
1221      {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE},
1222      {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE},
1223      {"list-upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE},
1224      {"list_changed_conffiles", 0, (opkg_cmd_fun_t)opkg_list_changed_conffiles_cmd, PFM_SOURCE},
1225      {"list-changed-conffiles", 0, (opkg_cmd_fun_t)opkg_list_changed_conffiles_cmd, PFM_SOURCE},
1226      {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd, 0},
1227      {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1228      {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1229      {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1230      {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1231      {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1232      {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1233      {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1234      {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1235      {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1236      {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1237      {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1238      {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1239      {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1240      {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1241      {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1242      {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1243      {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1244      {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1245      {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1246      {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1247      {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1248      {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd, PFM_DESCRIPTION|PFM_SOURCE},
1249 };
1250
1251 opkg_cmd_t *
1252 opkg_cmd_find(const char *name)
1253 {
1254         int i;
1255         opkg_cmd_t *cmd;
1256         int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
1257
1258         for (i=0; i < num_cmds; i++) {
1259                 cmd = &cmds[i];
1260                 if (strcmp(name, cmd->name) == 0)
1261                         return cmd;
1262         }
1263
1264         return NULL;
1265 }
1266
1267 int
1268 opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv)
1269 {
1270         return (cmd->fun)(argc, argv);
1271 }