1/* $NetBSD$ */ 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$"); 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 56static struct cdbw *db; 57static DB *db_compat; 58static const char *db_name; 59static char *db_name_tmp; 60 61static void usage(void) __dead; 62 63static void 64cdb_open(void) 65{ 66 db = cdbw_open(); 67 if (db == NULL) 68 err(1, "opening cdb writer failed"); 69} 70 71static void 72cdb_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 87static void 88cdb_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 102static void 103compat_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 122static void 123compat_close(void) 124{ 125 if ((*db_compat->close)(db_compat)) 126 err(1, "failed to write temporary database %s", db_name_tmp); 127} 128 129static void 130compat_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 177int 178main(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 261static void 262usage(void) 263{ 264 265 (void)fprintf(stderr, "Usage: %s [-c] [-o database] [directory]\n", 266 getprogname()); 267 exit(1); 268} 269