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