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