xref: /openbsd-src/usr.sbin/kvm_mkdb/kvm_mkdb.c (revision b7041c0781c8668129da8084451ded41b0c43954)
1*b7041c07Sderaadt /*	$OpenBSD: kvm_mkdb.c,v 1.33 2021/10/24 21:24:18 deraadt Exp $	*/
22d682701Smillert 
3df930be7Sderaadt /*-
4df930be7Sderaadt  * Copyright (c) 1990, 1993
5df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
6df930be7Sderaadt  *
7df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
8df930be7Sderaadt  * modification, are permitted provided that the following conditions
9df930be7Sderaadt  * are met:
10df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
11df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
12df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
13df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
14df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
1529295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
16df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
17df930be7Sderaadt  *    without specific prior written permission.
18df930be7Sderaadt  *
19df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29df930be7Sderaadt  * SUCH DAMAGE.
30df930be7Sderaadt  */
31df930be7Sderaadt 
32df930be7Sderaadt #include <sys/stat.h>
330a256418Stedu #include <sys/types.h>
340a256418Stedu #include <sys/time.h>
350a256418Stedu #include <sys/resource.h>
36df930be7Sderaadt 
37df930be7Sderaadt #include <db.h>
38df930be7Sderaadt #include <err.h>
39df930be7Sderaadt #include <errno.h>
40df930be7Sderaadt #include <fcntl.h>
41c59ab75fSmillert #include <libgen.h>
42df930be7Sderaadt #include <paths.h>
43df930be7Sderaadt #include <stdio.h>
44df930be7Sderaadt #include <stdlib.h>
45df930be7Sderaadt #include <string.h>
46c59ab75fSmillert #include <unistd.h>
470a256418Stedu #include <grp.h>
4856b08df7Smillert 
49df930be7Sderaadt #include "extern.h"
50df930be7Sderaadt 
5136246103Smillert __dead void usage(void);
5236246103Smillert int kvm_mkdb(int, const char *, char *, char *, gid_t, int);
53df930be7Sderaadt 
54df930be7Sderaadt HASHINFO openinfo = {
55df930be7Sderaadt 	4096,		/* bsize */
56df930be7Sderaadt 	128,		/* ffactor */
57df930be7Sderaadt 	1024,		/* nelem */
58df930be7Sderaadt 	2048 * 1024,	/* cachesize */
59df930be7Sderaadt 	NULL,		/* hash() */
60df930be7Sderaadt 	0		/* lorder */
61df930be7Sderaadt };
62df930be7Sderaadt 
63df930be7Sderaadt int
main(int argc,char * argv[])6400da5b9dSderaadt main(int argc, char *argv[])
65df930be7Sderaadt {
6656b08df7Smillert 	struct rlimit rl;
6736246103Smillert 	struct group *gr;
6836246103Smillert 	gid_t kvm_gid = -1;
6932131dd8Smillert 	int fd, rval, ch, verbose = 0;
7089cce642Smillert 	char *nlistpath, *nlistname;
71b9fc9a72Sderaadt 	char dbdir[PATH_MAX];
72df930be7Sderaadt 
7330f341d9Smestre 	if (pledge("stdio rpath wpath cpath fattr getpw flock id unveil", NULL) == -1)
7436246103Smillert 		err(1, "pledge");
7536246103Smillert 
7636246103Smillert 	/* Try to use the kmem group to be able to fchown() in kvm_mkdb(). */
7736246103Smillert 	if ((gr = getgrnam("kmem")) == NULL) {
7836246103Smillert 		warn("can't find kmem group");
7936246103Smillert 	} else {
8036246103Smillert 		kvm_gid = gr->gr_gid;
8170885aeaSderaadt 		if (setresgid(kvm_gid, kvm_gid, kvm_gid) == -1)
825eee0837Stb 			err(1, "setresgid");
8336246103Smillert 	}
8436246103Smillert 
8556b08df7Smillert 	/* Increase our data size to the max if we can. */
8656b08df7Smillert 	if (getrlimit(RLIMIT_DATA, &rl) == 0) {
8756b08df7Smillert 		rl.rlim_cur = rl.rlim_max;
88df69c215Sderaadt 		if (setrlimit(RLIMIT_DATA, &rl) == -1)
8956b08df7Smillert 			warn("can't set rlimit data size");
9056b08df7Smillert 	}
9156b08df7Smillert 
9230f341d9Smestre 	if (pledge("stdio rpath wpath cpath fattr flock unveil", NULL) == -1)
9336246103Smillert 		err(1, "pledge");
9436246103Smillert 
95fe75eb04Sdjm 	strlcpy(dbdir, _PATH_VARDB, sizeof(dbdir));
96fe75eb04Sdjm 	while ((ch = getopt(argc, argv, "vo:")) != -1)
97df930be7Sderaadt 		switch (ch) {
98c59ab75fSmillert 		case 'v':
99c59ab75fSmillert 			verbose = 1;
100c59ab75fSmillert 			break;
101fe75eb04Sdjm 		case 'o':
102fe75eb04Sdjm 			rval = strlcpy(dbdir, optarg, sizeof(dbdir));
103fe75eb04Sdjm 			if (rval == 0 || rval + 1 >= sizeof(dbdir))
104fe75eb04Sdjm 				errx(1, "Invalid directory");
105fe75eb04Sdjm 			/* Make sure there is a '/' at the end of the path */
106fe75eb04Sdjm 			if (dbdir[strlen(dbdir) - 1] != '/')
107fe75eb04Sdjm 				strlcat(dbdir, "/", sizeof(dbdir));
108fe75eb04Sdjm 			break;
109df930be7Sderaadt 		default:
110df930be7Sderaadt 			usage();
111df930be7Sderaadt 		}
112df930be7Sderaadt 	argc -= optind;
113df930be7Sderaadt 	argv += optind;
114df930be7Sderaadt 
115df930be7Sderaadt 	if (argc > 1)
116df930be7Sderaadt 		usage();
117df930be7Sderaadt 
11830f341d9Smestre 	if (argc > 0) {
11930f341d9Smestre 		if (unveil(argv[0], "r") == -1)
120bc5a8259Sbeck 			err(1, "unveil %s", argv[0]);
12130f341d9Smestre 	} else {
12230f341d9Smestre 		if (unveil(_PATH_UNIX, "r") == -1)
123bc5a8259Sbeck 			err(1, "unveil %s", _PATH_UNIX);
12430f341d9Smestre 		if (unveil(_PATH_KSYMS, "r") == -1)
125bc5a8259Sbeck 			err(1, "unveil %s", _PATH_KSYMS);
12630f341d9Smestre 	}
12730f341d9Smestre 	if (unveil(dbdir, "rwc") == -1)
128bc5a8259Sbeck 		err(1, "unveil %s", dbdir);
12930f341d9Smestre 	if (pledge("stdio rpath wpath cpath fattr flock", NULL) == -1)
13030f341d9Smestre 		err(1, "pledge");
13130f341d9Smestre 
132da2f7a99Smillert 	/* If no kernel specified use _PATH_KSYMS and fall back to _PATH_UNIX */
133da2f7a99Smillert 	if (argc > 0) {
134da2f7a99Smillert 		nlistpath = argv[0];
13532131dd8Smillert 		nlistname = basename(nlistpath);
136*b7041c07Sderaadt 		if ((fd = open(nlistpath, O_RDONLY)) == -1)
13732131dd8Smillert 			err(1, "can't open %s", nlistpath);
13836246103Smillert 		rval = kvm_mkdb(fd, dbdir, nlistpath, nlistname, kvm_gid,
13936246103Smillert 		    verbose);
140da2f7a99Smillert 	} else {
14189cce642Smillert 		nlistname = basename(_PATH_UNIX);
142*b7041c07Sderaadt 		if ((fd = open((nlistpath = _PATH_KSYMS), O_RDONLY)) == -1 ||
14336246103Smillert 		    (rval = kvm_mkdb(fd, dbdir, nlistpath, nlistname, kvm_gid,
144fe75eb04Sdjm 		    verbose)) != 0) {
1459da998eeSespie 			if (fd == -1)
1469da998eeSespie 				warnx("can't open %s", _PATH_KSYMS);
1479da998eeSespie 			else
1489da998eeSespie 				warnx("will try again using %s instead", _PATH_UNIX);
149*b7041c07Sderaadt 			if ((fd = open((nlistpath = _PATH_UNIX), O_RDONLY)) == -1)
15032131dd8Smillert 				err(1, "can't open %s", nlistpath);
151fe75eb04Sdjm 			rval = kvm_mkdb(fd, dbdir, nlistpath, nlistname,
15236246103Smillert 			    kvm_gid, verbose);
153da2f7a99Smillert 		}
15489cce642Smillert 	}
15589cce642Smillert 	exit(rval);
15689cce642Smillert }
15789cce642Smillert 
15889cce642Smillert int
kvm_mkdb(int fd,const char * dbdir,char * nlistpath,char * nlistname,gid_t gid,int verbose)15936246103Smillert kvm_mkdb(int fd, const char *dbdir, char *nlistpath, char *nlistname, gid_t gid,
160fe75eb04Sdjm     int verbose)
16189cce642Smillert {
16289cce642Smillert 	DB *db;
163b9fc9a72Sderaadt 	char dbtemp[PATH_MAX], dbname[PATH_MAX];
164fe75eb04Sdjm 	int r;
16589cce642Smillert 
166fe75eb04Sdjm 	r = snprintf(dbtemp, sizeof(dbtemp), "%skvm_%s.tmp",
167fe75eb04Sdjm 	    dbdir, nlistname);
1688ebf3ea0Sdjm 	if (r < 0 || r >= sizeof(dbtemp)) {
169fe75eb04Sdjm 		warnx("Directory name too long");
170fe75eb04Sdjm 		return (1);
171fe75eb04Sdjm 	}
172fe75eb04Sdjm 	r = snprintf(dbname, sizeof(dbname), "%skvm_%s.db",
173fe75eb04Sdjm 	    dbdir, nlistname);
1748ebf3ea0Sdjm 	if (r < 0 || r >= sizeof(dbtemp)) {
175fe75eb04Sdjm 		warnx("Directory name too long");
176fe75eb04Sdjm 		return (1);
177fe75eb04Sdjm 	}
178c59ab75fSmillert 
179c59ab75fSmillert 	/* If the existing db file matches the currently running kernel, exit */
18089cce642Smillert 	if (testdb(dbname)) {
181ebbf9c34Smillert 		if (verbose)
18289cce642Smillert 			warnx("%s already up to date", dbname);
18389cce642Smillert 		return(0);
184ebbf9c34Smillert 	} else if (verbose)
185c59ab75fSmillert 		warnx("rebuilding %s", dbname);
186c59ab75fSmillert 
187df930be7Sderaadt 	(void)umask(0);
188df930be7Sderaadt 	db = dbopen(dbtemp, O_CREAT | O_EXLOCK | O_TRUNC | O_RDWR,
1890a256418Stedu 	    S_IRUSR | S_IWUSR | S_IRGRP, DB_HASH, &openinfo);
19089cce642Smillert 	if (db == NULL) {
19189cce642Smillert 		warn("can't dbopen %s", dbtemp);
19289cce642Smillert 		return(1);
19389cce642Smillert 	}
1945c94ac0aSderaadt 
19536246103Smillert 	if (gid != -1 && fchown(db->fd(db), -1, gid) == -1) {
1965c94ac0aSderaadt 		warn("can't chown %s", dbtemp);
1975c94ac0aSderaadt 		(void)unlink(dbtemp);
1985c94ac0aSderaadt 		return(1);
1995c94ac0aSderaadt 	}
2005c94ac0aSderaadt 
201da2f7a99Smillert 	if (create_knlist(nlistpath, fd, db) != 0) {
20289cce642Smillert 		warn("cannot determine executable type of %s", nlistpath);
203ffb4dd05Sguenther 		(void)unlink(dbtemp);
20489cce642Smillert 		return(1);
205feed01ecSmillert 	}
206feed01ecSmillert 	if (db->close(db)) {
207feed01ecSmillert 		warn("can't dbclose %s", dbtemp);
208feed01ecSmillert 		(void)unlink(dbtemp);
20989cce642Smillert 		return(1);
210feed01ecSmillert 	}
2110a256418Stedu 
21289cce642Smillert 	if (rename(dbtemp, dbname)) {
21389cce642Smillert 		warn("rename %s to %s", dbtemp, dbname);
21489cce642Smillert 		(void)unlink(dbtemp);
21589cce642Smillert 		return(1);
21689cce642Smillert 	}
21789cce642Smillert 
21889cce642Smillert 	return(0);
219df930be7Sderaadt }
220df930be7Sderaadt 
22136246103Smillert __dead void
usage(void)22200da5b9dSderaadt usage(void)
223df930be7Sderaadt {
224fe75eb04Sdjm 	(void)fprintf(stderr, "usage: kvm_mkdb [-v] [-o directory] [file]\n");
225df930be7Sderaadt 	exit(1);
226df930be7Sderaadt }
227