Import pkg_install-20090425:
[netbsd-mini2440.git] / external / bsd / pkg_install / dist / admin / main.c
blobcf10405a6527478e0311805600e9a646f358182f
1 /* $NetBSD: main.c,v 1.52 2009/04/25 21:31:13 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.52 2009/04/25 21:31:13 joerg Exp $");
12 /*-
13 * Copyright (c) 1999-2008 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 #endif
79 #include "admin.h"
80 #include "lib.h"
82 #define DEFAULT_SFX ".t[bg]z" /* default suffix for ls{all,best} */
84 static const char Options[] = "C:K:SVbd:qs:v";
86 int quiet, verbose;
88 static void set_unset_variable(char **, Boolean);
90 /* print usage message and exit */
91 void
92 usage(void)
94 (void) fprintf(stderr, "usage: %s [-bqSvV] [-C config] [-d lsdir] [-K pkg_dbdir] [-s sfx] command args ...\n"
95 "Where 'commands' and 'args' are:\n"
96 " rebuild - rebuild pkgdb from +CONTENTS files\n"
97 " rebuild-tree - rebuild +REQUIRED_BY files from forward deps\n"
98 " check [pkg ...] - check md5 checksum of installed files\n"
99 " add pkg ... - add pkg files to database\n"
100 " delete pkg ... - delete file entries for pkg in database\n"
101 " set variable=value pkg ... - set installation variable for package\n"
102 " unset variable pkg ... - unset installation variable for package\n"
103 " lsall /path/to/pkgpattern - list all pkgs matching the pattern\n"
104 " lsbest /path/to/pkgpattern - list pkgs matching the pattern best\n"
105 " dump - dump database\n"
106 " pmatch pattern pkg - returns true if pkg matches pattern, otherwise false\n"
107 " fetch-pkg-vulnerabilities [-s] - fetch new vulnerability file\n"
108 " check-pkg-vulnerabilities [-s] <file> - check syntax and checksums of the vulnerability file\n"
109 " audit [-es] [-t type] ... - check installed packages for vulnerabilities\n"
110 " audit-pkg [-es] [-t type] ... - check listed packages for vulnerabilities\n"
111 " audit-batch [-es] [-t type] ... - check packages in listed files for vulnerabilities\n"
112 " audit-history [-t type] ... - print all advisories for package names\n"
113 " check-license <condition> - check if condition is acceptable\n"
114 " check-single-license <license> - check if license is acceptable\n"
115 " config-var name - print current value of the configuration variable\n"
116 " check-signature ... - verify the signature of packages\n"
117 " x509-sign-package pkg spkg key cert - create X509 signature\n"
118 " gpg-sign-package pkg spkg - create GPG signature\n",
119 getprogname());
120 exit(EXIT_FAILURE);
124 * add1pkg(<pkg>)
125 * adds the files listed in the +CONTENTS of <pkg> into the
126 * pkgdb.byfile.db database file in the current package dbdir. It
127 * returns the number of files added to the database file.
129 static int
130 add_pkg(const char *pkgdir, void *vp)
132 FILE *f;
133 plist_t *p;
134 package_t Plist;
135 char *contents;
136 const char *PkgDBDir;
137 char *PkgName, *dirp;
138 char file[MaxPathSize];
139 char dir[MaxPathSize];
140 int tmp, *cnt;
142 if (!pkgdb_open(ReadWrite))
143 err(EXIT_FAILURE, "cannot open pkgdb");
145 cnt = vp != NULL ? vp : &tmp;
147 PkgDBDir = _pkgdb_getPKGDB_DIR();
148 contents = pkgdb_pkg_file(pkgdir, CONTENTS_FNAME);
149 if ((f = fopen(contents, "r")) == NULL)
150 errx(EXIT_FAILURE, "%s: can't open `%s'", pkgdir, CONTENTS_FNAME);
151 free(contents);
153 read_plist(&Plist, f);
154 if ((p = find_plist(&Plist, PLIST_NAME)) == NULL) {
155 errx(EXIT_FAILURE, "Package `%s' has no @name, aborting.", pkgdir);
158 PkgName = p->name;
159 dirp = NULL;
160 for (p = Plist.head; p; p = p->next) {
161 switch(p->type) {
162 case PLIST_FILE:
163 if (dirp == NULL) {
164 errx(EXIT_FAILURE, "@cwd not yet found, please send-pr!");
166 (void) snprintf(file, sizeof(file), "%s/%s", dirp, p->name);
167 if (!(isfile(file) || islinktodir(file))) {
168 if (isbrokenlink(file)) {
169 warnx("%s: Symlink `%s' exists and is in %s but target does not exist!",
170 PkgName, file, CONTENTS_FNAME);
171 } else {
172 warnx("%s: File `%s' is in %s but not on filesystem!",
173 PkgName, file, CONTENTS_FNAME);
175 } else {
176 pkgdb_store(file, PkgName);
177 (*cnt)++;
179 break;
180 case PLIST_PKGDIR:
181 add_pkgdir(PkgName, dirp, p->name);
182 (*cnt)++;
183 break;
184 case PLIST_CWD:
185 if (strcmp(p->name, ".") != 0) {
186 dirp = p->name;
187 } else {
188 (void) snprintf(dir, sizeof(dir), "%s/%s", PkgDBDir, pkgdir);
189 dirp = dir;
191 break;
192 case PLIST_IGNORE:
193 p = p->next;
194 break;
195 case PLIST_SHOW_ALL:
196 case PLIST_SRC:
197 case PLIST_CMD:
198 case PLIST_CHMOD:
199 case PLIST_CHOWN:
200 case PLIST_CHGRP:
201 case PLIST_COMMENT:
202 case PLIST_NAME:
203 case PLIST_UNEXEC:
204 case PLIST_DISPLAY:
205 case PLIST_PKGDEP:
206 case PLIST_DIR_RM:
207 case PLIST_OPTION:
208 case PLIST_PKGCFL:
209 case PLIST_BLDDEP:
210 break;
213 free_plist(&Plist);
214 fclose(f);
215 pkgdb_close();
217 return 0;
220 static void
221 delete1pkg(const char *pkgdir)
223 if (!pkgdb_open(ReadWrite))
224 err(EXIT_FAILURE, "cannot open pkgdb");
225 (void) pkgdb_remove_pkg(pkgdir);
226 pkgdb_close();
229 static void
230 rebuild(void)
232 char cachename[MaxPathSize];
233 int pkgcnt, filecnt;
235 pkgcnt = 0;
236 filecnt = 0;
238 (void) _pkgdb_getPKGDB_FILE(cachename, sizeof(cachename));
239 if (unlink(cachename) != 0 && errno != ENOENT)
240 err(EXIT_FAILURE, "unlink %s", cachename);
242 setbuf(stdout, NULL);
244 iterate_pkg_db(add_pkg, &filecnt);
246 printf("\n");
247 printf("Stored %d file%s from %d package%s in %s.\n",
248 filecnt, filecnt == 1 ? "" : "s",
249 pkgcnt, pkgcnt == 1 ? "" : "s",
250 cachename);
253 static int
254 lspattern(const char *pkg, void *vp)
256 const char *dir = vp;
257 printf("%s/%s\n", dir, pkg);
258 return 0;
261 static int
262 lsbasepattern(const char *pkg, void *vp)
264 puts(pkg);
265 return 0;
268 static int
269 remove_required_by(const char *pkgname, void *cookie)
271 char *path;
273 path = pkgdb_pkg_file(pkgname, REQUIRED_BY_FNAME);
275 if (unlink(path) == -1 && errno != ENOENT)
276 err(EXIT_FAILURE, "Cannot remove %s", path);
278 free(path);
280 return 0;
283 static void
284 add_required_by(const char *pattern, const char *required_by)
286 char *best_installed, *path;
287 int fd;
288 size_t len;
290 best_installed = find_best_matching_installed_pkg(pattern);
291 if (best_installed == NULL) {
292 warnx("Dependency %s of %s unresolved", pattern, required_by);
293 return;
296 path = pkgdb_pkg_file(best_installed, REQUIRED_BY_FNAME);
297 free(best_installed);
299 if ((fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0644)) == -1)
300 errx(EXIT_FAILURE, "Cannot write to %s", path);
301 free(path);
303 len = strlen(required_by);
304 if (write(fd, required_by, len) != len ||
305 write(fd, "\n", 1) != 1 ||
306 close(fd) == -1)
307 errx(EXIT_FAILURE, "Cannot write to %s", path);
311 static int
312 add_depends_of(const char *pkgname, void *cookie)
314 FILE *fp;
315 plist_t *p;
316 package_t plist;
317 char *path;
319 path = pkgdb_pkg_file(pkgname, CONTENTS_FNAME);
320 if ((fp = fopen(path, "r")) == NULL)
321 errx(EXIT_FAILURE, "Cannot read %s of package %s",
322 CONTENTS_FNAME, pkgname);
323 free(path);
324 read_plist(&plist, fp);
325 fclose(fp);
327 for (p = plist.head; p; p = p->next) {
328 if (p->type == PLIST_PKGDEP)
329 add_required_by(p->name, pkgname);
332 free_plist(&plist);
334 return 0;
337 static void
338 rebuild_tree(void)
340 if (iterate_pkg_db(remove_required_by, NULL) == -1)
341 errx(EXIT_FAILURE, "cannot iterate pkgdb");
342 if (iterate_pkg_db(add_depends_of, NULL) == -1)
343 errx(EXIT_FAILURE, "cannot iterate pkgdb");
346 int
347 main(int argc, char *argv[])
349 Boolean use_default_sfx = TRUE;
350 Boolean show_basename_only = FALSE;
351 char lsdir[MaxPathSize];
352 char sfx[MaxPathSize];
353 char *lsdirp = NULL;
354 int ch;
356 setprogname(argv[0]);
358 if (argc < 2)
359 usage();
361 while ((ch = getopt(argc, argv, Options)) != -1)
362 switch (ch) {
363 case 'C':
364 config_file = optarg;
365 break;
367 case 'K':
368 _pkgdb_setPKGDB_DIR(optarg);
369 break;
371 case 'S':
372 sfx[0] = 0x0;
373 use_default_sfx = FALSE;
374 break;
376 case 'V':
377 show_version();
378 /* NOTREACHED */
380 case 'b':
381 show_basename_only = TRUE;
382 break;
384 case 'd':
385 (void) strlcpy(lsdir, optarg, sizeof(lsdir));
386 lsdirp = lsdir;
387 break;
389 case 'q':
390 quiet = 1;
391 break;
393 case 's':
394 (void) strlcpy(sfx, optarg, sizeof(sfx));
395 use_default_sfx = FALSE;
396 break;
398 case 'v':
399 ++verbose;
400 break;
402 default:
403 usage();
404 /* NOTREACHED */
407 argc -= optind;
408 argv += optind;
410 if (argc <= 0) {
411 usage();
414 pkg_install_config();
416 if (use_default_sfx)
417 (void) snprintf(sfx, sizeof(sfx), "%s", DEFAULT_SFX);
419 if (strcasecmp(argv[0], "pmatch") == 0) {
421 char *pattern, *pkg;
423 argv++; /* "pmatch" */
425 if (argv[0] == NULL || argv[1] == NULL) {
426 usage();
429 pattern = argv[0];
430 pkg = argv[1];
432 if (pkg_match(pattern, pkg)){
433 return 0;
434 } else {
435 return 1;
438 } else if (strcasecmp(argv[0], "rebuild") == 0) {
440 rebuild();
441 printf("Done.\n");
444 } else if (strcasecmp(argv[0], "rebuild-tree") == 0) {
446 rebuild_tree();
447 printf("Done.\n");
449 } else if (strcasecmp(argv[0], "check") == 0) {
450 argv++; /* "check" */
452 check(argv);
454 if (!quiet) {
455 printf("Done.\n");
458 } else if (strcasecmp(argv[0], "lsall") == 0) {
459 argv++; /* "lsall" */
461 while (*argv != NULL) {
462 /* args specified */
463 int rc;
464 const char *basep, *dir;
466 dir = lsdirp ? lsdirp : dirname_of(*argv);
467 basep = basename_of(*argv);
469 if (show_basename_only)
470 rc = match_local_files(dir, use_default_sfx, 1, basep, lsbasepattern, NULL);
471 else
472 rc = match_local_files(dir, use_default_sfx, 1, basep, lspattern, (void *)dir);
473 if (rc == -1)
474 errx(EXIT_FAILURE, "Error from match_local_files(\"%s\", \"%s\", ...)",
475 dir, basep);
477 argv++;
480 } else if (strcasecmp(argv[0], "lsbest") == 0) {
481 argv++; /* "lsbest" */
483 while (*argv != NULL) {
484 /* args specified */
485 const char *basep, *dir;
486 char *p;
488 dir = lsdirp ? lsdirp : dirname_of(*argv);
489 basep = basename_of(*argv);
491 p = find_best_matching_file(dir, basep, use_default_sfx, 1);
493 if (p) {
494 if (show_basename_only)
495 printf("%s\n", p);
496 else
497 printf("%s/%s\n", dir, p);
498 free(p);
501 argv++;
504 } else if (strcasecmp(argv[0], "list") == 0 ||
505 strcasecmp(argv[0], "dump") == 0) {
507 pkgdb_dump();
509 } else if (strcasecmp(argv[0], "add") == 0) {
510 for (++argv; *argv != NULL; ++argv)
511 add_pkg(*argv, NULL);
512 } else if (strcasecmp(argv[0], "delete") == 0) {
513 argv++; /* "delete" */
514 while (*argv != NULL) {
515 delete1pkg(*argv);
516 argv++;
518 } else if (strcasecmp(argv[0], "set") == 0) {
519 argv++; /* "set" */
520 set_unset_variable(argv, FALSE);
521 } else if (strcasecmp(argv[0], "unset") == 0) {
522 argv++; /* "unset" */
523 set_unset_variable(argv, TRUE);
524 } else if (strcasecmp(argv[0], "config-var") == 0) {
525 argv++;
526 if (argv == NULL || argv[1] != NULL)
527 errx(EXIT_FAILURE, "config-var takes exactly one argument");
528 pkg_install_show_variable(argv[0]);
529 } else if (strcasecmp(argv[0], "check-license") == 0) {
530 if (argv[1] == NULL)
531 errx(EXIT_FAILURE, "check-license takes exactly one argument");
533 load_license_lists();
535 switch (acceptable_pkg_license(argv[1])) {
536 case 0:
537 puts("no");
538 return 0;
539 case 1:
540 puts("yes");
541 return 0;
542 case -1:
543 errx(EXIT_FAILURE, "invalid license condition");
545 } else if (strcasecmp(argv[0], "check-single-license") == 0) {
546 if (argv[1] == NULL)
547 errx(EXIT_FAILURE, "check-license takes exactly one argument");
548 load_license_lists();
550 switch (acceptable_license(argv[1])) {
551 case 0:
552 puts("no");
553 return 0;
554 case 1:
555 puts("yes");
556 return 0;
557 case -1:
558 errx(EXIT_FAILURE, "invalid license");
561 #ifndef BOOTSTRAP
562 else if (strcasecmp(argv[0], "fetch-pkg-vulnerabilities") == 0) {
563 fetch_pkg_vulnerabilities(--argc, ++argv);
564 } else if (strcasecmp(argv[0], "check-pkg-vulnerabilities") == 0) {
565 check_pkg_vulnerabilities(--argc, ++argv);
566 } else if (strcasecmp(argv[0], "audit") == 0) {
567 audit_pkgdb(--argc, ++argv);
568 } else if (strcasecmp(argv[0], "audit-pkg") == 0) {
569 audit_pkg(--argc, ++argv);
570 } else if (strcasecmp(argv[0], "audit-batch") == 0) {
571 audit_batch(--argc, ++argv);
572 } else if (strcasecmp(argv[0], "audit-history") == 0) {
573 audit_history(--argc, ++argv);
574 } else if (strcasecmp(argv[0], "check-signature") == 0) {
575 struct archive *pkg;
576 int rc;
578 rc = 0;
579 for (--argc, ++argv; argc > 0; --argc, ++argv) {
580 pkg = open_archive(*argv);
581 if (pkg == NULL) {
582 warnx("%s could not be opened", *argv);
583 continue;
585 if (pkg_full_signature_check(&pkg))
586 rc = 1;
587 if (!pkg)
588 archive_read_finish(pkg);
590 return rc;
591 } else if (strcasecmp(argv[0], "x509-sign-package") == 0) {
592 #ifdef HAVE_SSL
593 --argc;
594 ++argv;
595 if (argc != 4)
596 errx(EXIT_FAILURE, "x509-sign-package takes exactly four arguments");
597 pkg_sign_x509(argv[0], argv[1], argv[2], argv[3]);
598 #else
599 errx(EXIT_FAILURE, "OpenSSL support is not included");
600 #endif
601 } else if (strcasecmp(argv[0], "gpg-sign-package") == 0) {
602 --argc;
603 ++argv;
604 if (argc != 2)
605 errx(EXIT_FAILURE, "gpg-sign-package takes exactly two arguments");
606 pkg_sign_gpg(argv[0], argv[1]);
608 #endif
609 else {
610 usage();
613 return 0;
616 struct set_installed_info_arg {
617 char *variable;
618 char *value;
619 int got_match;
622 static int
623 set_installed_info_var(const char *name, void *cookie)
625 struct set_installed_info_arg *arg = cookie;
626 char *filename;
627 int retval;
629 filename = pkgdb_pkg_file(name, INSTALLED_INFO_FNAME);
631 retval = var_set(filename, arg->variable, arg->value);
633 free(filename);
634 arg->got_match = 1;
636 return retval;
639 static void
640 set_unset_variable(char **argv, Boolean unset)
642 struct set_installed_info_arg arg;
643 char *eq;
644 char *variable;
645 int ret = 0;
647 if (argv[0] == NULL || argv[1] == NULL)
648 usage();
650 variable = NULL;
652 if (unset) {
653 arg.variable = argv[0];
654 arg.value = NULL;
655 } else {
656 eq = NULL;
657 if ((eq=strchr(argv[0], '=')) == NULL)
658 usage();
660 variable = xmalloc(eq-argv[0]+1);
661 strlcpy(variable, argv[0], eq-argv[0]+1);
663 arg.variable = variable;
664 arg.value = eq+1;
666 if (strcmp(variable, AUTOMATIC_VARNAME) == 0 &&
667 strcasecmp(arg.value, "yes") != 0 &&
668 strcasecmp(arg.value, "no") != 0) {
669 errx(EXIT_FAILURE,
670 "unknown value `%s' for " AUTOMATIC_VARNAME,
671 arg.value);
674 if (strpbrk(arg.variable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != NULL) {
675 free(variable);
676 errx(EXIT_FAILURE,
677 "variable name must not contain uppercase letters");
680 argv++;
681 while (*argv != NULL) {
682 arg.got_match = 0;
683 if (match_installed_pkgs(*argv, set_installed_info_var, &arg) == -1)
684 errx(EXIT_FAILURE, "Cannot process pkdbdb");
685 if (arg.got_match == 0) {
686 char *pattern;
688 if (ispkgpattern(*argv)) {
689 warnx("no matching pkg for `%s'", *argv);
690 ret++;
691 } else {
692 pattern = xasprintf("%s-[0-9]*", *argv);
694 if (match_installed_pkgs(pattern, set_installed_info_var, &arg) == -1)
695 errx(EXIT_FAILURE, "Cannot process pkdbdb");
697 if (arg.got_match == 0) {
698 warnx("cannot find package %s", *argv);
699 ++ret;
701 free(pattern);
705 argv++;
708 if (ret > 0)
709 exit(EXIT_FAILURE);
711 free(variable);
713 return;
716 void
717 cleanup(int signo)