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