etc/protocols - sync with NetBSD-8
[minix.git] / external / bsd / pkg_install / dist / admin / main.c
blob56a5353c42b285022997b25969eadeb32fd78d6e
1 /* $NetBSD: main.c,v 1.1.1.15 2010/04/23 20:54:07 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.1.1.15 2010/04/23 20:54:07 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 char *PkgName, *dirp;
144 char file[MaxPathSize];
145 struct pkgdb_count *count;
147 if (!pkgdb_open(ReadWrite))
148 err(EXIT_FAILURE, "cannot open pkgdb");
150 count = vp;
151 ++count->packages;
153 contents = pkgdb_pkg_file(pkgdir, CONTENTS_FNAME);
154 if ((f = fopen(contents, "r")) == NULL)
155 errx(EXIT_FAILURE, "%s: can't open `%s'", pkgdir, CONTENTS_FNAME);
156 free(contents);
158 read_plist(&Plist, f);
159 if ((p = find_plist(&Plist, PLIST_NAME)) == NULL) {
160 errx(EXIT_FAILURE, "Package `%s' has no @name, aborting.", pkgdir);
163 PkgName = p->name;
164 dirp = NULL;
165 for (p = Plist.head; p; p = p->next) {
166 switch(p->type) {
167 case PLIST_FILE:
168 if (dirp == NULL) {
169 errx(EXIT_FAILURE, "@cwd not yet found, please send-pr!");
171 (void) snprintf(file, sizeof(file), "%s/%s", dirp, p->name);
172 if (!(isfile(file) || islinktodir(file))) {
173 if (isbrokenlink(file)) {
174 warnx("%s: Symlink `%s' exists and is in %s but target does not exist!",
175 PkgName, file, CONTENTS_FNAME);
176 } else {
177 warnx("%s: File `%s' is in %s but not on filesystem!",
178 PkgName, file, CONTENTS_FNAME);
180 } else {
181 pkgdb_store(file, PkgName);
182 ++count->files;
184 break;
185 case PLIST_PKGDIR:
186 add_pkgdir(PkgName, dirp, p->name);
187 ++count->directories;
188 break;
189 case PLIST_CWD:
190 if (strcmp(p->name, ".") != 0)
191 dirp = p->name;
192 else
193 dirp = pkgdb_pkg_dir(pkgdir);
194 break;
195 case PLIST_IGNORE:
196 p = p->next;
197 break;
198 case PLIST_SHOW_ALL:
199 case PLIST_SRC:
200 case PLIST_CMD:
201 case PLIST_CHMOD:
202 case PLIST_CHOWN:
203 case PLIST_CHGRP:
204 case PLIST_COMMENT:
205 case PLIST_NAME:
206 case PLIST_UNEXEC:
207 case PLIST_DISPLAY:
208 case PLIST_PKGDEP:
209 case PLIST_DIR_RM:
210 case PLIST_OPTION:
211 case PLIST_PKGCFL:
212 case PLIST_BLDDEP:
213 break;
216 free_plist(&Plist);
217 fclose(f);
218 pkgdb_close();
220 return 0;
223 static void
224 delete1pkg(const char *pkgdir)
226 if (!pkgdb_open(ReadWrite))
227 err(EXIT_FAILURE, "cannot open pkgdb");
228 (void) pkgdb_remove_pkg(pkgdir);
229 pkgdb_close();
232 static void
233 rebuild(void)
235 char *cachename;
236 struct pkgdb_count count;
238 count.files = 0;
239 count.directories = 0;
240 count.packages = 0;
242 cachename = pkgdb_get_database();
243 if (unlink(cachename) != 0 && errno != ENOENT)
244 err(EXIT_FAILURE, "unlink %s", cachename);
246 setbuf(stdout, NULL);
248 iterate_pkg_db(add_pkg, &count);
250 printf("\n");
251 printf("Stored %" PRIzu " file%s and %zu explicit director%s"
252 " from %"PRIzu " package%s in %s.\n",
253 count.files, count.files == 1 ? "" : "s",
254 count.directories, count.directories == 1 ? "y" : "ies",
255 count.packages, count.packages == 1 ? "" : "s",
256 cachename);
259 static int
260 lspattern(const char *pkg, void *vp)
262 const char *dir = vp;
263 printf("%s/%s\n", dir, pkg);
264 return 0;
267 static int
268 lsbasepattern(const char *pkg, void *vp)
270 puts(pkg);
271 return 0;
274 static int
275 remove_required_by(const char *pkgname, void *cookie)
277 char *path;
279 path = pkgdb_pkg_file(pkgname, REQUIRED_BY_FNAME);
281 if (unlink(path) == -1 && errno != ENOENT)
282 err(EXIT_FAILURE, "Cannot remove %s", path);
284 free(path);
286 return 0;
289 static void
290 add_required_by(const char *pattern, const char *required_by)
292 char *best_installed, *path;
293 int fd;
294 size_t len;
296 best_installed = find_best_matching_installed_pkg(pattern);
297 if (best_installed == NULL) {
298 warnx("Dependency %s of %s unresolved", pattern, required_by);
299 return;
302 path = pkgdb_pkg_file(best_installed, REQUIRED_BY_FNAME);
303 free(best_installed);
305 if ((fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0644)) == -1)
306 errx(EXIT_FAILURE, "Cannot write to %s", path);
307 free(path);
309 len = strlen(required_by);
310 if (write(fd, required_by, len) != (ssize_t)len ||
311 write(fd, "\n", 1) != 1 ||
312 close(fd) == -1)
313 errx(EXIT_FAILURE, "Cannot write to %s", path);
317 static int
318 add_depends_of(const char *pkgname, void *cookie)
320 FILE *fp;
321 plist_t *p;
322 package_t plist;
323 char *path;
325 path = pkgdb_pkg_file(pkgname, CONTENTS_FNAME);
326 if ((fp = fopen(path, "r")) == NULL)
327 errx(EXIT_FAILURE, "Cannot read %s of package %s",
328 CONTENTS_FNAME, pkgname);
329 free(path);
330 read_plist(&plist, fp);
331 fclose(fp);
333 for (p = plist.head; p; p = p->next) {
334 if (p->type == PLIST_PKGDEP)
335 add_required_by(p->name, pkgname);
338 free_plist(&plist);
340 return 0;
343 static void
344 rebuild_tree(void)
346 if (iterate_pkg_db(remove_required_by, NULL) == -1)
347 errx(EXIT_FAILURE, "cannot iterate pkgdb");
348 if (iterate_pkg_db(add_depends_of, NULL) == -1)
349 errx(EXIT_FAILURE, "cannot iterate pkgdb");
352 int
353 main(int argc, char *argv[])
355 Boolean use_default_sfx = TRUE;
356 Boolean show_basename_only = FALSE;
357 char lsdir[MaxPathSize];
358 char sfx[MaxPathSize];
359 char *lsdirp = NULL;
360 int ch;
362 setprogname(argv[0]);
364 if (argc < 2)
365 usage();
367 while ((ch = getopt(argc, argv, Options)) != -1)
368 switch (ch) {
369 case 'C':
370 config_file = optarg;
371 break;
373 case 'K':
374 pkgdb_set_dir(optarg, 3);
375 break;
377 case 'S':
378 sfx[0] = 0x0;
379 use_default_sfx = FALSE;
380 break;
382 case 'V':
383 show_version();
384 /* NOTREACHED */
386 case 'b':
387 show_basename_only = TRUE;
388 break;
390 case 'd':
391 (void) strlcpy(lsdir, optarg, sizeof(lsdir));
392 lsdirp = lsdir;
393 break;
395 case 'q':
396 quiet = 1;
397 break;
399 case 's':
400 (void) strlcpy(sfx, optarg, sizeof(sfx));
401 use_default_sfx = FALSE;
402 break;
404 case 'v':
405 ++verbose;
406 break;
408 default:
409 usage();
410 /* NOTREACHED */
413 argc -= optind;
414 argv += optind;
416 if (argc <= 0) {
417 usage();
421 * config-var is reading the config file implicitly,
422 * so skip it here.
424 if (strcasecmp(argv[0], "config-var") != 0)
425 pkg_install_config();
427 if (use_default_sfx)
428 (void) strlcpy(sfx, DEFAULT_SFX, sizeof(sfx));
430 if (strcasecmp(argv[0], "pmatch") == 0) {
432 char *pattern, *pkg;
434 argv++; /* "pmatch" */
436 if (argv[0] == NULL || argv[1] == NULL) {
437 usage();
440 pattern = argv[0];
441 pkg = argv[1];
443 if (pkg_match(pattern, pkg)){
444 return 0;
445 } else {
446 return 1;
449 } else if (strcasecmp(argv[0], "rebuild") == 0) {
451 rebuild();
452 printf("Done.\n");
455 } else if (strcasecmp(argv[0], "rebuild-tree") == 0) {
457 rebuild_tree();
458 printf("Done.\n");
460 } else if (strcasecmp(argv[0], "check") == 0) {
461 argv++; /* "check" */
463 check(argv);
465 if (!quiet) {
466 printf("Done.\n");
469 } else if (strcasecmp(argv[0], "lsall") == 0) {
470 argv++; /* "lsall" */
472 while (*argv != NULL) {
473 /* args specified */
474 int rc;
475 const char *basep, *dir;
477 dir = lsdirp ? lsdirp : dirname_of(*argv);
478 basep = basename_of(*argv);
480 if (show_basename_only)
481 rc = match_local_files(dir, use_default_sfx, 1, basep, lsbasepattern, NULL);
482 else
483 rc = match_local_files(dir, use_default_sfx, 1, basep, lspattern, __UNCONST(dir));
484 if (rc == -1)
485 errx(EXIT_FAILURE, "Error from match_local_files(\"%s\", \"%s\", ...)",
486 dir, basep);
488 argv++;
491 } else if (strcasecmp(argv[0], "lsbest") == 0) {
492 argv++; /* "lsbest" */
494 while (*argv != NULL) {
495 /* args specified */
496 const char *basep, *dir;
497 char *p;
499 dir = lsdirp ? lsdirp : dirname_of(*argv);
500 basep = basename_of(*argv);
502 p = find_best_matching_file(dir, basep, use_default_sfx, 1);
504 if (p) {
505 if (show_basename_only)
506 printf("%s\n", p);
507 else
508 printf("%s/%s\n", dir, p);
509 free(p);
512 argv++;
514 } else if (strcasecmp(argv[0], "list") == 0 ||
515 strcasecmp(argv[0], "dump") == 0) {
517 pkgdb_dump();
519 } else if (strcasecmp(argv[0], "add") == 0) {
520 struct pkgdb_count count;
522 count.files = 0;
523 count.directories = 0;
524 count.packages = 0;
526 for (++argv; *argv != NULL; ++argv)
527 add_pkg(*argv, &count);
528 } else if (strcasecmp(argv[0], "delete") == 0) {
529 argv++; /* "delete" */
530 while (*argv != NULL) {
531 delete1pkg(*argv);
532 argv++;
534 } else if (strcasecmp(argv[0], "set") == 0) {
535 argv++; /* "set" */
536 set_unset_variable(argv, FALSE);
537 } else if (strcasecmp(argv[0], "unset") == 0) {
538 argv++; /* "unset" */
539 set_unset_variable(argv, TRUE);
540 } else if (strcasecmp(argv[0], "config-var") == 0) {
541 argv++;
542 if (argv == NULL || argv[1] != NULL)
543 errx(EXIT_FAILURE, "config-var takes exactly one argument");
544 pkg_install_show_variable(argv[0]);
545 } else if (strcasecmp(argv[0], "check-license") == 0) {
546 if (argv[1] == NULL)
547 errx(EXIT_FAILURE, "check-license takes exactly one argument");
549 load_license_lists();
551 switch (acceptable_pkg_license(argv[1])) {
552 case 0:
553 puts("no");
554 return 0;
555 case 1:
556 puts("yes");
557 return 0;
558 case -1:
559 errx(EXIT_FAILURE, "invalid license condition");
561 } else if (strcasecmp(argv[0], "check-single-license") == 0) {
562 if (argv[1] == NULL)
563 errx(EXIT_FAILURE, "check-license takes exactly one argument");
564 load_license_lists();
566 switch (acceptable_license(argv[1])) {
567 case 0:
568 puts("no");
569 return 0;
570 case 1:
571 puts("yes");
572 return 0;
573 case -1:
574 errx(EXIT_FAILURE, "invalid license");
577 #ifndef BOOTSTRAP
578 else if (strcasecmp(argv[0], "findbest") == 0) {
579 struct url *url;
580 char *output;
581 int rc;
583 process_pkg_path();
585 rc = 0;
586 for (++argv; *argv != NULL; ++argv) {
587 url = find_best_package(NULL, *argv, 1);
588 if (url == NULL) {
589 rc = 1;
590 continue;
592 output = fetchStringifyURL(url);
593 puts(output);
594 fetchFreeURL(url);
595 free(output);
598 return rc;
599 } else if (strcasecmp(argv[0], "fetch-pkg-vulnerabilities") == 0) {
600 fetch_pkg_vulnerabilities(--argc, ++argv);
601 } else if (strcasecmp(argv[0], "check-pkg-vulnerabilities") == 0) {
602 check_pkg_vulnerabilities(--argc, ++argv);
603 } else if (strcasecmp(argv[0], "audit") == 0) {
604 audit_pkgdb(--argc, ++argv);
605 } else if (strcasecmp(argv[0], "audit-pkg") == 0) {
606 audit_pkg(--argc, ++argv);
607 } else if (strcasecmp(argv[0], "audit-batch") == 0) {
608 audit_batch(--argc, ++argv);
609 } else if (strcasecmp(argv[0], "audit-history") == 0) {
610 audit_history(--argc, ++argv);
611 } else if (strcasecmp(argv[0], "check-signature") == 0) {
612 struct archive *pkg;
613 int rc;
615 rc = 0;
616 for (--argc, ++argv; argc > 0; --argc, ++argv) {
617 char *archive_name;
619 pkg = open_archive(*argv, &archive_name);
620 if (pkg == NULL) {
621 warnx("%s could not be opened", *argv);
622 continue;
624 if (pkg_full_signature_check(archive_name, &pkg))
625 rc = 1;
626 free(archive_name);
627 if (!pkg)
628 archive_read_finish(pkg);
630 return rc;
631 } else if (strcasecmp(argv[0], "x509-sign-package") == 0) {
632 #ifdef HAVE_SSL
633 --argc;
634 ++argv;
635 if (argc != 4)
636 errx(EXIT_FAILURE, "x509-sign-package takes exactly four arguments");
637 pkg_sign_x509(argv[0], argv[1], argv[2], argv[3]);
638 #else
639 errx(EXIT_FAILURE, "OpenSSL support is not included");
640 #endif
641 } else if (strcasecmp(argv[0], "gpg-sign-package") == 0) {
642 --argc;
643 ++argv;
644 if (argc != 2)
645 errx(EXIT_FAILURE, "gpg-sign-package takes exactly two arguments");
646 pkg_sign_gpg(argv[0], argv[1]);
648 #endif
649 else {
650 usage();
653 return 0;
656 struct set_installed_info_arg {
657 char *variable;
658 char *value;
659 int got_match;
662 static int
663 set_installed_info_var(const char *name, void *cookie)
665 struct set_installed_info_arg *arg = cookie;
666 char *filename;
667 int retval;
669 filename = pkgdb_pkg_file(name, INSTALLED_INFO_FNAME);
671 retval = var_set(filename, arg->variable, arg->value);
673 free(filename);
674 arg->got_match = 1;
676 return retval;
679 static void
680 set_unset_variable(char **argv, Boolean unset)
682 struct set_installed_info_arg arg;
683 char *eq;
684 char *variable;
685 int ret = 0;
687 if (argv[0] == NULL || argv[1] == NULL)
688 usage();
690 variable = NULL;
692 if (unset) {
693 arg.variable = argv[0];
694 arg.value = NULL;
695 } else {
696 eq = NULL;
697 if ((eq=strchr(argv[0], '=')) == NULL)
698 usage();
700 variable = xmalloc(eq-argv[0]+1);
701 strlcpy(variable, argv[0], eq-argv[0]+1);
703 arg.variable = variable;
704 arg.value = eq+1;
706 if (strcmp(variable, AUTOMATIC_VARNAME) == 0 &&
707 strcasecmp(arg.value, "yes") != 0 &&
708 strcasecmp(arg.value, "no") != 0) {
709 errx(EXIT_FAILURE,
710 "unknown value `%s' for " AUTOMATIC_VARNAME,
711 arg.value);
714 if (strpbrk(arg.variable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != NULL) {
715 free(variable);
716 errx(EXIT_FAILURE,
717 "variable name must not contain uppercase letters");
720 argv++;
721 while (*argv != NULL) {
722 arg.got_match = 0;
723 if (match_installed_pkgs(*argv, set_installed_info_var, &arg) == -1)
724 errx(EXIT_FAILURE, "Cannot process pkdbdb");
725 if (arg.got_match == 0) {
726 char *pattern;
728 if (ispkgpattern(*argv)) {
729 warnx("no matching pkg for `%s'", *argv);
730 ret++;
731 } else {
732 pattern = xasprintf("%s-[0-9]*", *argv);
734 if (match_installed_pkgs(pattern, set_installed_info_var, &arg) == -1)
735 errx(EXIT_FAILURE, "Cannot process pkdbdb");
737 if (arg.got_match == 0) {
738 warnx("cannot find package %s", *argv);
739 ++ret;
741 free(pattern);
745 argv++;
748 if (ret > 0)
749 exit(EXIT_FAILURE);
751 free(variable);
753 return;