1/* $NetBSD: mknod.c,v 1.39 2009/02/13 01:37:23 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.39 2009/02/13 01:37:23 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 63static int gid_name(const char *, gid_t *); 64static portdev_t callPack(pack_t *, int, u_long *); 65 66__dead static void usage(void); 67 68#ifdef KERN_DRIVERS 69static struct kinfo_drivers *kern_drivers; 70static int num_drivers; 71 72static void get_device_info(void); 73static void print_device_info(char **); 74static int major_from_name(const char *, mode_t); 75#endif 76 77#define MAXARGS 3 /* 3 for bsdos, 2 for rest */ 78 79int 80main(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 285static void 286usage(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 308static int 309gid_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 320static portdev_t 321callPack(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 333static void 334get_device_info(void) 335{ 336 static int mib[2] = {CTL_KERN, KERN_DRIVERS}; 337 size_t len; 338 339 if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0) 340 err(1, "kern.drivers" ); 341 kern_drivers = malloc(len); 342 if (kern_drivers == NULL) 343 err(1, "malloc"); 344 if (sysctl(mib, 2, kern_drivers, &len, NULL, 0) != 0) 345 err(1, "kern.drivers" ); 346 347 num_drivers = len / sizeof *kern_drivers; 348} 349 350static void 351print_device_info(char **names) 352{ 353 int i; 354 struct kinfo_drivers *kd; 355 356 if (kern_drivers == NULL) 357 get_device_info(); 358 359 do { 360 kd = kern_drivers; 361 for (i = 0; i < num_drivers; kd++, i++) { 362 if (*names && strcmp(*names, kd->d_name)) 363 continue; 364 printf("%s", kd->d_name); 365 if (kd->d_cmajor != -1) 366 printf(" character major %d", kd->d_cmajor); 367 if (kd->d_bmajor != -1) 368 printf(" block major %d", kd->d_bmajor); 369 printf("\n"); 370 } 371 } while (*names && *++names); 372} 373 374static int 375major_from_name(const char *name, mode_t mode) 376{ 377 int i; 378 struct kinfo_drivers *kd; 379 380 if (kern_drivers == NULL) 381 get_device_info(); 382 383 kd = kern_drivers; 384 for (i = 0; i < num_drivers; kd++, i++) { 385 if (strcmp(name, kd->d_name)) 386 continue; 387 if (S_ISCHR(mode)) 388 return kd->d_cmajor; 389 return kd->d_bmajor; 390 } 391 return -1; 392} 393#endif 394