logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/

mknod.c (3578B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #define _XOPEN_SOURCE 700 // mknod is in XSI
  6. #include "../config.h"
  7. #include "../libutils/getopt_nolong.h"
  8. #include "../libutils/mode.h"
  9. #include <errno.h>
  10. #include <stdio.h> // fprintf
  11. #include <stdlib.h> // abort, exit
  12. #include <string.h> // strerror, strrchr
  13. #include <sys/stat.h> // mknod
  14. #include <sys/sysmacros.h> // makedev
  15. #include <unistd.h> // getopt
  16. #ifdef HAS_GETOPT_LONG
  17. #include <getopt.h>
  18. #endif
  19. mode_t filemask;
  20. const char *argv0 = "mknod";
  21. static void
  22. usage(void)
  23. {
  24. fprintf(stderr, "Usage: mknod [-m mode] file <b|c|u|p> [major minor]\n");
  25. }
  26. static unsigned int
  27. strtodev(char *arg)
  28. {
  29. char *endptr = NULL;
  30. long dev = strtol(arg, &endptr, 0);
  31. if(errno != 0)
  32. {
  33. fprintf(stderr, "mknod: error: Failed parsing '%s' into a number: %s\n", arg, strerror(errno));
  34. exit(1);
  35. }
  36. if(endptr != NULL && endptr[0] != 0)
  37. {
  38. fprintf(stderr,
  39. "mknod: error: Extraneous characters in '%s' while parsing it as a number: '%s'\n",
  40. arg,
  41. endptr);
  42. exit(1);
  43. }
  44. return (unsigned int)dev;
  45. }
  46. int
  47. main(int argc, char *argv[])
  48. {
  49. mode_t mode = 0666;
  50. const char *errstr = NULL;
  51. #ifdef HAS_GETOPT_LONG
  52. // Strictly for GNUisms compatibility so no long-only options
  53. // clang-format off
  54. static struct option opts[] = {
  55. {"mode", required_argument, NULL, 'm'},
  56. {0, 0, 0, 0},
  57. };
  58. // clang-format on
  59. // Need + as first character to get POSIX-style option parsing
  60. for(int c = -1; (c = getopt_long(argc, argv, "+:m:", opts, NULL)) != -1;)
  61. #else
  62. for(int c = -1; (c = getopt_nolong(argc, argv, ":m:")) != -1;)
  63. #endif
  64. {
  65. switch(c)
  66. {
  67. case 'm':
  68. mode = new_mode(optarg, 0666, &errstr);
  69. if(errstr != NULL)
  70. {
  71. fprintf(stderr, "mknod: error: Failed parsing mode '%s': %s\n", optarg, errstr);
  72. return 1;
  73. }
  74. break;
  75. case ':':
  76. fprintf(stderr, "mknod: error: Missing operand for option: '-%c'\n", optopt);
  77. usage();
  78. return 1;
  79. case '?':
  80. GETOPT_UNKNOWN_OPT
  81. usage();
  82. return 1;
  83. default:
  84. abort();
  85. }
  86. }
  87. argc -= optind;
  88. argv += optind;
  89. if(argc < 2)
  90. {
  91. fprintf(stderr, "mknod: error: Missing operands\n");
  92. usage();
  93. return 1;
  94. }
  95. char *file = argv[0];
  96. char *type = argv[1];
  97. if(type[0] == 0 || type[1] != 0)
  98. {
  99. fprintf(stderr, "mknod: error: Invalid type '%s'\n", type);
  100. usage();
  101. return 1;
  102. }
  103. if(type[0] == 'p')
  104. {
  105. if(mknod(file, mode | S_IFIFO, 0) != 0)
  106. {
  107. fprintf(stderr, "mknod: error: Failed creating FIFO at '%s': %s\n", file, strerror(errno));
  108. return 1;
  109. }
  110. }
  111. else
  112. {
  113. if(argc != 4)
  114. {
  115. fprintf(stderr,
  116. "mknod: error: non-FIFO device types requires major minor arguments to be given\n");
  117. return 1;
  118. }
  119. unsigned int maj = strtodev(argv[2]);
  120. unsigned int min = strtodev(argv[3]);
  121. const char *type_name;
  122. switch(type[0])
  123. {
  124. case 'b':
  125. mode |= S_IFBLK;
  126. type_name = "block-special";
  127. break;
  128. case 'c':
  129. mode |= S_IFCHR;
  130. type_name = "character-special";
  131. break;
  132. case 'u':
  133. mode |= S_IFCHR;
  134. type_name = "character-special";
  135. break;
  136. default:
  137. fprintf(stderr, "mknod: error: Invalid type '%c'\n", type[0]);
  138. usage();
  139. return 1;
  140. }
  141. if(mknod(file, mode, makedev(maj, min)) != 0)
  142. {
  143. fprintf(stderr,
  144. "mknod: error: Failed creating %s at '%s': %s\n",
  145. type_name,
  146. file,
  147. strerror(errno));
  148. return 1;
  149. }
  150. }
  151. return 0;
  152. }