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