1 1.42 mlelstv /* $NetBSD: mknod.c,v 1.42 2014/08/22 22:28:50 mlelstv Exp $ */ 2 1.7 cgd 3 1.13 mycroft /*- 4 1.22 lukem * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. 5 1.13 mycroft * All rights reserved. 6 1.13 mycroft * 7 1.13 mycroft * This code is derived from software contributed to The NetBSD Foundation 8 1.13 mycroft * by Charles M. Hannum. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.1 cgd * 19 1.13 mycroft * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.13 mycroft * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.13 mycroft * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.13 mycroft * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.13 mycroft * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.13 mycroft * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.13 mycroft * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.13 mycroft * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.13 mycroft * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.13 mycroft * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.13 mycroft * POSSIBILITY OF SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.28 lukem #if HAVE_NBTOOL_CONFIG_H 33 1.28 lukem #include "nbtool_config.h" 34 1.28 lukem #endif 35 1.28 lukem 36 1.9 lukem #include <sys/cdefs.h> 37 1.1 cgd #ifndef lint 38 1.38 lukem __COPYRIGHT("@(#) Copyright (c) 1998\ 39 1.38 lukem The NetBSD Foundation, Inc. All rights reserved."); 40 1.42 mlelstv __RCSID("$NetBSD: mknod.c,v 1.42 2014/08/22 22:28:50 mlelstv Exp $"); 41 1.1 cgd #endif /* not lint */ 42 1.1 cgd 43 1.1 cgd #include <sys/types.h> 44 1.1 cgd #include <sys/stat.h> 45 1.26 dsl #include <sys/param.h> 46 1.34 jmc #if !HAVE_NBTOOL_CONFIG_H 47 1.32 dsl #include <sys/sysctl.h> 48 1.33 christos #endif 49 1.11 mycroft 50 1.11 mycroft #include <err.h> 51 1.11 mycroft #include <errno.h> 52 1.11 mycroft #include <limits.h> 53 1.1 cgd #include <stdio.h> 54 1.6 cgd #include <stdlib.h> 55 1.6 cgd #include <unistd.h> 56 1.26 dsl #include <pwd.h> 57 1.26 dsl #include <grp.h> 58 1.19 matt #include <string.h> 59 1.26 dsl #include <ctype.h> 60 1.8 jtc 61 1.24 lukem #include "pack_dev.h" 62 1.11 mycroft 63 1.26 dsl static int gid_name(const char *, gid_t *); 64 1.41 tsutsui static dev_t callPack(pack_t *, int, u_long *); 65 1.26 dsl 66 1.40 joerg __dead static void usage(void); 67 1.11 mycroft 68 1.32 dsl #ifdef KERN_DRIVERS 69 1.32 dsl static struct kinfo_drivers *kern_drivers; 70 1.32 dsl static int num_drivers; 71 1.32 dsl 72 1.32 dsl static void get_device_info(void); 73 1.32 dsl static void print_device_info(char **); 74 1.32 dsl static int major_from_name(const char *, mode_t); 75 1.32 dsl #endif 76 1.32 dsl 77 1.23 lukem #define MAXARGS 3 /* 3 for bsdos, 2 for rest */ 78 1.11 mycroft 79 1.22 lukem int 80 1.22 lukem main(int argc, char **argv) 81 1.14 mycroft { 82 1.22 lukem char *name, *p; 83 1.22 lukem mode_t mode; 84 1.41 tsutsui dev_t dev; 85 1.11 mycroft pack_t *pack; 86 1.22 lukem u_long numbers[MAXARGS]; 87 1.22 lukem int n, ch, fifo, hasformat; 88 1.26 dsl int r_flag = 0; /* force: delete existing entry */ 89 1.32 dsl #ifdef KERN_DRIVERS 90 1.32 dsl int l_flag = 0; /* list device names and numbers */ 91 1.32 dsl int major; 92 1.32 dsl #endif 93 1.26 dsl void *modes = 0; 94 1.26 dsl uid_t uid = -1; 95 1.26 dsl gid_t gid = -1; 96 1.26 dsl int rval; 97 1.1 cgd 98 1.22 lukem dev = 0; 99 1.22 lukem fifo = hasformat = 0; 100 1.11 mycroft pack = pack_native; 101 1.11 mycroft 102 1.32 dsl #ifdef KERN_DRIVERS 103 1.32 dsl while ((ch = getopt(argc, argv, "lrRF:g:m:u:")) != -1) { 104 1.32 dsl #else 105 1.26 dsl while ((ch = getopt(argc, argv, "rRF:g:m:u:")) != -1) { 106 1.32 dsl #endif 107 1.11 mycroft switch (ch) { 108 1.26 dsl 109 1.32 dsl #ifdef KERN_DRIVERS 110 1.32 dsl case 'l': 111 1.32 dsl l_flag = 1; 112 1.32 dsl break; 113 1.32 dsl #endif 114 1.32 dsl 115 1.26 dsl case 'r': 116 1.26 dsl r_flag = 1; 117 1.26 dsl break; 118 1.26 dsl 119 1.26 dsl case 'R': 120 1.26 dsl r_flag = 2; 121 1.26 dsl break; 122 1.26 dsl 123 1.11 mycroft case 'F': 124 1.24 lukem pack = pack_find(optarg); 125 1.22 lukem if (pack == NULL) 126 1.11 mycroft errx(1, "invalid format: %s", optarg); 127 1.22 lukem hasformat++; 128 1.11 mycroft break; 129 1.11 mycroft 130 1.26 dsl case 'g': 131 1.26 dsl if (optarg[0] == '#') { 132 1.26 dsl gid = strtol(optarg + 1, &p, 10); 133 1.26 dsl if (*p == 0) 134 1.26 dsl break; 135 1.26 dsl } 136 1.26 dsl if (gid_name(optarg, &gid) == 0) 137 1.26 dsl break; 138 1.26 dsl gid = strtol(optarg, &p, 10); 139 1.26 dsl if (*p == 0) 140 1.26 dsl break; 141 1.26 dsl errx(1, "%s: invalid group name", optarg); 142 1.26 dsl 143 1.26 dsl case 'm': 144 1.26 dsl modes = setmode(optarg); 145 1.26 dsl if (modes == NULL) 146 1.35 christos err(1, "Cannot set file mode `%s'", optarg); 147 1.26 dsl break; 148 1.26 dsl 149 1.26 dsl case 'u': 150 1.26 dsl if (optarg[0] == '#') { 151 1.26 dsl uid = strtol(optarg + 1, &p, 10); 152 1.26 dsl if (*p == 0) 153 1.26 dsl break; 154 1.26 dsl } 155 1.26 dsl if (uid_from_user(optarg, &uid) == 0) 156 1.26 dsl break; 157 1.26 dsl uid = strtol(optarg, &p, 10); 158 1.26 dsl if (*p == 0) 159 1.26 dsl break; 160 1.26 dsl errx(1, "%s: invalid user name", optarg); 161 1.26 dsl 162 1.11 mycroft default: 163 1.11 mycroft case '?': 164 1.11 mycroft usage(); 165 1.11 mycroft } 166 1.11 mycroft } 167 1.11 mycroft argc -= optind; 168 1.11 mycroft argv += optind; 169 1.11 mycroft 170 1.32 dsl #ifdef KERN_DRIVERS 171 1.32 dsl if (l_flag) { 172 1.32 dsl print_device_info(argv); 173 1.32 dsl return 0; 174 1.32 dsl } 175 1.32 dsl #endif 176 1.32 dsl 177 1.18 christos if (argc < 2 || argc > 10) 178 1.8 jtc usage(); 179 1.1 cgd 180 1.14 mycroft name = *argv; 181 1.14 mycroft argc--; 182 1.14 mycroft argv++; 183 1.14 mycroft 184 1.26 dsl umask(mode = umask(0)); 185 1.26 dsl mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) & ~mode; 186 1.26 dsl 187 1.22 lukem if (argv[0][1] != '\0') 188 1.22 lukem goto badtype; 189 1.18 christos switch (*argv[0]) { 190 1.18 christos case 'c': 191 1.1 cgd mode |= S_IFCHR; 192 1.18 christos break; 193 1.18 christos 194 1.18 christos case 'b': 195 1.1 cgd mode |= S_IFBLK; 196 1.18 christos break; 197 1.18 christos 198 1.18 christos case 'p': 199 1.22 lukem if (hasformat) 200 1.18 christos errx(1, "format is meaningless for fifos"); 201 1.26 dsl mode |= S_IFIFO; 202 1.18 christos fifo = 1; 203 1.18 christos break; 204 1.18 christos 205 1.18 christos default: 206 1.22 lukem badtype: 207 1.18 christos errx(1, "node type must be 'b', 'c' or 'p'."); 208 1.18 christos } 209 1.14 mycroft argc--; 210 1.14 mycroft argv++; 211 1.14 mycroft 212 1.22 lukem if (fifo) { 213 1.22 lukem if (argc != 0) 214 1.22 lukem usage(); 215 1.22 lukem } else { 216 1.23 lukem if (argc < 1 || argc > MAXARGS) 217 1.22 lukem usage(); 218 1.22 lukem } 219 1.18 christos 220 1.14 mycroft for (n = 0; n < argc; n++) { 221 1.25 lukem errno = 0; 222 1.14 mycroft numbers[n] = strtoul(argv[n], &p, 0); 223 1.26 dsl if (*p == 0 && errno == 0) 224 1.26 dsl continue; 225 1.32 dsl #ifdef KERN_DRIVERS 226 1.42 mlelstv if (argc == 2 && n == 0) { 227 1.32 dsl major = major_from_name(argv[0], mode); 228 1.32 dsl if (major != -1) { 229 1.32 dsl numbers[0] = major; 230 1.32 dsl continue; 231 1.32 dsl } 232 1.32 dsl if (!isdigit(*(unsigned char *)argv[0])) 233 1.32 dsl errx(1, "unknown driver: %s", argv[0]); 234 1.32 dsl } 235 1.32 dsl #endif 236 1.26 dsl errx(1, "invalid number: %s", argv[n]); 237 1.14 mycroft } 238 1.11 mycroft 239 1.18 christos switch (argc) { 240 1.18 christos case 0: 241 1.18 christos dev = 0; 242 1.18 christos break; 243 1.18 christos 244 1.18 christos case 1: 245 1.14 mycroft dev = numbers[0]; 246 1.18 christos break; 247 1.18 christos 248 1.18 christos default: 249 1.30 ross dev = callPack(pack, argc, numbers); 250 1.18 christos break; 251 1.18 christos } 252 1.1 cgd 253 1.26 dsl if (modes != NULL) 254 1.26 dsl mode = getmode(modes, mode); 255 1.26 dsl umask(0); 256 1.26 dsl rval = fifo ? mkfifo(name, mode) : mknod(name, mode, dev); 257 1.26 dsl if (rval < 0 && errno == EEXIST && r_flag) { 258 1.26 dsl struct stat sb; 259 1.26 dsl if (lstat(name, &sb) != 0 || (!fifo && sb.st_rdev != dev)) 260 1.26 dsl sb.st_mode = 0; 261 1.26 dsl 262 1.26 dsl if ((sb.st_mode & S_IFMT) == (mode & S_IFMT)) { 263 1.26 dsl if (r_flag == 1) 264 1.26 dsl /* Ignore permissions and user/group */ 265 1.26 dsl return 0; 266 1.26 dsl if (sb.st_mode != mode) 267 1.26 dsl rval = chmod(name, mode); 268 1.26 dsl else 269 1.26 dsl rval = 0; 270 1.26 dsl } else { 271 1.26 dsl unlink(name); 272 1.26 dsl rval = fifo ? mkfifo(name, mode) 273 1.26 dsl : mknod(name, mode, dev); 274 1.26 dsl } 275 1.26 dsl } 276 1.26 dsl if (rval < 0) 277 1.17 tron err(1, "%s", name); 278 1.39 lukem if ((uid != (uid_t)-1 || gid != (uid_t)-1) && chown(name, uid, gid) == -1) 279 1.26 dsl /* XXX Should we unlink the files here? */ 280 1.26 dsl warn("%s: uid/gid not changed", name); 281 1.8 jtc 282 1.26 dsl return 0; 283 1.8 jtc } 284 1.8 jtc 285 1.18 christos static void 286 1.22 lukem usage(void) 287 1.8 jtc { 288 1.21 cgd const char *progname = getprogname(); 289 1.21 cgd 290 1.18 christos (void)fprintf(stderr, 291 1.29 jmmv "usage: %s [-rR] [-F format] [-m mode] [-u user] [-g group]\n", 292 1.26 dsl progname); 293 1.18 christos (void)fprintf(stderr, 294 1.32 dsl #ifdef KERN_DRIVERS 295 1.32 dsl " [ name [b | c] [major | driver] minor\n" 296 1.32 dsl #else 297 1.26 dsl " [ name [b | c] major minor\n" 298 1.32 dsl #endif 299 1.26 dsl " | name [b | c] major unit subunit\n" 300 1.26 dsl " | name [b | c] number\n" 301 1.26 dsl " | name p ]\n"); 302 1.32 dsl #ifdef KERN_DRIVERS 303 1.32 dsl (void)fprintf(stderr, " %s -l [driver] ...\n", progname); 304 1.32 dsl #endif 305 1.8 jtc exit(1); 306 1.26 dsl } 307 1.26 dsl 308 1.26 dsl static int 309 1.26 dsl gid_name(const char *name, gid_t *gid) 310 1.26 dsl { 311 1.26 dsl struct group *g; 312 1.26 dsl 313 1.26 dsl g = getgrnam(name); 314 1.26 dsl if (!g) 315 1.26 dsl return -1; 316 1.26 dsl *gid = g->gr_gid; 317 1.26 dsl return 0; 318 1.1 cgd } 319 1.30 ross 320 1.41 tsutsui static dev_t 321 1.30 ross callPack(pack_t *f, int n, u_long *numbers) 322 1.30 ross { 323 1.41 tsutsui dev_t d; 324 1.31 christos const char *error = NULL; 325 1.30 ross 326 1.30 ross d = (*f)(n, numbers, &error); 327 1.30 ross if (error != NULL) 328 1.30 ross errx(1, "%s", error); 329 1.30 ross return d; 330 1.30 ross } 331 1.32 dsl 332 1.32 dsl #ifdef KERN_DRIVERS 333 1.32 dsl static void 334 1.32 dsl get_device_info(void) 335 1.32 dsl { 336 1.32 dsl static int mib[2] = {CTL_KERN, KERN_DRIVERS}; 337 1.32 dsl size_t len; 338 1.32 dsl 339 1.32 dsl if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0) 340 1.32 dsl err(1, "kern.drivers" ); 341 1.32 dsl kern_drivers = malloc(len); 342 1.32 dsl if (kern_drivers == NULL) 343 1.32 dsl err(1, "malloc"); 344 1.32 dsl if (sysctl(mib, 2, kern_drivers, &len, NULL, 0) != 0) 345 1.32 dsl err(1, "kern.drivers" ); 346 1.32 dsl 347 1.32 dsl num_drivers = len / sizeof *kern_drivers; 348 1.32 dsl } 349 1.32 dsl 350 1.32 dsl static void 351 1.32 dsl print_device_info(char **names) 352 1.32 dsl { 353 1.32 dsl int i; 354 1.32 dsl struct kinfo_drivers *kd; 355 1.32 dsl 356 1.32 dsl if (kern_drivers == NULL) 357 1.32 dsl get_device_info(); 358 1.32 dsl 359 1.32 dsl do { 360 1.32 dsl kd = kern_drivers; 361 1.32 dsl for (i = 0; i < num_drivers; kd++, i++) { 362 1.32 dsl if (*names && strcmp(*names, kd->d_name)) 363 1.32 dsl continue; 364 1.32 dsl printf("%s", kd->d_name); 365 1.32 dsl if (kd->d_cmajor != -1) 366 1.32 dsl printf(" character major %d", kd->d_cmajor); 367 1.32 dsl if (kd->d_bmajor != -1) 368 1.32 dsl printf(" block major %d", kd->d_bmajor); 369 1.32 dsl printf("\n"); 370 1.32 dsl } 371 1.32 dsl } while (*names && *++names); 372 1.32 dsl } 373 1.32 dsl 374 1.32 dsl static int 375 1.32 dsl major_from_name(const char *name, mode_t mode) 376 1.32 dsl { 377 1.32 dsl int i; 378 1.32 dsl struct kinfo_drivers *kd; 379 1.32 dsl 380 1.32 dsl if (kern_drivers == NULL) 381 1.32 dsl get_device_info(); 382 1.32 dsl 383 1.32 dsl kd = kern_drivers; 384 1.32 dsl for (i = 0; i < num_drivers; kd++, i++) { 385 1.32 dsl if (strcmp(name, kd->d_name)) 386 1.32 dsl continue; 387 1.36 dsl if (S_ISCHR(mode)) 388 1.32 dsl return kd->d_cmajor; 389 1.32 dsl return kd->d_bmajor; 390 1.32 dsl } 391 1.32 dsl return -1; 392 1.32 dsl } 393 1.32 dsl #endif 394