1 /* $NetBSD: mknod.c,v 1.38 2008/07/20 01:20:22 lukem 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.38 2008/07/20 01:20:22 lukem 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 int main(int, char *[]); 67 static void usage(void); 68 69 #ifdef KERN_DRIVERS 70 static struct kinfo_drivers *kern_drivers; 71 static int num_drivers; 72 73 static void get_device_info(void); 74 static void print_device_info(char **); 75 static int major_from_name(const char *, mode_t); 76 #endif 77 78 #define MAXARGS 3 /* 3 for bsdos, 2 for rest */ 79 80 int 81 main(int argc, char **argv) 82 { 83 char *name, *p; 84 mode_t mode; 85 portdev_t dev; 86 pack_t *pack; 87 u_long numbers[MAXARGS]; 88 int n, ch, fifo, hasformat; 89 int r_flag = 0; /* force: delete existing entry */ 90 #ifdef KERN_DRIVERS 91 int l_flag = 0; /* list device names and numbers */ 92 int major; 93 #endif 94 void *modes = 0; 95 uid_t uid = -1; 96 gid_t gid = -1; 97 int rval; 98 99 dev = 0; 100 fifo = hasformat = 0; 101 pack = pack_native; 102 103 #ifdef KERN_DRIVERS 104 while ((ch = getopt(argc, argv, "lrRF:g:m:u:")) != -1) { 105 #else 106 while ((ch = getopt(argc, argv, "rRF:g:m:u:")) != -1) { 107 #endif 108 switch (ch) { 109 110 #ifdef KERN_DRIVERS 111 case 'l': 112 l_flag = 1; 113 break; 114 #endif 115 116 case 'r': 117 r_flag = 1; 118 break; 119 120 case 'R': 121 r_flag = 2; 122 break; 123 124 case 'F': 125 pack = pack_find(optarg); 126 if (pack == NULL) 127 errx(1, "invalid format: %s", optarg); 128 hasformat++; 129 break; 130 131 case 'g': 132 if (optarg[0] == '#') { 133 gid = strtol(optarg + 1, &p, 10); 134 if (*p == 0) 135 break; 136 } 137 if (gid_name(optarg, &gid) == 0) 138 break; 139 gid = strtol(optarg, &p, 10); 140 if (*p == 0) 141 break; 142 errx(1, "%s: invalid group name", optarg); 143 144 case 'm': 145 modes = setmode(optarg); 146 if (modes == NULL) 147 err(1, "Cannot set file mode `%s'", optarg); 148 break; 149 150 case 'u': 151 if (optarg[0] == '#') { 152 uid = strtol(optarg + 1, &p, 10); 153 if (*p == 0) 154 break; 155 } 156 if (uid_from_user(optarg, &uid) == 0) 157 break; 158 uid = strtol(optarg, &p, 10); 159 if (*p == 0) 160 break; 161 errx(1, "%s: invalid user name", optarg); 162 163 default: 164 case '?': 165 usage(); 166 } 167 } 168 argc -= optind; 169 argv += optind; 170 171 #ifdef KERN_DRIVERS 172 if (l_flag) { 173 print_device_info(argv); 174 return 0; 175 } 176 #endif 177 178 if (argc < 2 || argc > 10) 179 usage(); 180 181 name = *argv; 182 argc--; 183 argv++; 184 185 umask(mode = umask(0)); 186 mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) & ~mode; 187 188 if (argv[0][1] != '\0') 189 goto badtype; 190 switch (*argv[0]) { 191 case 'c': 192 mode |= S_IFCHR; 193 break; 194 195 case 'b': 196 mode |= S_IFBLK; 197 break; 198 199 case 'p': 200 if (hasformat) 201 errx(1, "format is meaningless for fifos"); 202 mode |= S_IFIFO; 203 fifo = 1; 204 break; 205 206 default: 207 badtype: 208 errx(1, "node type must be 'b', 'c' or 'p'."); 209 } 210 argc--; 211 argv++; 212 213 if (fifo) { 214 if (argc != 0) 215 usage(); 216 } else { 217 if (argc < 1 || argc > MAXARGS) 218 usage(); 219 } 220 221 for (n = 0; n < argc; n++) { 222 errno = 0; 223 numbers[n] = strtoul(argv[n], &p, 0); 224 if (*p == 0 && errno == 0) 225 continue; 226 #ifdef KERN_DRIVERS 227 if (n == 0) { 228 major = major_from_name(argv[0], mode); 229 if (major != -1) { 230 numbers[0] = major; 231 continue; 232 } 233 if (!isdigit(*(unsigned char *)argv[0])) 234 errx(1, "unknown driver: %s", argv[0]); 235 } 236 #endif 237 errx(1, "invalid number: %s", argv[n]); 238 } 239 240 switch (argc) { 241 case 0: 242 dev = 0; 243 break; 244 245 case 1: 246 dev = numbers[0]; 247 break; 248 249 default: 250 dev = callPack(pack, argc, numbers); 251 break; 252 } 253 254 if (modes != NULL) 255 mode = getmode(modes, mode); 256 umask(0); 257 rval = fifo ? mkfifo(name, mode) : mknod(name, mode, dev); 258 if (rval < 0 && errno == EEXIST && r_flag) { 259 struct stat sb; 260 if (lstat(name, &sb) != 0 || (!fifo && sb.st_rdev != dev)) 261 sb.st_mode = 0; 262 263 if ((sb.st_mode & S_IFMT) == (mode & S_IFMT)) { 264 if (r_flag == 1) 265 /* Ignore permissions and user/group */ 266 return 0; 267 if (sb.st_mode != mode) 268 rval = chmod(name, mode); 269 else 270 rval = 0; 271 } else { 272 unlink(name); 273 rval = fifo ? mkfifo(name, mode) 274 : mknod(name, mode, dev); 275 } 276 } 277 if (rval < 0) 278 err(1, "%s", name); 279 if ((uid != -1 || gid != -1) && chown(name, uid, gid) == -1) 280 /* XXX Should we unlink the files here? */ 281 warn("%s: uid/gid not changed", name); 282 283 return 0; 284 } 285 286 static void 287 usage(void) 288 { 289 const char *progname = getprogname(); 290 291 (void)fprintf(stderr, 292 "usage: %s [-rR] [-F format] [-m mode] [-u user] [-g group]\n", 293 progname); 294 (void)fprintf(stderr, 295 #ifdef KERN_DRIVERS 296 " [ name [b | c] [major | driver] minor\n" 297 #else 298 " [ name [b | c] major minor\n" 299 #endif 300 " | name [b | c] major unit subunit\n" 301 " | name [b | c] number\n" 302 " | name p ]\n"); 303 #ifdef KERN_DRIVERS 304 (void)fprintf(stderr, " %s -l [driver] ...\n", progname); 305 #endif 306 exit(1); 307 } 308 309 static int 310 gid_name(const char *name, gid_t *gid) 311 { 312 struct group *g; 313 314 g = getgrnam(name); 315 if (!g) 316 return -1; 317 *gid = g->gr_gid; 318 return 0; 319 } 320 321 static portdev_t 322 callPack(pack_t *f, int n, u_long *numbers) 323 { 324 portdev_t d; 325 const char *error = NULL; 326 327 d = (*f)(n, numbers, &error); 328 if (error != NULL) 329 errx(1, "%s", error); 330 return d; 331 } 332 333 #ifdef KERN_DRIVERS 334 static void 335 get_device_info(void) 336 { 337 static int mib[2] = {CTL_KERN, KERN_DRIVERS}; 338 size_t len; 339 340 if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0) 341 err(1, "kern.drivers" ); 342 kern_drivers = malloc(len); 343 if (kern_drivers == NULL) 344 err(1, "malloc"); 345 if (sysctl(mib, 2, kern_drivers, &len, NULL, 0) != 0) 346 err(1, "kern.drivers" ); 347 348 num_drivers = len / sizeof *kern_drivers; 349 } 350 351 static void 352 print_device_info(char **names) 353 { 354 int i; 355 struct kinfo_drivers *kd; 356 357 if (kern_drivers == NULL) 358 get_device_info(); 359 360 do { 361 kd = kern_drivers; 362 for (i = 0; i < num_drivers; kd++, i++) { 363 if (*names && strcmp(*names, kd->d_name)) 364 continue; 365 printf("%s", kd->d_name); 366 if (kd->d_cmajor != -1) 367 printf(" character major %d", kd->d_cmajor); 368 if (kd->d_bmajor != -1) 369 printf(" block major %d", kd->d_bmajor); 370 printf("\n"); 371 } 372 } while (*names && *++names); 373 } 374 375 static int 376 major_from_name(const char *name, mode_t mode) 377 { 378 int i; 379 struct kinfo_drivers *kd; 380 381 if (kern_drivers == NULL) 382 get_device_info(); 383 384 kd = kern_drivers; 385 for (i = 0; i < num_drivers; kd++, i++) { 386 if (strcmp(name, kd->d_name)) 387 continue; 388 if (S_ISCHR(mode)) 389 return kd->d_cmajor; 390 return kd->d_bmajor; 391 } 392 return -1; 393 } 394 #endif 395