GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/mknod/mknod.c Lines: 0 95 0.0 %
Date: 2016-12-06 Branches: 0 58 0.0 %

Line Branch Exec Source
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 rpath cpath wpath", 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
}