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