mknod.c (3188B)
- // utils-std: Collection of commonly available Unix tools
- // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- #define _POSIX_C_SOURCE 200809L
- #define _XOPEN_SOURCE 700 // mknod is in XSI
- #include "../lib/mode.h"
- #include <assert.h>
- #include <errno.h>
- #include <stdio.h> // fprintf
- #include <stdlib.h> // abort, exit
- #include <string.h> // strerror, strrchr
- #include <sys/stat.h> // mknod
- #include <sys/sysmacros.h> // makedev
- #include <unistd.h> // getopt
- mode_t filemask;
- static void
- usage(void)
- {
- fprintf(stderr, "Usage: mknod [-m mode] file <b|c|u|p> [major minor]\n");
- }
- static unsigned int
- strtodev(char *arg)
- {
- char *endptr = NULL;
- assert(errno == 0);
- long dev = strtol(arg, &endptr, 0);
- if(errno != 0)
- {
- fprintf(stderr, "mknod: error: Failed parsing '%s' into a number: %s\n", arg, strerror(errno));
- exit(1);
- }
- if(endptr != NULL && endptr[0] != 0)
- {
- fprintf(stderr,
- "mknod: error: Extraneous characters in '%s' while parsing it as a number: '%s'\n",
- arg,
- endptr);
- exit(1);
- }
- return (unsigned int)dev;
- }
- int
- main(int argc, char *argv[])
- {
- mode_t mode = 0666;
- const char *errstr = NULL;
- int c = -1;
- while((c = getopt(argc, argv, ":m:")) != -1)
- {
- switch(c)
- {
- case 'm':
- mode = new_mode(optarg, 0666, &errstr);
- if(errstr != NULL)
- {
- fprintf(stderr, "mknod: error: Failed parsing mode '%s': %s\n", optarg, errstr);
- return 1;
- }
- break;
- case ':':
- fprintf(stderr, "mknod: error: Missing operand for option: '-%c'\n", optopt);
- usage();
- return 1;
- case '?':
- fprintf(stderr, "mknod: error: Unrecognised option: '-%c'\n", optopt);
- usage();
- return 1;
- default:
- abort();
- }
- }
- argc -= optind;
- argv += optind;
- assert(errno == 0);
- if(argc < 2)
- {
- fprintf(stderr, "mknod: error: Missing operands\n");
- usage();
- return 1;
- }
- char *file = argv[0];
- char *type = argv[1];
- if(type[0] == 0 || type[1] != 0)
- {
- fprintf(stderr, "mknod: error: Invalid type '%s'\n", type);
- usage();
- return 1;
- }
- assert(errno == 0);
- if(type[0] == 'p')
- {
- if(mknod(file, mode | S_IFIFO, 0) != 0)
- {
- fprintf(stderr, "mknod: error: Failed creating FIFO at '%s': %s\n", file, strerror(errno));
- return 1;
- }
- }
- else
- {
- if(argc != 4)
- {
- fprintf(stderr,
- "mknod: error: non-FIFO device types requires major minor arguments to be given\n");
- return 1;
- }
- unsigned int maj = strtodev(argv[2]);
- unsigned int min = strtodev(argv[3]);
- const char *type_name;
- switch(type[0])
- {
- case 'b':
- mode |= S_IFBLK;
- type_name = "block-special";
- break;
- case 'c':
- mode |= S_IFCHR;
- type_name = "character-special";
- break;
- case 'u':
- mode |= S_IFCHR;
- type_name = "character-special";
- break;
- default:
- fprintf(stderr, "mknod: error: Invalid type '%c'\n", type[0]);
- usage();
- return 1;
- }
- if(mknod(file, mode, makedev(maj, min)) != 0)
- {
- fprintf(stderr,
- "mknod: error: Failed creating %s at '%s': %s\n",
- type_name,
- file,
- strerror(errno));
- return 1;
- }
- }
- return 0;
- }