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