logo

utils-std

Collection of commonly available Unix tools

mknod.c (3060B)


  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 "../lib/mode.h"
  7. #include <assert.h>
  8. #include <errno.h>
  9. #include <stdio.h> // fprintf
  10. #include <stdlib.h> // abort, exit
  11. #include <string.h> // strerror, strrchr
  12. #include <sys/stat.h> // mknod
  13. #include <sys/sysmacros.h> // makedev
  14. #include <unistd.h> // getopt
  15. mode_t filemask;
  16. static void
  17. usage()
  18. {
  19. fprintf(stderr, "Usage: mknod [-m mode] file <b|c|u|p> [major minor]\n");
  20. }
  21. static unsigned int
  22. strtodev(char *arg)
  23. {
  24. char *endptr = NULL;
  25. assert(errno == 0);
  26. long dev = strtol(arg, &endptr, 0);
  27. if(errno != 0)
  28. {
  29. fprintf(stderr, "mknod: Failed parsing '%s' into a number: %s\n", arg, strerror(errno));
  30. exit(1);
  31. }
  32. if(endptr != NULL && endptr[0] != 0)
  33. {
  34. fprintf(stderr,
  35. "mknod: Extraneous characters in '%s' while parsing it as a number: '%s'\n",
  36. arg,
  37. endptr);
  38. exit(1);
  39. }
  40. return (unsigned int)dev;
  41. }
  42. int
  43. main(int argc, char *argv[])
  44. {
  45. mode_t mode = 0666;
  46. const char *errstr = NULL;
  47. int c = -1;
  48. while((c = getopt(argc, argv, ":m:")) != -1)
  49. {
  50. switch(c)
  51. {
  52. case 'm':
  53. mode = new_mode(optarg, 0666, &errstr);
  54. if(errstr != NULL)
  55. {
  56. fprintf(stderr, "mknod: Failed parsing mode '%s': %s\n", optarg, errstr);
  57. return 1;
  58. }
  59. break;
  60. case ':':
  61. fprintf(stderr, "mknod: Error: Missing operand for option: '-%c'\n", optopt);
  62. usage();
  63. return 1;
  64. case '?':
  65. fprintf(stderr, "mknod: Error: Unrecognised option: '-%c'\n", optopt);
  66. usage();
  67. return 1;
  68. default:
  69. abort();
  70. }
  71. }
  72. argc -= optind;
  73. argv += optind;
  74. assert(errno == 0);
  75. if(argc < 2)
  76. {
  77. fprintf(stderr, "mknod: Missing operands\n");
  78. usage();
  79. return 1;
  80. }
  81. char *file = argv[0];
  82. char *type = argv[1];
  83. if(type[0] == 0 || type[1] != 0)
  84. {
  85. fprintf(stderr, "mknod: Invalid type '%s'\n", type);
  86. usage();
  87. return 1;
  88. }
  89. assert(errno == 0);
  90. if(type[0] == 'p')
  91. {
  92. if(mknod(file, mode | S_IFIFO, 0) != 0)
  93. {
  94. fprintf(stderr, "mknod: Failed creating FIFO at '%s': %s\n", file, strerror(errno));
  95. return 1;
  96. }
  97. }
  98. else
  99. {
  100. if(argc != 4)
  101. {
  102. fprintf(stderr, "mknod: non-FIFO device types requires major minor arguments to be given\n");
  103. return 1;
  104. }
  105. unsigned int maj = strtodev(argv[2]);
  106. unsigned int min = strtodev(argv[3]);
  107. char *type_name;
  108. switch(type[0])
  109. {
  110. case 'b':
  111. mode |= S_IFBLK;
  112. type_name = "block-special";
  113. break;
  114. case 'c':
  115. mode |= S_IFCHR;
  116. type_name = "character-special";
  117. break;
  118. case 'u':
  119. mode |= S_IFCHR;
  120. type_name = "character-special";
  121. break;
  122. default:
  123. fprintf(stderr, "mknod: Invalid type '%c'\n", type[0]);
  124. usage();
  125. return 1;
  126. }
  127. if(mknod(file, mode, makedev(maj, min)) != 0)
  128. {
  129. fprintf(stderr, "mknod: Failed creating %s at '%s': %s\n", type_name, file, strerror(errno));
  130. return 1;
  131. }
  132. }
  133. return 0;
  134. }