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