225 lines
5.0 KiB
C
225 lines
5.0 KiB
C
/* $OpenBSD: mknod.c,v 1.31 2019/06/28 13:32:44 deraadt Exp $ */
|
|
/* $NetBSD: mknod.c,v 1.8 1995/08/11 00:08:18 jtc Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1997-2016 Theo de Raadt <deraadt@openbsd.org>,
|
|
* Marc Espie <espie@openbsd.org>, Todd Miller <millert@openbsd.org>,
|
|
* Martin Natano <natano@openbsd.org>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
extern char *__progname;
|
|
|
|
struct node {
|
|
const char *name;
|
|
mode_t mode;
|
|
dev_t dev;
|
|
char mflag;
|
|
};
|
|
|
|
static int domakenodes(struct node *, int);
|
|
static dev_t compute_device(int, char **);
|
|
__dead static void usage(int);
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
struct node *node;
|
|
int ismkfifo;
|
|
int n = 0;
|
|
int mode = DEFFILEMODE;
|
|
int mflag = 0;
|
|
void *set;
|
|
int ch;
|
|
|
|
if (pledge("stdio dpath", NULL) == -1)
|
|
err(1, "pledge");
|
|
|
|
node = reallocarray(NULL, sizeof(struct node), argc);
|
|
if (!node)
|
|
err(1, NULL);
|
|
|
|
ismkfifo = strcmp(__progname, "mkfifo") == 0;
|
|
|
|
/* we parse all arguments upfront */
|
|
while (argc > 1) {
|
|
while ((ch = getopt(argc, argv, "m:")) != -1) {
|
|
switch (ch) {
|
|
case 'm':
|
|
if (!(set = setmode(optarg)))
|
|
errx(1, "invalid file mode '%s'",
|
|
optarg);
|
|
/*
|
|
* In symbolic mode strings, the + and -
|
|
* operators are interpreted relative to
|
|
* an assumed initial mode of a=rw.
|
|
*/
|
|
mode = getmode(set, DEFFILEMODE);
|
|
if ((mode & ACCESSPERMS) != mode)
|
|
errx(1, "forbidden mode: %o", mode);
|
|
mflag = 1;
|
|
free(set);
|
|
break;
|
|
default:
|
|
usage(ismkfifo);
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if (ismkfifo) {
|
|
while (*argv) {
|
|
node[n].mode = mode | S_IFIFO;
|
|
node[n].mflag = mflag;
|
|
node[n].name = *argv;
|
|
node[n].dev = 0;
|
|
n++;
|
|
argv++;
|
|
}
|
|
/* XXX no multiple getopt */
|
|
break;
|
|
} else {
|
|
if (argc < 2)
|
|
usage(ismkfifo);
|
|
node[n].mode = mode;
|
|
node[n].mflag = mflag;
|
|
node[n].name = argv[0];
|
|
if (strlen(argv[1]) != 1)
|
|
errx(1, "invalid device type '%s'", argv[1]);
|
|
|
|
/* XXX computation offset by one for next getopt */
|
|
switch(argv[1][0]) {
|
|
case 'p':
|
|
node[n].mode |= S_IFIFO;
|
|
node[n].dev = 0;
|
|
argv++;
|
|
argc--;
|
|
break;
|
|
case 'b':
|
|
node[n].mode |= S_IFBLK;
|
|
goto common;
|
|
case 'c':
|
|
node[n].mode |= S_IFCHR;
|
|
common:
|
|
node[n].dev = compute_device(argc, argv);
|
|
argv+=3;
|
|
argc-=3;
|
|
break;
|
|
default:
|
|
errx(1, "invalid device type '%s'", argv[1]);
|
|
}
|
|
n++;
|
|
}
|
|
optind = 1;
|
|
optreset = 1;
|
|
}
|
|
|
|
if (n == 0)
|
|
usage(ismkfifo);
|
|
|
|
return (domakenodes(node, n));
|
|
}
|
|
|
|
static dev_t
|
|
compute_device(int argc, char **argv)
|
|
{
|
|
dev_t dev;
|
|
char *endp;
|
|
unsigned long major, minor;
|
|
|
|
if (argc < 4)
|
|
usage(0);
|
|
|
|
errno = 0;
|
|
major = strtoul(argv[2], &endp, 0);
|
|
if (endp == argv[2] || *endp != '\0')
|
|
errx(1, "invalid major number '%s'", argv[2]);
|
|
if (errno == ERANGE && major == ULONG_MAX)
|
|
errx(1, "major number too large: '%s'", argv[2]);
|
|
|
|
errno = 0;
|
|
minor = strtoul(argv[3], &endp, 0);
|
|
if (endp == argv[3] || *endp != '\0')
|
|
errx(1, "invalid minor number '%s'", argv[3]);
|
|
if (errno == ERANGE && minor == ULONG_MAX)
|
|
errx(1, "minor number too large: '%s'", argv[3]);
|
|
|
|
dev = makedev(major, minor);
|
|
if (major(dev) != major || minor(dev) != minor)
|
|
errx(1, "major or minor number too large (%lu %lu)", major,
|
|
minor);
|
|
|
|
return dev;
|
|
}
|
|
|
|
static int
|
|
domakenodes(struct node *node, int n)
|
|
{
|
|
int done_umask = 0;
|
|
int rv = 0;
|
|
int i;
|
|
|
|
for (i = 0; i != n; i++) {
|
|
int r;
|
|
/*
|
|
* If the user specified a mode via `-m', don't allow the umask
|
|
* to modify it. If no `-m' flag was specified, the default
|
|
* mode is the value of the bitwise inclusive or of S_IRUSR,
|
|
* S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH as
|
|
* modified by the umask.
|
|
*/
|
|
if (node[i].mflag && !done_umask) {
|
|
(void)umask(0);
|
|
done_umask = 1;
|
|
}
|
|
|
|
r = mknod(node[i].name, node[i].mode, node[i].dev);
|
|
if (r == -1) {
|
|
warn("%s", node[i].name);
|
|
rv = 1;
|
|
}
|
|
}
|
|
|
|
free(node);
|
|
return rv;
|
|
}
|
|
|
|
__dead static void
|
|
usage(int ismkfifo)
|
|
{
|
|
|
|
if (ismkfifo == 1)
|
|
(void)fprintf(stderr, "usage: %s [-m mode] fifo_name ...\n",
|
|
__progname);
|
|
else {
|
|
(void)fprintf(stderr,
|
|
"usage: %s [-m mode] name b|c major minor\n",
|
|
__progname);
|
|
(void)fprintf(stderr, " %s [-m mode] name p\n",
|
|
__progname);
|
|
}
|
|
exit(1);
|
|
}
|