1 /* $NetBSD: main.c,v 1.58 2009/10/21 17:10:36 joerg Exp $ */
10 __RCSID("$NetBSD: main.c,v 1.58 2009/10/21 17:10:36 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 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");
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
);
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
);
168 for (p
= Plist
.head
; p
; p
= p
->next
) {
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
);
180 warnx("%s: File `%s' is in %s but not on filesystem!",
181 PkgName
, file
, CONTENTS_FNAME
);
184 pkgdb_store(file
, PkgName
);
189 add_pkgdir(PkgName
, dirp
, p
->name
);
190 ++count
->directories
;
193 if (strcmp(p
->name
, ".") != 0) {
196 (void) snprintf(dir
, sizeof(dir
), "%s/%s", PkgDBDir
, pkgdir
);
229 delete1pkg(const char *pkgdir
)
231 if (!pkgdb_open(ReadWrite
))
232 err(EXIT_FAILURE
, "cannot open pkgdb");
233 (void) pkgdb_remove_pkg(pkgdir
);
240 char cachename
[MaxPathSize
];
241 struct pkgdb_count count
;
244 count
.directories
= 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
);
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",
265 lspattern(const char *pkg
, void *vp
)
267 const char *dir
= vp
;
268 printf("%s/%s\n", dir
, pkg
);
273 lsbasepattern(const char *pkg
, void *vp
)
280 remove_required_by(const char *pkgname
, void *cookie
)
284 path
= pkgdb_pkg_file(pkgname
, REQUIRED_BY_FNAME
);
286 if (unlink(path
) == -1 && errno
!= ENOENT
)
287 err(EXIT_FAILURE
, "Cannot remove %s", path
);
295 add_required_by(const char *pattern
, const char *required_by
)
297 char *best_installed
, *path
;
301 best_installed
= find_best_matching_installed_pkg(pattern
);
302 if (best_installed
== NULL
) {
303 warnx("Dependency %s of %s unresolved", pattern
, required_by
);
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
);
314 len
= strlen(required_by
);
315 if (write(fd
, required_by
, len
) != (ssize_t
)len
||
316 write(fd
, "\n", 1) != 1 ||
318 errx(EXIT_FAILURE
, "Cannot write to %s", path
);
323 add_depends_of(const char *pkgname
, void *cookie
)
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
);
335 read_plist(&plist
, fp
);
338 for (p
= plist
.head
; p
; p
= p
->next
) {
339 if (p
->type
== PLIST_PKGDEP
)
340 add_required_by(p
->name
, pkgname
);
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");
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
];
367 setprogname(argv
[0]);
372 while ((ch
= getopt(argc
, argv
, Options
)) != -1)
375 config_file
= optarg
;
379 _pkgdb_setPKGDB_DIR(optarg
);
384 use_default_sfx
= FALSE
;
392 show_basename_only
= TRUE
;
396 (void) strlcpy(lsdir
, optarg
, sizeof(lsdir
));
405 (void) strlcpy(sfx
, optarg
, sizeof(sfx
));
406 use_default_sfx
= FALSE
;
426 * config-var is reading the config file implicitly,
429 if (strcasecmp(argv
[0], "config-var") != 0)
430 pkg_install_config();
433 (void) strlcpy(sfx
, DEFAULT_SFX
, sizeof(sfx
));
435 if (strcasecmp(argv
[0], "pmatch") == 0) {
439 argv
++; /* "pmatch" */
441 if (argv
[0] == NULL
|| argv
[1] == NULL
) {
448 if (pkg_match(pattern
, pkg
)){
454 } else if (strcasecmp(argv
[0], "rebuild") == 0) {
460 } else if (strcasecmp(argv
[0], "rebuild-tree") == 0) {
465 } else if (strcasecmp(argv
[0], "check") == 0) {
466 argv
++; /* "check" */
474 } else if (strcasecmp(argv
[0], "lsall") == 0) {
475 argv
++; /* "lsall" */
477 while (*argv
!= NULL
) {
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
);
488 rc
= match_local_files(dir
, use_default_sfx
, 1, basep
, lspattern
, __UNCONST(dir
));
490 errx(EXIT_FAILURE
, "Error from match_local_files(\"%s\", \"%s\", ...)",
496 } else if (strcasecmp(argv
[0], "lsbest") == 0) {
497 argv
++; /* "lsbest" */
499 while (*argv
!= NULL
) {
501 const char *basep
, *dir
;
504 dir
= lsdirp
? lsdirp
: dirname_of(*argv
);
505 basep
= basename_of(*argv
);
507 p
= find_best_matching_file(dir
, basep
, use_default_sfx
, 1);
510 if (show_basename_only
)
513 printf("%s/%s\n", dir
, p
);
519 } else if (strcasecmp(argv
[0], "list") == 0 ||
520 strcasecmp(argv
[0], "dump") == 0) {
524 } else if (strcasecmp(argv
[0], "add") == 0) {
525 struct pkgdb_count count
;
528 count
.directories
= 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
) {
539 } else if (strcasecmp(argv
[0], "set") == 0) {
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) {
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) {
552 errx(EXIT_FAILURE
, "check-license takes exactly one argument");
554 load_license_lists();
556 switch (acceptable_pkg_license(argv
[1])) {
564 errx(EXIT_FAILURE
, "invalid license condition");
566 } else if (strcasecmp(argv
[0], "check-single-license") == 0) {
568 errx(EXIT_FAILURE
, "check-license takes exactly one argument");
569 load_license_lists();
571 switch (acceptable_license(argv
[1])) {
579 errx(EXIT_FAILURE
, "invalid license");
583 else if (strcasecmp(argv
[0], "findbest") == 0) {
591 for (++argv
; *argv
!= NULL
; ++argv
) {
592 url
= find_best_package(NULL
, *argv
, 1);
597 output
= fetchStringifyURL(url
);
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) {
621 for (--argc
, ++argv
; argc
> 0; --argc
, ++argv
) {
622 pkg
= open_archive(*argv
);
624 warnx("%s could not be opened", *argv
);
627 if (pkg_full_signature_check(&pkg
))
630 archive_read_finish(pkg
);
633 } else if (strcasecmp(argv
[0], "x509-sign-package") == 0) {
638 errx(EXIT_FAILURE
, "x509-sign-package takes exactly four arguments");
639 pkg_sign_x509(argv
[0], argv
[1], argv
[2], argv
[3]);
641 errx(EXIT_FAILURE
, "OpenSSL support is not included");
643 } else if (strcasecmp(argv
[0], "gpg-sign-package") == 0) {
647 errx(EXIT_FAILURE
, "gpg-sign-package takes exactly two arguments");
648 pkg_sign_gpg(argv
[0], argv
[1]);
658 struct set_installed_info_arg
{
665 set_installed_info_var(const char *name
, void *cookie
)
667 struct set_installed_info_arg
*arg
= cookie
;
671 filename
= pkgdb_pkg_file(name
, INSTALLED_INFO_FNAME
);
673 retval
= var_set(filename
, arg
->variable
, arg
->value
);
682 set_unset_variable(char **argv
, Boolean unset
)
684 struct set_installed_info_arg arg
;
689 if (argv
[0] == NULL
|| argv
[1] == NULL
)
695 arg
.variable
= argv
[0];
699 if ((eq
=strchr(argv
[0], '=')) == NULL
)
702 variable
= xmalloc(eq
-argv
[0]+1);
703 strlcpy(variable
, argv
[0], eq
-argv
[0]+1);
705 arg
.variable
= variable
;
708 if (strcmp(variable
, AUTOMATIC_VARNAME
) == 0 &&
709 strcasecmp(arg
.value
, "yes") != 0 &&
710 strcasecmp(arg
.value
, "no") != 0) {
712 "unknown value `%s' for " AUTOMATIC_VARNAME
,
716 if (strpbrk(arg
.variable
, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != NULL
) {
719 "variable name must not contain uppercase letters");
723 while (*argv
!= NULL
) {
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) {
730 if (ispkgpattern(*argv
)) {
731 warnx("no matching pkg for `%s'", *argv
);
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
);