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