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