1 /* $NetBSD: main.c,v 1.1.1.15 2010/04/23 20:54:07 joerg Exp $ */
10 __RCSID("$NetBSD: main.c,v 1.1.1.15 2010/04/23 20:54:07 joerg Exp $");
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
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>
83 #define DEFAULT_SFX ".t[bg]z" /* default suffix for ls{all,best} */
91 static const char Options
[] = "C:K:SVbd:qs:v";
95 static void set_unset_variable(char **, Boolean
);
97 /* print usage message and exit */
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",
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.
137 add_pkg(const char *pkgdir
, void *vp
)
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");
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
);
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
);
165 for (p
= Plist
.head
; p
; p
= p
->next
) {
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
);
177 warnx("%s: File `%s' is in %s but not on filesystem!",
178 PkgName
, file
, CONTENTS_FNAME
);
181 pkgdb_store(file
, PkgName
);
186 add_pkgdir(PkgName
, dirp
, p
->name
);
187 ++count
->directories
;
190 if (strcmp(p
->name
, ".") != 0)
193 dirp
= pkgdb_pkg_dir(pkgdir
);
224 delete1pkg(const char *pkgdir
)
226 if (!pkgdb_open(ReadWrite
))
227 err(EXIT_FAILURE
, "cannot open pkgdb");
228 (void) pkgdb_remove_pkg(pkgdir
);
236 struct pkgdb_count count
;
239 count
.directories
= 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
);
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",
260 lspattern(const char *pkg
, void *vp
)
262 const char *dir
= vp
;
263 printf("%s/%s\n", dir
, pkg
);
268 lsbasepattern(const char *pkg
, void *vp
)
275 remove_required_by(const char *pkgname
, void *cookie
)
279 path
= pkgdb_pkg_file(pkgname
, REQUIRED_BY_FNAME
);
281 if (unlink(path
) == -1 && errno
!= ENOENT
)
282 err(EXIT_FAILURE
, "Cannot remove %s", path
);
290 add_required_by(const char *pattern
, const char *required_by
)
292 char *best_installed
, *path
;
296 best_installed
= find_best_matching_installed_pkg(pattern
);
297 if (best_installed
== NULL
) {
298 warnx("Dependency %s of %s unresolved", pattern
, required_by
);
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
);
309 len
= strlen(required_by
);
310 if (write(fd
, required_by
, len
) != (ssize_t
)len
||
311 write(fd
, "\n", 1) != 1 ||
313 errx(EXIT_FAILURE
, "Cannot write to %s", path
);
318 add_depends_of(const char *pkgname
, void *cookie
)
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
);
330 read_plist(&plist
, fp
);
333 for (p
= plist
.head
; p
; p
= p
->next
) {
334 if (p
->type
== PLIST_PKGDEP
)
335 add_required_by(p
->name
, pkgname
);
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");
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
];
362 setprogname(argv
[0]);
367 while ((ch
= getopt(argc
, argv
, Options
)) != -1)
370 config_file
= optarg
;
374 pkgdb_set_dir(optarg
, 3);
379 use_default_sfx
= FALSE
;
387 show_basename_only
= TRUE
;
391 (void) strlcpy(lsdir
, optarg
, sizeof(lsdir
));
400 (void) strlcpy(sfx
, optarg
, sizeof(sfx
));
401 use_default_sfx
= FALSE
;
421 * config-var is reading the config file implicitly,
424 if (strcasecmp(argv
[0], "config-var") != 0)
425 pkg_install_config();
428 (void) strlcpy(sfx
, DEFAULT_SFX
, sizeof(sfx
));
430 if (strcasecmp(argv
[0], "pmatch") == 0) {
434 argv
++; /* "pmatch" */
436 if (argv
[0] == NULL
|| argv
[1] == NULL
) {
443 if (pkg_match(pattern
, pkg
)){
449 } else if (strcasecmp(argv
[0], "rebuild") == 0) {
455 } else if (strcasecmp(argv
[0], "rebuild-tree") == 0) {
460 } else if (strcasecmp(argv
[0], "check") == 0) {
461 argv
++; /* "check" */
469 } else if (strcasecmp(argv
[0], "lsall") == 0) {
470 argv
++; /* "lsall" */
472 while (*argv
!= NULL
) {
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
);
483 rc
= match_local_files(dir
, use_default_sfx
, 1, basep
, lspattern
, __UNCONST(dir
));
485 errx(EXIT_FAILURE
, "Error from match_local_files(\"%s\", \"%s\", ...)",
491 } else if (strcasecmp(argv
[0], "lsbest") == 0) {
492 argv
++; /* "lsbest" */
494 while (*argv
!= NULL
) {
496 const char *basep
, *dir
;
499 dir
= lsdirp
? lsdirp
: dirname_of(*argv
);
500 basep
= basename_of(*argv
);
502 p
= find_best_matching_file(dir
, basep
, use_default_sfx
, 1);
505 if (show_basename_only
)
508 printf("%s/%s\n", dir
, p
);
514 } else if (strcasecmp(argv
[0], "list") == 0 ||
515 strcasecmp(argv
[0], "dump") == 0) {
519 } else if (strcasecmp(argv
[0], "add") == 0) {
520 struct pkgdb_count count
;
523 count
.directories
= 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
) {
534 } else if (strcasecmp(argv
[0], "set") == 0) {
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) {
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) {
547 errx(EXIT_FAILURE
, "check-license takes exactly one argument");
549 load_license_lists();
551 switch (acceptable_pkg_license(argv
[1])) {
559 errx(EXIT_FAILURE
, "invalid license condition");
561 } else if (strcasecmp(argv
[0], "check-single-license") == 0) {
563 errx(EXIT_FAILURE
, "check-license takes exactly one argument");
564 load_license_lists();
566 switch (acceptable_license(argv
[1])) {
574 errx(EXIT_FAILURE
, "invalid license");
578 else if (strcasecmp(argv
[0], "findbest") == 0) {
586 for (++argv
; *argv
!= NULL
; ++argv
) {
587 url
= find_best_package(NULL
, *argv
, 1);
592 output
= fetchStringifyURL(url
);
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) {
616 for (--argc
, ++argv
; argc
> 0; --argc
, ++argv
) {
619 pkg
= open_archive(*argv
, &archive_name
);
621 warnx("%s could not be opened", *argv
);
624 if (pkg_full_signature_check(archive_name
, &pkg
))
628 archive_read_finish(pkg
);
631 } else if (strcasecmp(argv
[0], "x509-sign-package") == 0) {
636 errx(EXIT_FAILURE
, "x509-sign-package takes exactly four arguments");
637 pkg_sign_x509(argv
[0], argv
[1], argv
[2], argv
[3]);
639 errx(EXIT_FAILURE
, "OpenSSL support is not included");
641 } else if (strcasecmp(argv
[0], "gpg-sign-package") == 0) {
645 errx(EXIT_FAILURE
, "gpg-sign-package takes exactly two arguments");
646 pkg_sign_gpg(argv
[0], argv
[1]);
656 struct set_installed_info_arg
{
663 set_installed_info_var(const char *name
, void *cookie
)
665 struct set_installed_info_arg
*arg
= cookie
;
669 filename
= pkgdb_pkg_file(name
, INSTALLED_INFO_FNAME
);
671 retval
= var_set(filename
, arg
->variable
, arg
->value
);
680 set_unset_variable(char **argv
, Boolean unset
)
682 struct set_installed_info_arg arg
;
687 if (argv
[0] == NULL
|| argv
[1] == NULL
)
693 arg
.variable
= argv
[0];
697 if ((eq
=strchr(argv
[0], '=')) == NULL
)
700 variable
= xmalloc(eq
-argv
[0]+1);
701 strlcpy(variable
, argv
[0], eq
-argv
[0]+1);
703 arg
.variable
= variable
;
706 if (strcmp(variable
, AUTOMATIC_VARNAME
) == 0 &&
707 strcasecmp(arg
.value
, "yes") != 0 &&
708 strcasecmp(arg
.value
, "no") != 0) {
710 "unknown value `%s' for " AUTOMATIC_VARNAME
,
714 if (strpbrk(arg
.variable
, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != NULL
) {
717 "variable name must not contain uppercase letters");
721 while (*argv
!= NULL
) {
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) {
728 if (ispkgpattern(*argv
)) {
729 warnx("no matching pkg for `%s'", *argv
);
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
);