xref: /minix3/usr.sbin/dev_mkdb/dev_mkdb.c (revision 180e74704d3b012a5a9186f196cd218b8ab783f4)
1*180e7470SDavid van Moolenbroek /*	$NetBSD: dev_mkdb.c,v 1.29 2012/06/03 21:42:47 joerg Exp $	*/
2*180e7470SDavid van Moolenbroek 
3*180e7470SDavid van Moolenbroek /*-
4*180e7470SDavid van Moolenbroek  * Copyright (c) 1990, 1993
5*180e7470SDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
6*180e7470SDavid van Moolenbroek  *
7*180e7470SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
8*180e7470SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
9*180e7470SDavid van Moolenbroek  * are met:
10*180e7470SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
11*180e7470SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
12*180e7470SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
13*180e7470SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
14*180e7470SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
15*180e7470SDavid van Moolenbroek  * 3. Neither the name of the University nor the names of its contributors
16*180e7470SDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
17*180e7470SDavid van Moolenbroek  *    without specific prior written permission.
18*180e7470SDavid van Moolenbroek  *
19*180e7470SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*180e7470SDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*180e7470SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*180e7470SDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*180e7470SDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*180e7470SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*180e7470SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*180e7470SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*180e7470SDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*180e7470SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*180e7470SDavid van Moolenbroek  * SUCH DAMAGE.
30*180e7470SDavid van Moolenbroek  */
31*180e7470SDavid van Moolenbroek 
32*180e7470SDavid van Moolenbroek #include <sys/cdefs.h>
33*180e7470SDavid van Moolenbroek __RCSID("$NetBSD: dev_mkdb.c,v 1.29 2012/06/03 21:42:47 joerg Exp $");
34*180e7470SDavid van Moolenbroek 
35*180e7470SDavid van Moolenbroek #include <sys/queue.h>
36*180e7470SDavid van Moolenbroek #include <sys/stat.h>
37*180e7470SDavid van Moolenbroek 
38*180e7470SDavid van Moolenbroek #include <cdbw.h>
39*180e7470SDavid van Moolenbroek #include <db.h>
40*180e7470SDavid van Moolenbroek #include <err.h>
41*180e7470SDavid van Moolenbroek #include <errno.h>
42*180e7470SDavid van Moolenbroek #include <fcntl.h>
43*180e7470SDavid van Moolenbroek #include <fts.h>
44*180e7470SDavid van Moolenbroek #include <paths.h>
45*180e7470SDavid van Moolenbroek #include <search.h>
46*180e7470SDavid van Moolenbroek #include <stdint.h>
47*180e7470SDavid van Moolenbroek #include <stdio.h>
48*180e7470SDavid van Moolenbroek #include <stdlib.h>
49*180e7470SDavid van Moolenbroek #include <string.h>
50*180e7470SDavid van Moolenbroek #include <unistd.h>
51*180e7470SDavid van Moolenbroek #include <util.h>
52*180e7470SDavid van Moolenbroek 
53*180e7470SDavid van Moolenbroek #define	HASH_SIZE	65536
54*180e7470SDavid van Moolenbroek #define	FILE_PERMISSION	S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
55*180e7470SDavid van Moolenbroek 
56*180e7470SDavid van Moolenbroek static struct cdbw *db;
57*180e7470SDavid van Moolenbroek static DB *db_compat;
58*180e7470SDavid van Moolenbroek static const char *db_name;
59*180e7470SDavid van Moolenbroek static char *db_name_tmp;
60*180e7470SDavid van Moolenbroek 
61*180e7470SDavid van Moolenbroek static void	usage(void) __dead;
62*180e7470SDavid van Moolenbroek 
63*180e7470SDavid van Moolenbroek static void
cdb_open(void)64*180e7470SDavid van Moolenbroek cdb_open(void)
65*180e7470SDavid van Moolenbroek {
66*180e7470SDavid van Moolenbroek 	db = cdbw_open();
67*180e7470SDavid van Moolenbroek 	if (db == NULL)
68*180e7470SDavid van Moolenbroek 		err(1, "opening cdb writer failed");
69*180e7470SDavid van Moolenbroek }
70*180e7470SDavid van Moolenbroek 
71*180e7470SDavid van Moolenbroek static void
cdb_close(void)72*180e7470SDavid van Moolenbroek cdb_close(void)
73*180e7470SDavid van Moolenbroek {
74*180e7470SDavid van Moolenbroek 	int fd;
75*180e7470SDavid van Moolenbroek 
76*180e7470SDavid van Moolenbroek 	fd = open(db_name_tmp, O_CREAT|O_EXCL|O_WRONLY, FILE_PERMISSION);
77*180e7470SDavid van Moolenbroek 	if (fd == -1)
78*180e7470SDavid van Moolenbroek 		err(1, "opening %s failed", db_name_tmp);
79*180e7470SDavid van Moolenbroek 	if (cdbw_output(db, fd, "NetBSD6 devdb", NULL))
80*180e7470SDavid van Moolenbroek 		err(1, "failed to write temporary database %s", db_name_tmp);
81*180e7470SDavid van Moolenbroek 	cdbw_close(db);
82*180e7470SDavid van Moolenbroek 	db = NULL;
83*180e7470SDavid van Moolenbroek 	if (close(fd))
84*180e7470SDavid van Moolenbroek 		err(1, "failed to write temporary database %s", db_name_tmp);
85*180e7470SDavid van Moolenbroek }
86*180e7470SDavid van Moolenbroek 
87*180e7470SDavid van Moolenbroek static void
cdb_add_entry(dev_t dev,mode_t type,const char * relpath)88*180e7470SDavid van Moolenbroek cdb_add_entry(dev_t dev, mode_t type, const char *relpath)
89*180e7470SDavid van Moolenbroek {
90*180e7470SDavid van Moolenbroek 	uint8_t *buf;
91*180e7470SDavid van Moolenbroek 	size_t len;
92*180e7470SDavid van Moolenbroek 
93*180e7470SDavid van Moolenbroek 	len = strlen(relpath) + 1;
94*180e7470SDavid van Moolenbroek 	buf = malloc(len + 10);
95*180e7470SDavid van Moolenbroek 	le64enc(buf, dev);
96*180e7470SDavid van Moolenbroek 	le16enc(buf + 8, type);
97*180e7470SDavid van Moolenbroek 	memcpy(buf + 10, relpath, len);
98*180e7470SDavid van Moolenbroek 	cdbw_put(db, buf, 10, buf, len + 10);
99*180e7470SDavid van Moolenbroek 	free(buf);
100*180e7470SDavid van Moolenbroek }
101*180e7470SDavid van Moolenbroek 
102*180e7470SDavid van Moolenbroek static void
compat_open(void)103*180e7470SDavid van Moolenbroek compat_open(void)
104*180e7470SDavid van Moolenbroek {
105*180e7470SDavid van Moolenbroek 	static HASHINFO openinfo = {
106*180e7470SDavid van Moolenbroek 		4096,		/* bsize */
107*180e7470SDavid van Moolenbroek 		128,		/* ffactor */
108*180e7470SDavid van Moolenbroek 		1024,		/* nelem */
109*180e7470SDavid van Moolenbroek 		2048 * 1024,	/* cachesize */
110*180e7470SDavid van Moolenbroek 		NULL,		/* hash() */
111*180e7470SDavid van Moolenbroek 		0		/* lorder */
112*180e7470SDavid van Moolenbroek 	};
113*180e7470SDavid van Moolenbroek 
114*180e7470SDavid van Moolenbroek 	db_compat = dbopen(db_name_tmp, O_CREAT|O_EXCL|O_EXLOCK|O_RDWR|O_TRUNC,
115*180e7470SDavid van Moolenbroek 	    FILE_PERMISSION, DB_HASH, &openinfo);
116*180e7470SDavid van Moolenbroek 
117*180e7470SDavid van Moolenbroek 	if (db_compat == NULL)
118*180e7470SDavid van Moolenbroek 		err(1, "failed to create temporary database %s",
119*180e7470SDavid van Moolenbroek 		    db_name_tmp);
120*180e7470SDavid van Moolenbroek }
121*180e7470SDavid van Moolenbroek 
122*180e7470SDavid van Moolenbroek static void
compat_close(void)123*180e7470SDavid van Moolenbroek compat_close(void)
124*180e7470SDavid van Moolenbroek {
125*180e7470SDavid van Moolenbroek 	if ((*db_compat->close)(db_compat))
126*180e7470SDavid van Moolenbroek 		err(1, "failed to write temporary database %s", db_name_tmp);
127*180e7470SDavid van Moolenbroek }
128*180e7470SDavid van Moolenbroek 
129*180e7470SDavid van Moolenbroek static void
compat_add_entry(dev_t dev,mode_t type,const char * relpath)130*180e7470SDavid van Moolenbroek compat_add_entry(dev_t dev, mode_t type, const char *relpath)
131*180e7470SDavid van Moolenbroek {
132*180e7470SDavid van Moolenbroek 	/*
133*180e7470SDavid van Moolenbroek 	 * Keys are a mode_t followed by a dev_t.  The former is the type of
134*180e7470SDavid van Moolenbroek 	 * the file (mode & S_IFMT), the latter is the st_rdev field.  Note
135*180e7470SDavid van Moolenbroek 	 * that the structure may contain padding, so we have to clear it
136*180e7470SDavid van Moolenbroek 	 * out here.
137*180e7470SDavid van Moolenbroek 	 */
138*180e7470SDavid van Moolenbroek 	struct {
139*180e7470SDavid van Moolenbroek 		mode_t type;
140*180e7470SDavid van Moolenbroek 		dev_t dev;
141*180e7470SDavid van Moolenbroek 	} bkey;
142*180e7470SDavid van Moolenbroek 	struct {
143*180e7470SDavid van Moolenbroek 		mode_t type;
144*180e7470SDavid van Moolenbroek 		int32_t dev;
145*180e7470SDavid van Moolenbroek 	} obkey;
146*180e7470SDavid van Moolenbroek 	DBT data, key;
147*180e7470SDavid van Moolenbroek 
148*180e7470SDavid van Moolenbroek 	(void)memset(&bkey, 0, sizeof(bkey));
149*180e7470SDavid van Moolenbroek 	key.data = &bkey;
150*180e7470SDavid van Moolenbroek 	key.size = sizeof(bkey);
151*180e7470SDavid van Moolenbroek 	data.data = __UNCONST(relpath);
152*180e7470SDavid van Moolenbroek 	data.size = strlen(relpath) + 1;
153*180e7470SDavid van Moolenbroek 	bkey.type = type;
154*180e7470SDavid van Moolenbroek 	bkey.dev = dev;
155*180e7470SDavid van Moolenbroek 	if ((*db_compat->put)(db_compat, &key, &data, 0))
156*180e7470SDavid van Moolenbroek 		err(1, "failed to write temporary database %s", db_name_tmp);
157*180e7470SDavid van Moolenbroek 
158*180e7470SDavid van Moolenbroek 	/*
159*180e7470SDavid van Moolenbroek 	 * If the device fits into the old 32bit format, add compat entry
160*180e7470SDavid van Moolenbroek 	 * for pre-NetBSD6 libc.
161*180e7470SDavid van Moolenbroek 	 */
162*180e7470SDavid van Moolenbroek 
163*180e7470SDavid van Moolenbroek 	if ((dev_t)(int32_t)dev != dev)
164*180e7470SDavid van Moolenbroek 		return;
165*180e7470SDavid van Moolenbroek 
166*180e7470SDavid van Moolenbroek 	(void)memset(&obkey, 0, sizeof(obkey));
167*180e7470SDavid van Moolenbroek 	key.data = &obkey;
168*180e7470SDavid van Moolenbroek 	key.size = sizeof(obkey);
169*180e7470SDavid van Moolenbroek 	data.data = __UNCONST(relpath);
170*180e7470SDavid van Moolenbroek 	data.size = strlen(relpath) + 1;
171*180e7470SDavid van Moolenbroek 	obkey.type = type;
172*180e7470SDavid van Moolenbroek 	obkey.dev = (int32_t)dev;
173*180e7470SDavid van Moolenbroek 	if ((*db_compat->put)(db_compat, &key, &data, 0))
174*180e7470SDavid van Moolenbroek 		err(1, "failed to write temporary database %s", db_name_tmp);
175*180e7470SDavid van Moolenbroek }
176*180e7470SDavid van Moolenbroek 
177*180e7470SDavid van Moolenbroek int
main(int argc,char ** argv)178*180e7470SDavid van Moolenbroek main(int argc, char **argv)
179*180e7470SDavid van Moolenbroek {
180*180e7470SDavid van Moolenbroek 	struct stat *st;
181*180e7470SDavid van Moolenbroek 	FTS *ftsp;
182*180e7470SDavid van Moolenbroek 	FTSENT *p;
183*180e7470SDavid van Moolenbroek 	int ch;
184*180e7470SDavid van Moolenbroek 	char *pathv[2];
185*180e7470SDavid van Moolenbroek 	size_t dlen;
186*180e7470SDavid van Moolenbroek 	int compat_mode;
187*180e7470SDavid van Moolenbroek 
188*180e7470SDavid van Moolenbroek 	setprogname(argv[0]);
189*180e7470SDavid van Moolenbroek 	compat_mode = 0;
190*180e7470SDavid van Moolenbroek 
191*180e7470SDavid van Moolenbroek 	while ((ch = getopt(argc, argv, "co:")) != -1)
192*180e7470SDavid van Moolenbroek 		switch (ch) {
193*180e7470SDavid van Moolenbroek 		case 'c':
194*180e7470SDavid van Moolenbroek 			compat_mode = 1;
195*180e7470SDavid van Moolenbroek 			break;
196*180e7470SDavid van Moolenbroek 		case 'o':
197*180e7470SDavid van Moolenbroek 			db_name = optarg;
198*180e7470SDavid van Moolenbroek 			break;
199*180e7470SDavid van Moolenbroek 		default:
200*180e7470SDavid van Moolenbroek 			usage();
201*180e7470SDavid van Moolenbroek 		}
202*180e7470SDavid van Moolenbroek 	argc -= optind;
203*180e7470SDavid van Moolenbroek 	argv += optind;
204*180e7470SDavid van Moolenbroek 
205*180e7470SDavid van Moolenbroek 	if (argc > 1)
206*180e7470SDavid van Moolenbroek 		usage();
207*180e7470SDavid van Moolenbroek 
208*180e7470SDavid van Moolenbroek 	pathv[1] = NULL;
209*180e7470SDavid van Moolenbroek 	if (argc == 1)
210*180e7470SDavid van Moolenbroek 		pathv[0] = argv[0];
211*180e7470SDavid van Moolenbroek 	else
212*180e7470SDavid van Moolenbroek 		pathv[0] = __UNCONST(_PATH_DEV);
213*180e7470SDavid van Moolenbroek 
214*180e7470SDavid van Moolenbroek 	ftsp = fts_open(pathv, FTS_NOCHDIR | FTS_PHYSICAL, NULL);
215*180e7470SDavid van Moolenbroek 	if (ftsp == NULL)
216*180e7470SDavid van Moolenbroek 		err(1, "fts_open: %s", pathv[0]);
217*180e7470SDavid van Moolenbroek 
218*180e7470SDavid van Moolenbroek 	if (db_name == NULL) {
219*180e7470SDavid van Moolenbroek 		if (compat_mode)
220*180e7470SDavid van Moolenbroek 			db_name = _PATH_DEVDB;
221*180e7470SDavid van Moolenbroek 		else
222*180e7470SDavid van Moolenbroek 			db_name = _PATH_DEVCDB;
223*180e7470SDavid van Moolenbroek 	}
224*180e7470SDavid van Moolenbroek 	easprintf(&db_name_tmp, "%s.XXXXXXX", db_name);
225*180e7470SDavid van Moolenbroek 	mktemp(db_name_tmp);
226*180e7470SDavid van Moolenbroek 
227*180e7470SDavid van Moolenbroek 	if (compat_mode)
228*180e7470SDavid van Moolenbroek 		compat_open();
229*180e7470SDavid van Moolenbroek 	else
230*180e7470SDavid van Moolenbroek 		cdb_open();
231*180e7470SDavid van Moolenbroek 
232*180e7470SDavid van Moolenbroek 	while ((p = fts_read(ftsp)) != NULL) {
233*180e7470SDavid van Moolenbroek 		if (p->fts_info != FTS_DEFAULT)
234*180e7470SDavid van Moolenbroek 			continue;
235*180e7470SDavid van Moolenbroek 
236*180e7470SDavid van Moolenbroek 		st = p->fts_statp;
237*180e7470SDavid van Moolenbroek 		if (!S_ISCHR(st->st_mode) && !S_ISBLK(st->st_mode))
238*180e7470SDavid van Moolenbroek 			continue;
239*180e7470SDavid van Moolenbroek 		dlen = strlen(pathv[0]);
240*180e7470SDavid van Moolenbroek 		while (pathv[0][dlen] == '/')
241*180e7470SDavid van Moolenbroek 			++dlen;
242*180e7470SDavid van Moolenbroek 		if (compat_mode)
243*180e7470SDavid van Moolenbroek 			compat_add_entry(st->st_rdev, st->st_mode & S_IFMT,
244*180e7470SDavid van Moolenbroek 			    p->fts_path + dlen);
245*180e7470SDavid van Moolenbroek 		else
246*180e7470SDavid van Moolenbroek 			cdb_add_entry(st->st_rdev, st->st_mode & S_IFMT,
247*180e7470SDavid van Moolenbroek 			    p->fts_path + dlen);
248*180e7470SDavid van Moolenbroek 	}
249*180e7470SDavid van Moolenbroek 	(void)fts_close(ftsp);
250*180e7470SDavid van Moolenbroek 
251*180e7470SDavid van Moolenbroek 	if (compat_mode)
252*180e7470SDavid van Moolenbroek 		compat_close();
253*180e7470SDavid van Moolenbroek 	else
254*180e7470SDavid van Moolenbroek 		cdb_close();
255*180e7470SDavid van Moolenbroek 
256*180e7470SDavid van Moolenbroek 	if (rename(db_name_tmp, db_name) == -1)
257*180e7470SDavid van Moolenbroek 		err(1, "rename %s to %s", db_name_tmp, db_name);
258*180e7470SDavid van Moolenbroek 	return 0;
259*180e7470SDavid van Moolenbroek }
260*180e7470SDavid van Moolenbroek 
261*180e7470SDavid van Moolenbroek static void
usage(void)262*180e7470SDavid van Moolenbroek usage(void)
263*180e7470SDavid van Moolenbroek {
264*180e7470SDavid van Moolenbroek 
265*180e7470SDavid van Moolenbroek 	(void)fprintf(stderr, "Usage: %s [-c] [-o database] [directory]\n",
266*180e7470SDavid van Moolenbroek 	    getprogname());
267*180e7470SDavid van Moolenbroek 	exit(1);
268*180e7470SDavid van Moolenbroek }
269