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