Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / pkg_install / dist / admin / main.c
blob8e4e8b793c0b1de9ed0cb499e9054194e3f3436c
1 /* $NetBSD: main.c,v 1.58 2009/10/21 17:10:36 joerg Exp $ */
3 #if HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6 #include <nbcompat.h>
7 #if HAVE_SYS_CDEFS_H
8 #include <sys/cdefs.h>
9 #endif
10 __RCSID("$NetBSD: main.c,v 1.58 2009/10/21 17:10:36 joerg Exp $");
12 /*-
13 * Copyright (c) 1999-2009 The NetBSD Foundation, Inc.
14 * All rights reserved.
16 * This code is derived from software contributed to The NetBSD Foundation
17 * by Hubert Feyrer <hubert@feyrer.de> and
18 * by Joerg Sonnenberger <joerg@NetBSD.org>.
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 * 1. Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
29 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
42 #if HAVE_SYS_TYPES_H
43 #include <sys/types.h>
44 #endif
45 #if HAVE_SYS_STAT_H
46 #include <sys/stat.h>
47 #endif
48 #if HAVE_DIRENT_H
49 #include <dirent.h>
50 #endif
51 #if HAVE_ERR_H
52 #include <err.h>
53 #endif
54 #if HAVE_ERRNO_H
55 #include <errno.h>
56 #endif
57 #if HAVE_FCNTL_H
58 #include <fcntl.h>
59 #endif
60 #ifndef NETBSD
61 #include <nbcompat/md5.h>
62 #else
63 #include <md5.h>
64 #endif
65 #if HAVE_LIMITS_H
66 #include <limits.h>
67 #endif
68 #if HAVE_STDIO_H
69 #include <stdio.h>
70 #endif
71 #if HAVE_STRING_H
72 #include <string.h>
73 #endif
75 #ifndef BOOTSTRAP
76 #include <archive.h>
77 #include <fetch.h>
78 #endif
80 #include "admin.h"
81 #include "lib.h"
83 #define DEFAULT_SFX ".t[bg]z" /* default suffix for ls{all,best} */
85 struct pkgdb_count {
86 size_t files;
87 size_t directories;
88 size_t packages;
91 static const char Options[] = "C:K:SVbd:qs:v";
93 int quiet, verbose;
95 static void set_unset_variable(char **, Boolean);
97 /* print usage message and exit */
98 void
99 usage(void)
101 (void) fprintf(stderr, "usage: %s [-bqSVv] [-C config] [-d lsdir] [-K pkg_dbdir] [-s sfx] command [args ...]\n"
102 "Where 'commands' and 'args' are:\n"
103 " rebuild - rebuild pkgdb from +CONTENTS files\n"
104 " rebuild-tree - rebuild +REQUIRED_BY files from forward deps\n"
105 " check [pkg ...] - check md5 checksum of installed files\n"
106 " add pkg ... - add pkg files to database\n"
107 " delete pkg ... - delete file entries for pkg in database\n"
108 " set variable=value pkg ... - set installation variable for package\n"
109 " unset variable pkg ... - unset installation variable for package\n"
110 " lsall /path/to/pkgpattern - list all pkgs matching the pattern\n"
111 " lsbest /path/to/pkgpattern - list pkgs matching the pattern best\n"
112 " dump - dump database\n"
113 " pmatch pattern pkg - returns true if pkg matches pattern, otherwise false\n"
114 " fetch-pkg-vulnerabilities [-s] - fetch new vulnerability file\n"
115 " check-pkg-vulnerabilities [-s] <file> - check syntax and checksums of the vulnerability file\n"
116 " audit [-es] [-t type] ... - check installed packages for vulnerabilities\n"
117 " audit-pkg [-es] [-t type] ... - check listed packages for vulnerabilities\n"
118 " audit-batch [-es] [-t type] ... - check packages in listed files for vulnerabilities\n"
119 " audit-history [-t type] ... - print all advisories for package names\n"
120 " check-license <condition> - check if condition is acceptable\n"
121 " check-single-license <license> - check if license is acceptable\n"
122 " config-var name - print current value of the configuration variable\n"
123 " check-signature ... - verify the signature of packages\n"
124 " x509-sign-package pkg spkg key cert - create X509 signature\n"
125 " gpg-sign-package pkg spkg - create GPG signature\n",
126 getprogname());
127 exit(EXIT_FAILURE);
131 * add1pkg(<pkg>)
132 * adds the files listed in the +CONTENTS of <pkg> into the
133 * pkgdb.byfile.db database file in the current package dbdir. It
134 * returns the number of files added to the database file.
136 static int
137 add_pkg(const char *pkgdir, void *vp)
139 FILE *f;
140 plist_t *p;
141 package_t Plist;
142 char *contents;
143 const char *PkgDBDir;
144 char *PkgName, *dirp;
145 char file[MaxPathSize];
146 char dir[MaxPathSize];
147 struct pkgdb_count *count;
149 if (!pkgdb_open(ReadWrite))
150 err(EXIT_FAILURE, "cannot open pkgdb");
152 count = vp;
153 ++count->packages;
155 PkgDBDir = _pkgdb_getPKGDB_DIR();
156 contents = pkgdb_pkg_file(pkgdir, CONTENTS_FNAME);
157 if ((f = fopen(contents, "r")) == NULL)
158 errx(EXIT_FAILURE, "%s: can't open `%s'", pkgdir, CONTENTS_FNAME);
159 free(contents);
161 read_plist(&Plist, f);
162 if ((p = find_plist(&Plist, PLIST_NAME)) == NULL) {
163 errx(EXIT_FAILURE, "Package `%s' has no @name, aborting.", pkgdir);
166 PkgName = p->name;
167 dirp = NULL;
168 for (p = Plist.head; p; p = p->next) {
169 switch(p->type) {
170 case PLIST_FILE:
171 if (dirp == NULL) {
172 errx(EXIT_FAILURE, "@cwd not yet found, please send-pr!");
174 (void) snprintf(file, sizeof(file), "%s/%s", dirp, p->name);
175 if (!(isfile(file) || islinktodir(file))) {
176 if (isbrokenlink(file)) {
177 warnx("%s: Symlink `%s' exists and is in %s but target does not exist!",
178 PkgName, file, CONTENTS_FNAME);
179 } else {
180 warnx("%s: File `%s' is in %s but not on filesystem!",
181 PkgName, file, CONTENTS_FNAME);
183 } else {
184 pkgdb_store(file, PkgName);
185 ++count->files;
187 break;
188 case PLIST_PKGDIR:
189 add_pkgdir(PkgName, dirp, p->name);
190 ++count->directories;
191 break;
192 case PLIST_CWD:
193 if (strcmp(p->name, ".") != 0) {
194 dirp = p->name;
195 } else {
196 (void) snprintf(dir, sizeof(dir), "%s/%s", PkgDBDir, pkgdir);
197 dirp = dir;
199 break;
200 case PLIST_IGNORE:
201 p = p->next;
202 break;
203 case PLIST_SHOW_ALL:
204 case PLIST_SRC:
205 case PLIST_CMD:
206 case PLIST_CHMOD:
207 case PLIST_CHOWN:
208 case PLIST_CHGRP:
209 case PLIST_COMMENT:
210 case PLIST_NAME:
211 case PLIST_UNEXEC:
212 case PLIST_DISPLAY:
213 case PLIST_PKGDEP:
214 case PLIST_DIR_RM:
215 case PLIST_OPTION:
216 case PLIST_PKGCFL:
217 case PLIST_BLDDEP:
218 break;
221 free_plist(&Plist);
222 fclose(f);
223 pkgdb_close();
225 return 0;
228 static void
229 delete1pkg(const char *pkgdir)
231 if (!pkgdb_open(ReadWrite))
232 err(EXIT_FAILURE, "cannot open pkgdb");
233 (void) pkgdb_remove_pkg(pkgdir);
234 pkgdb_close();
237 static void
238 rebuild(void)
240 char cachename[MaxPathSize];
241 struct pkgdb_count count;
243 count.files = 0;
244 count.directories = 0;
245 count.packages = 0;
247 (void) _pkgdb_getPKGDB_FILE(cachename, sizeof(cachename));
248 if (unlink(cachename) != 0 && errno != ENOENT)
249 err(EXIT_FAILURE, "unlink %s", cachename);
251 setbuf(stdout, NULL);
253 iterate_pkg_db(add_pkg, &count);
255 printf("\n");
256 printf("Stored %zu file%s and %zu explicit director%s"
257 " from %zu package%s in %s.\n",
258 count.files, count.files == 1 ? "" : "s",
259 count.directories, count.directories == 1 ? "y" : "ies",
260 count.packages, count.packages == 1 ? "" : "s",
261 cachename);
264 static int
265 lspattern(const char *pkg, void *vp)
267 const char *dir = vp;
268 printf("%s/%s\n", dir, pkg);
269 return 0;
272 static int
273 lsbasepattern(const char *pkg, void *vp)
275 puts(pkg);
276 return 0;
279 static int
280 remove_required_by(const char *pkgname, void *cookie)
282 char *path;
284 path = pkgdb_pkg_file(pkgname, REQUIRED_BY_FNAME);
286 if (unlink(path) == -1 && errno != ENOENT)
287 err(EXIT_FAILURE, "Cannot remove %s", path);
289 free(path);
291 return 0;
294 static void
295 add_required_by(const char *pattern, const char *required_by)
297 char *best_installed, *path;
298 int fd;
299 size_t len;
301 best_installed = find_best_matching_installed_pkg(pattern);
302 if (best_installed == NULL) {
303 warnx("Dependency %s of %s unresolved", pattern, required_by);
304 return;
307 path = pkgdb_pkg_file(best_installed, REQUIRED_BY_FNAME);
308 free(best_installed);
310 if ((fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0644)) == -1)
311 errx(EXIT_FAILURE, "Cannot write to %s", path);
312 free(path);
314 len = strlen(required_by);
315 if (write(fd, required_by, len) != (ssize_t)len ||
316 write(fd, "\n", 1) != 1 ||
317 close(fd) == -1)
318 errx(EXIT_FAILURE, "Cannot write to %s", path);
322 static int
323 add_depends_of(const char *pkgname, void *cookie)
325 FILE *fp;
326 plist_t *p;
327 package_t plist;
328 char *path;
330 path = pkgdb_pkg_file(pkgname, CONTENTS_FNAME);
331 if ((fp = fopen(path, "r")) == NULL)
332 errx(EXIT_FAILURE, "Cannot read %s of package %s",
333 CONTENTS_FNAME, pkgname);
334 free(path);
335 read_plist(&plist, fp);
336 fclose(fp);
338 for (p = plist.head; p; p = p->next) {
339 if (p->type == PLIST_PKGDEP)
340 add_required_by(p->name, pkgname);
343 free_plist(&plist);
345 return 0;
348 static void
349 rebuild_tree(void)
351 if (iterate_pkg_db(remove_required_by, NULL) == -1)
352 errx(EXIT_FAILURE, "cannot iterate pkgdb");
353 if (iterate_pkg_db(add_depends_of, NULL) == -1)
354 errx(EXIT_FAILURE, "cannot iterate pkgdb");
357 int
358 main(int argc, char *argv[])
360 Boolean use_default_sfx = TRUE;
361 Boolean show_basename_only = FALSE;
362 char lsdir[MaxPathSize];
363 char sfx[MaxPathSize];
364 char *lsdirp = NULL;
365 int ch;
367 setprogname(argv[0]);
369 if (argc < 2)
370 usage();
372 while ((ch = getopt(argc, argv, Options)) != -1)
373 switch (ch) {
374 case 'C':
375 config_file = optarg;
376 break;
378 case 'K':
379 _pkgdb_setPKGDB_DIR(optarg);
380 break;
382 case 'S':
383 sfx[0] = 0x0;
384 use_default_sfx = FALSE;
385 break;
387 case 'V':
388 show_version();
389 /* NOTREACHED */
391 case 'b':
392 show_basename_only = TRUE;
393 break;
395 case 'd':
396 (void) strlcpy(lsdir, optarg, sizeof(lsdir));
397 lsdirp = lsdir;
398 break;
400 case 'q':
401 quiet = 1;
402 break;
404 case 's':
405 (void) strlcpy(sfx, optarg, sizeof(sfx));
406 use_default_sfx = FALSE;
407 break;
409 case 'v':
410 ++verbose;
411 break;
413 default:
414 usage();
415 /* NOTREACHED */
418 argc -= optind;
419 argv += optind;
421 if (argc <= 0) {
422 usage();
426 * config-var is reading the config file implicitly,
427 * so skip it here.
429 if (strcasecmp(argv[0], "config-var") != 0)
430 pkg_install_config();
432 if (use_default_sfx)
433 (void) strlcpy(sfx, DEFAULT_SFX, sizeof(sfx));
435 if (strcasecmp(argv[0], "pmatch") == 0) {
437 char *pattern, *pkg;
439 argv++; /* "pmatch" */
441 if (argv[0] == NULL || argv[1] == NULL) {
442 usage();
445 pattern = argv[0];
446 pkg = argv[1];
448 if (pkg_match(pattern, pkg)){
449 return 0;
450 } else {
451 return 1;
454 } else if (strcasecmp(argv[0], "rebuild") == 0) {
456 rebuild();
457 printf("Done.\n");
460 } else if (strcasecmp(argv[0], "rebuild-tree") == 0) {
462 rebuild_tree();
463 printf("Done.\n");
465 } else if (strcasecmp(argv[0], "check") == 0) {
466 argv++; /* "check" */
468 check(argv);
470 if (!quiet) {
471 printf("Done.\n");
474 } else if (strcasecmp(argv[0], "lsall") == 0) {
475 argv++; /* "lsall" */
477 while (*argv != NULL) {
478 /* args specified */
479 int rc;
480 const char *basep, *dir;
482 dir = lsdirp ? lsdirp : dirname_of(*argv);
483 basep = basename_of(*argv);
485 if (show_basename_only)
486 rc = match_local_files(dir, use_default_sfx, 1, basep, lsbasepattern, NULL);
487 else
488 rc = match_local_files(dir, use_default_sfx, 1, basep, lspattern, __UNCONST(dir));
489 if (rc == -1)
490 errx(EXIT_FAILURE, "Error from match_local_files(\"%s\", \"%s\", ...)",
491 dir, basep);
493 argv++;
496 } else if (strcasecmp(argv[0], "lsbest") == 0) {
497 argv++; /* "lsbest" */
499 while (*argv != NULL) {
500 /* args specified */
501 const char *basep, *dir;
502 char *p;
504 dir = lsdirp ? lsdirp : dirname_of(*argv);
505 basep = basename_of(*argv);
507 p = find_best_matching_file(dir, basep, use_default_sfx, 1);
509 if (p) {
510 if (show_basename_only)
511 printf("%s\n", p);
512 else
513 printf("%s/%s\n", dir, p);
514 free(p);
517 argv++;
519 } else if (strcasecmp(argv[0], "list") == 0 ||
520 strcasecmp(argv[0], "dump") == 0) {
522 pkgdb_dump();
524 } else if (strcasecmp(argv[0], "add") == 0) {
525 struct pkgdb_count count;
527 count.files = 0;
528 count.directories = 0;
529 count.packages = 0;
531 for (++argv; *argv != NULL; ++argv)
532 add_pkg(*argv, &count);
533 } else if (strcasecmp(argv[0], "delete") == 0) {
534 argv++; /* "delete" */
535 while (*argv != NULL) {
536 delete1pkg(*argv);
537 argv++;
539 } else if (strcasecmp(argv[0], "set") == 0) {
540 argv++; /* "set" */
541 set_unset_variable(argv, FALSE);
542 } else if (strcasecmp(argv[0], "unset") == 0) {
543 argv++; /* "unset" */
544 set_unset_variable(argv, TRUE);
545 } else if (strcasecmp(argv[0], "config-var") == 0) {
546 argv++;
547 if (argv == NULL || argv[1] != NULL)
548 errx(EXIT_FAILURE, "config-var takes exactly one argument");
549 pkg_install_show_variable(argv[0]);
550 } else if (strcasecmp(argv[0], "check-license") == 0) {
551 if (argv[1] == NULL)
552 errx(EXIT_FAILURE, "check-license takes exactly one argument");
554 load_license_lists();
556 switch (acceptable_pkg_license(argv[1])) {
557 case 0:
558 puts("no");
559 return 0;
560 case 1:
561 puts("yes");
562 return 0;
563 case -1:
564 errx(EXIT_FAILURE, "invalid license condition");
566 } else if (strcasecmp(argv[0], "check-single-license") == 0) {
567 if (argv[1] == NULL)
568 errx(EXIT_FAILURE, "check-license takes exactly one argument");
569 load_license_lists();
571 switch (acceptable_license(argv[1])) {
572 case 0:
573 puts("no");
574 return 0;
575 case 1:
576 puts("yes");
577 return 0;
578 case -1:
579 errx(EXIT_FAILURE, "invalid license");
582 #ifndef BOOTSTRAP
583 else if (strcasecmp(argv[0], "findbest") == 0) {
584 struct url *url;
585 char *output;
586 int rc;
588 process_pkg_path();
590 rc = 0;
591 for (++argv; *argv != NULL; ++argv) {
592 url = find_best_package(NULL, *argv, 1);
593 if (url == NULL) {
594 rc = 1;
595 continue;
597 output = fetchStringifyURL(url);
598 puts(output);
599 fetchFreeURL(url);
600 free(output);
603 return rc;
604 } else if (strcasecmp(argv[0], "fetch-pkg-vulnerabilities") == 0) {
605 fetch_pkg_vulnerabilities(--argc, ++argv);
606 } else if (strcasecmp(argv[0], "check-pkg-vulnerabilities") == 0) {
607 check_pkg_vulnerabilities(--argc, ++argv);
608 } else if (strcasecmp(argv[0], "audit") == 0) {
609 audit_pkgdb(--argc, ++argv);
610 } else if (strcasecmp(argv[0], "audit-pkg") == 0) {
611 audit_pkg(--argc, ++argv);
612 } else if (strcasecmp(argv[0], "audit-batch") == 0) {
613 audit_batch(--argc, ++argv);
614 } else if (strcasecmp(argv[0], "audit-history") == 0) {
615 audit_history(--argc, ++argv);
616 } else if (strcasecmp(argv[0], "check-signature") == 0) {
617 struct archive *pkg;
618 int rc;
620 rc = 0;
621 for (--argc, ++argv; argc > 0; --argc, ++argv) {
622 pkg = open_archive(*argv);
623 if (pkg == NULL) {
624 warnx("%s could not be opened", *argv);
625 continue;
627 if (pkg_full_signature_check(&pkg))
628 rc = 1;
629 if (!pkg)
630 archive_read_finish(pkg);
632 return rc;
633 } else if (strcasecmp(argv[0], "x509-sign-package") == 0) {
634 #ifdef HAVE_SSL
635 --argc;
636 ++argv;
637 if (argc != 4)
638 errx(EXIT_FAILURE, "x509-sign-package takes exactly four arguments");
639 pkg_sign_x509(argv[0], argv[1], argv[2], argv[3]);
640 #else
641 errx(EXIT_FAILURE, "OpenSSL support is not included");
642 #endif
643 } else if (strcasecmp(argv[0], "gpg-sign-package") == 0) {
644 --argc;
645 ++argv;
646 if (argc != 2)
647 errx(EXIT_FAILURE, "gpg-sign-package takes exactly two arguments");
648 pkg_sign_gpg(argv[0], argv[1]);
650 #endif
651 else {
652 usage();
655 return 0;
658 struct set_installed_info_arg {
659 char *variable;
660 char *value;
661 int got_match;
664 static int
665 set_installed_info_var(const char *name, void *cookie)
667 struct set_installed_info_arg *arg = cookie;
668 char *filename;
669 int retval;
671 filename = pkgdb_pkg_file(name, INSTALLED_INFO_FNAME);
673 retval = var_set(filename, arg->variable, arg->value);
675 free(filename);
676 arg->got_match = 1;
678 return retval;
681 static void
682 set_unset_variable(char **argv, Boolean unset)
684 struct set_installed_info_arg arg;
685 char *eq;
686 char *variable;
687 int ret = 0;
689 if (argv[0] == NULL || argv[1] == NULL)
690 usage();
692 variable = NULL;
694 if (unset) {
695 arg.variable = argv[0];
696 arg.value = NULL;
697 } else {
698 eq = NULL;
699 if ((eq=strchr(argv[0], '=')) == NULL)
700 usage();
702 variable = xmalloc(eq-argv[0]+1);
703 strlcpy(variable, argv[0], eq-argv[0]+1);
705 arg.variable = variable;
706 arg.value = eq+1;
708 if (strcmp(variable, AUTOMATIC_VARNAME) == 0 &&
709 strcasecmp(arg.value, "yes") != 0 &&
710 strcasecmp(arg.value, "no") != 0) {
711 errx(EXIT_FAILURE,
712 "unknown value `%s' for " AUTOMATIC_VARNAME,
713 arg.value);
716 if (strpbrk(arg.variable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != NULL) {
717 free(variable);
718 errx(EXIT_FAILURE,
719 "variable name must not contain uppercase letters");
722 argv++;
723 while (*argv != NULL) {
724 arg.got_match = 0;
725 if (match_installed_pkgs(*argv, set_installed_info_var, &arg) == -1)
726 errx(EXIT_FAILURE, "Cannot process pkdbdb");
727 if (arg.got_match == 0) {
728 char *pattern;
730 if (ispkgpattern(*argv)) {
731 warnx("no matching pkg for `%s'", *argv);
732 ret++;
733 } else {
734 pattern = xasprintf("%s-[0-9]*", *argv);
736 if (match_installed_pkgs(pattern, set_installed_info_var, &arg) == -1)
737 errx(EXIT_FAILURE, "Cannot process pkdbdb");
739 if (arg.got_match == 0) {
740 warnx("cannot find package %s", *argv);
741 ++ret;
743 free(pattern);
747 argv++;
750 if (ret > 0)
751 exit(EXIT_FAILURE);
753 free(variable);
755 return;