1 /* $NetBSD: main.c,v 1.52 2009/04/25 21:31:13 joerg Exp $ */
10 __RCSID("$NetBSD: main.c,v 1.52 2009/04/25 21:31:13 joerg Exp $");
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
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.
43 #include <sys/types.h>
61 #include <nbcompat/md5.h>
82 #define DEFAULT_SFX ".t[bg]z" /* default suffix for ls{all,best} */
84 static const char Options
[] = "C:K:SVbd:qs:v";
88 static void set_unset_variable(char **, Boolean
);
90 /* print usage message and exit */
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",
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.
130 add_pkg(const char *pkgdir
, void *vp
)
136 const char *PkgDBDir
;
137 char *PkgName
, *dirp
;
138 char file
[MaxPathSize
];
139 char dir
[MaxPathSize
];
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
);
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
);
160 for (p
= Plist
.head
; p
; p
= p
->next
) {
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
);
172 warnx("%s: File `%s' is in %s but not on filesystem!",
173 PkgName
, file
, CONTENTS_FNAME
);
176 pkgdb_store(file
, PkgName
);
181 add_pkgdir(PkgName
, dirp
, p
->name
);
185 if (strcmp(p
->name
, ".") != 0) {
188 (void) snprintf(dir
, sizeof(dir
), "%s/%s", PkgDBDir
, pkgdir
);
221 delete1pkg(const char *pkgdir
)
223 if (!pkgdb_open(ReadWrite
))
224 err(EXIT_FAILURE
, "cannot open pkgdb");
225 (void) pkgdb_remove_pkg(pkgdir
);
232 char cachename
[MaxPathSize
];
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
);
247 printf("Stored %d file%s from %d package%s in %s.\n",
248 filecnt
, filecnt
== 1 ? "" : "s",
249 pkgcnt
, pkgcnt
== 1 ? "" : "s",
254 lspattern(const char *pkg
, void *vp
)
256 const char *dir
= vp
;
257 printf("%s/%s\n", dir
, pkg
);
262 lsbasepattern(const char *pkg
, void *vp
)
269 remove_required_by(const char *pkgname
, void *cookie
)
273 path
= pkgdb_pkg_file(pkgname
, REQUIRED_BY_FNAME
);
275 if (unlink(path
) == -1 && errno
!= ENOENT
)
276 err(EXIT_FAILURE
, "Cannot remove %s", path
);
284 add_required_by(const char *pattern
, const char *required_by
)
286 char *best_installed
, *path
;
290 best_installed
= find_best_matching_installed_pkg(pattern
);
291 if (best_installed
== NULL
) {
292 warnx("Dependency %s of %s unresolved", pattern
, required_by
);
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
);
303 len
= strlen(required_by
);
304 if (write(fd
, required_by
, len
) != len
||
305 write(fd
, "\n", 1) != 1 ||
307 errx(EXIT_FAILURE
, "Cannot write to %s", path
);
312 add_depends_of(const char *pkgname
, void *cookie
)
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
);
324 read_plist(&plist
, fp
);
327 for (p
= plist
.head
; p
; p
= p
->next
) {
328 if (p
->type
== PLIST_PKGDEP
)
329 add_required_by(p
->name
, pkgname
);
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");
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
];
356 setprogname(argv
[0]);
361 while ((ch
= getopt(argc
, argv
, Options
)) != -1)
364 config_file
= optarg
;
368 _pkgdb_setPKGDB_DIR(optarg
);
373 use_default_sfx
= FALSE
;
381 show_basename_only
= TRUE
;
385 (void) strlcpy(lsdir
, optarg
, sizeof(lsdir
));
394 (void) strlcpy(sfx
, optarg
, sizeof(sfx
));
395 use_default_sfx
= FALSE
;
414 pkg_install_config();
417 (void) snprintf(sfx
, sizeof(sfx
), "%s", DEFAULT_SFX
);
419 if (strcasecmp(argv
[0], "pmatch") == 0) {
423 argv
++; /* "pmatch" */
425 if (argv
[0] == NULL
|| argv
[1] == NULL
) {
432 if (pkg_match(pattern
, pkg
)){
438 } else if (strcasecmp(argv
[0], "rebuild") == 0) {
444 } else if (strcasecmp(argv
[0], "rebuild-tree") == 0) {
449 } else if (strcasecmp(argv
[0], "check") == 0) {
450 argv
++; /* "check" */
458 } else if (strcasecmp(argv
[0], "lsall") == 0) {
459 argv
++; /* "lsall" */
461 while (*argv
!= NULL
) {
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
);
472 rc
= match_local_files(dir
, use_default_sfx
, 1, basep
, lspattern
, (void *)dir
);
474 errx(EXIT_FAILURE
, "Error from match_local_files(\"%s\", \"%s\", ...)",
480 } else if (strcasecmp(argv
[0], "lsbest") == 0) {
481 argv
++; /* "lsbest" */
483 while (*argv
!= NULL
) {
485 const char *basep
, *dir
;
488 dir
= lsdirp
? lsdirp
: dirname_of(*argv
);
489 basep
= basename_of(*argv
);
491 p
= find_best_matching_file(dir
, basep
, use_default_sfx
, 1);
494 if (show_basename_only
)
497 printf("%s/%s\n", dir
, p
);
504 } else if (strcasecmp(argv
[0], "list") == 0 ||
505 strcasecmp(argv
[0], "dump") == 0) {
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
) {
518 } else if (strcasecmp(argv
[0], "set") == 0) {
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) {
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) {
531 errx(EXIT_FAILURE
, "check-license takes exactly one argument");
533 load_license_lists();
535 switch (acceptable_pkg_license(argv
[1])) {
543 errx(EXIT_FAILURE
, "invalid license condition");
545 } else if (strcasecmp(argv
[0], "check-single-license") == 0) {
547 errx(EXIT_FAILURE
, "check-license takes exactly one argument");
548 load_license_lists();
550 switch (acceptable_license(argv
[1])) {
558 errx(EXIT_FAILURE
, "invalid license");
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) {
579 for (--argc
, ++argv
; argc
> 0; --argc
, ++argv
) {
580 pkg
= open_archive(*argv
);
582 warnx("%s could not be opened", *argv
);
585 if (pkg_full_signature_check(&pkg
))
588 archive_read_finish(pkg
);
591 } else if (strcasecmp(argv
[0], "x509-sign-package") == 0) {
596 errx(EXIT_FAILURE
, "x509-sign-package takes exactly four arguments");
597 pkg_sign_x509(argv
[0], argv
[1], argv
[2], argv
[3]);
599 errx(EXIT_FAILURE
, "OpenSSL support is not included");
601 } else if (strcasecmp(argv
[0], "gpg-sign-package") == 0) {
605 errx(EXIT_FAILURE
, "gpg-sign-package takes exactly two arguments");
606 pkg_sign_gpg(argv
[0], argv
[1]);
616 struct set_installed_info_arg
{
623 set_installed_info_var(const char *name
, void *cookie
)
625 struct set_installed_info_arg
*arg
= cookie
;
629 filename
= pkgdb_pkg_file(name
, INSTALLED_INFO_FNAME
);
631 retval
= var_set(filename
, arg
->variable
, arg
->value
);
640 set_unset_variable(char **argv
, Boolean unset
)
642 struct set_installed_info_arg arg
;
647 if (argv
[0] == NULL
|| argv
[1] == NULL
)
653 arg
.variable
= argv
[0];
657 if ((eq
=strchr(argv
[0], '=')) == NULL
)
660 variable
= xmalloc(eq
-argv
[0]+1);
661 strlcpy(variable
, argv
[0], eq
-argv
[0]+1);
663 arg
.variable
= variable
;
666 if (strcmp(variable
, AUTOMATIC_VARNAME
) == 0 &&
667 strcasecmp(arg
.value
, "yes") != 0 &&
668 strcasecmp(arg
.value
, "no") != 0) {
670 "unknown value `%s' for " AUTOMATIC_VARNAME
,
674 if (strpbrk(arg
.variable
, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != NULL
) {
677 "variable name must not contain uppercase letters");
681 while (*argv
!= NULL
) {
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) {
688 if (ispkgpattern(*argv
)) {
689 warnx("no matching pkg for `%s'", *argv
);
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
);