logo

utils-std

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

mknod.c (3104B)


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