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