1 /* $OpenBSD: mknod.c,v 1.29 2016/03/07 19:16:06 tb Exp $ */ 2 /* $NetBSD: mknod.c,v 1.8 1995/08/11 00:08:18 jtc Exp $ */ 3 4 /* 5 * Copyright (c) 1997-2016 Theo de Raadt <deraadt@openbsd.org>, 6 * Marc Espie <espie@openbsd.org>, Todd Miller <millert@openbsd.org>, 7 * Martin Natano <natano@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/types.h> 23 #include <sys/stat.h> 24 25 #include <err.h> 26 #include <errno.h> 27 #include <limits.h> 28 #include <locale.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 34 extern char *__progname; 35 36 struct node { 37 const char *name; 38 mode_t mode; 39 dev_t dev; 40 char mflag; 41 }; 42 43 static int domakenodes(struct node *, int); 44 static dev_t compute_device(int, char **); 45 __dead static void usage(int); 46 47 int 48 main(int argc, char *argv[]) 49 { 50 struct node *node; 51 int ismkfifo; 52 int n = 0; 53 int mode = DEFFILEMODE; 54 int mflag = 0; 55 void *set; 56 int ch; 57 58 setlocale(LC_ALL, ""); 59 60 if (pledge("stdio dpath", NULL) == -1) 61 err(1, "pledge"); 62 63 node = reallocarray(NULL, sizeof(struct node), argc); 64 if (!node) 65 err(1, NULL); 66 67 ismkfifo = strcmp(__progname, "mkfifo") == 0; 68 69 /* we parse all arguments upfront */ 70 while (argc > 1) { 71 while ((ch = getopt(argc, argv, "m:")) != -1) { 72 switch (ch) { 73 case 'm': 74 if (!(set = setmode(optarg))) 75 errx(1, "invalid file mode '%s'", 76 optarg); 77 /* 78 * In symbolic mode strings, the + and - 79 * operators are interpreted relative to 80 * an assumed initial mode of a=rw. 81 */ 82 mode = getmode(set, DEFFILEMODE); 83 if ((mode & ACCESSPERMS) != mode) 84 errx(1, "forbidden mode: %o", mode); 85 mflag = 1; 86 free(set); 87 break; 88 default: 89 usage(ismkfifo); 90 } 91 } 92 argc -= optind; 93 argv += optind; 94 95 if (ismkfifo) { 96 while (*argv) { 97 node[n].mode = mode | S_IFIFO; 98 node[n].mflag = mflag; 99 node[n].name = *argv; 100 node[n].dev = 0; 101 n++; 102 argv++; 103 } 104 /* XXX no multiple getopt */ 105 break; 106 } else { 107 if (argc < 2) 108 usage(ismkfifo); 109 node[n].mode = mode; 110 node[n].mflag = mflag; 111 node[n].name = argv[0]; 112 if (strlen(argv[1]) != 1) 113 errx(1, "invalid device type '%s'", argv[1]); 114 115 /* XXX computation offset by one for next getopt */ 116 switch(argv[1][0]) { 117 case 'p': 118 node[n].mode |= S_IFIFO; 119 node[n].dev = 0; 120 argv++; 121 argc--; 122 break; 123 case 'b': 124 node[n].mode |= S_IFBLK; 125 goto common; 126 case 'c': 127 node[n].mode |= S_IFCHR; 128 common: 129 node[n].dev = compute_device(argc, argv); 130 argv+=3; 131 argc-=3; 132 break; 133 default: 134 errx(1, "invalid device type '%s'", argv[1]); 135 } 136 n++; 137 } 138 optind = 1; 139 optreset = 1; 140 } 141 142 if (n == 0) 143 usage(ismkfifo); 144 145 return (domakenodes(node, n)); 146 } 147 148 static dev_t 149 compute_device(int argc, char **argv) 150 { 151 dev_t dev; 152 char *endp; 153 unsigned long major, minor; 154 155 if (argc < 4) 156 usage(0); 157 158 errno = 0; 159 major = strtoul(argv[2], &endp, 0); 160 if (endp == argv[2] || *endp != '\0') 161 errx(1, "invalid major number '%s'", argv[2]); 162 if (errno == ERANGE && major == ULONG_MAX) 163 errx(1, "major number too large: '%s'", argv[2]); 164 165 errno = 0; 166 minor = strtoul(argv[3], &endp, 0); 167 if (endp == argv[3] || *endp != '\0') 168 errx(1, "invalid minor number '%s'", argv[3]); 169 if (errno == ERANGE && minor == ULONG_MAX) 170 errx(1, "minor number too large: '%s'", argv[3]); 171 172 dev = makedev(major, minor); 173 if (major(dev) != major || minor(dev) != minor) 174 errx(1, "major or minor number too large (%lu %lu)", major, 175 minor); 176 177 return dev; 178 } 179 180 static int 181 domakenodes(struct node *node, int n) 182 { 183 int done_umask = 0; 184 int rv = 0; 185 int i; 186 187 for (i = 0; i != n; i++) { 188 int r; 189 /* 190 * If the user specified a mode via `-m', don't allow the umask 191 * to modify it. If no `-m' flag was specified, the default 192 * mode is the value of the bitwise inclusive or of S_IRUSR, 193 * S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH as 194 * modified by the umask. 195 */ 196 if (node[i].mflag && !done_umask) { 197 (void)umask(0); 198 done_umask = 1; 199 } 200 201 r = mknod(node[i].name, node[i].mode, node[i].dev); 202 if (r < 0) { 203 warn("%s", node[i].name); 204 rv = 1; 205 } 206 } 207 208 free(node); 209 return rv; 210 } 211 212 __dead static void 213 usage(int ismkfifo) 214 { 215 216 if (ismkfifo == 1) 217 (void)fprintf(stderr, "usage: %s [-m mode] fifo_name ...\n", 218 __progname); 219 else { 220 (void)fprintf(stderr, 221 "usage: %s [-m mode] name b|c major minor\n", 222 __progname); 223 (void)fprintf(stderr, " %s [-m mode] name p\n", 224 __progname); 225 } 226 exit(1); 227 } 228