makedevs.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /* makedevs.c - Make ranges of device files.
  2. *
  3. * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
  4. * Copyright 2014 Kyungwan Han <asura321@gmail.com>
  5. *
  6. * No Standard
  7. USE_MAKEDEVS(NEWTOY(makedevs, "<1>1d:", TOYFLAG_USR|TOYFLAG_BIN))
  8. config MAKEDEVS
  9. bool "makedevs"
  10. default y
  11. help
  12. usage: makedevs [-d device_table] rootdir
  13. Create a range of special files as specified in a device table.
  14. -d File containing device table (default reads from stdin)
  15. Each line of the device table has the fields:
  16. <name> <type> <mode> <uid> <gid> <major> <minor> <start> <increment> <count>
  17. Where name is the file name, and type is one of the following:
  18. b Block device
  19. c Character device
  20. d Directory
  21. f Regular file
  22. p Named pipe (fifo)
  23. Other fields specify permissions, user and group id owning the file,
  24. and additional fields for device special files. Use '-' for blank entries,
  25. unspecified fields are treated as '-'.
  26. */
  27. #define FOR_makedevs
  28. #include "toys.h"
  29. GLOBALS(
  30. char *d;
  31. )
  32. void makedevs_main(void)
  33. {
  34. FILE *fp = stdin;
  35. char *line = NULL;
  36. size_t allocated_length = 0;
  37. int line_no = 0, i;
  38. // Open file and chdir, verbosely
  39. xprintf("rootdir = %s\n", *toys.optargs);
  40. if (FLAG(d) && strcmp(TT.d, "-")) {
  41. fp = xfopen(TT.d, "r");
  42. xprintf("table = %s\n", TT.d);
  43. } else xprintf("table = <stdin>\n");
  44. xchdir(*toys.optargs);
  45. while (getline(&line, &allocated_length, fp) > 0) {
  46. char type=0, user[64], group[64], *node, *ptr = line;
  47. unsigned int mode = 0755, major = 0, minor = 0, cnt = 0, incr = 0,
  48. st_val = 0;
  49. uid_t uid;
  50. gid_t gid;
  51. struct stat st;
  52. line_no++;
  53. while (isspace(*ptr)) ptr++;
  54. if (!*ptr || *ptr == '#') continue;
  55. node = ptr;
  56. while (*ptr && !isspace(*ptr)) ptr++;
  57. if (*ptr) *(ptr++) = 0;
  58. *user = *group = 0;
  59. sscanf(ptr, "%c %o %63s %63s %u %u %u %u %u", &type, &mode,
  60. user, group, &major, &minor, &st_val, &incr, &cnt);
  61. // type order here needs to line up with actions[] order.
  62. i = stridx("pcbdf", type);
  63. if (i == -1) {
  64. error_msg("line %d: bad type %c", line_no, type);
  65. continue;
  66. } else mode |= (mode_t[]){S_IFIFO, S_IFCHR, S_IFBLK, 0, 0}[i];
  67. uid = *user ? xgetuid(user) : getuid();
  68. gid = *group ? xgetgid(group) : getgid();
  69. while (*node == '/') node++; // using relative path
  70. for (i = 0; (!cnt && !i) || i < cnt; i++) {
  71. if (cnt>1) {
  72. snprintf(toybuf, sizeof(toybuf), "%.999s%u", node, st_val + i);
  73. ptr = toybuf;
  74. } else ptr = node;
  75. if (type == 'd') {
  76. if (mkpathat(AT_FDCWD, ptr, mode, MKPATHAT_MKLAST | MKPATHAT_MAKE)) {
  77. perror_msg("can't create directory '%s'", ptr);
  78. continue;
  79. }
  80. } else if (type == 'f') {
  81. if (stat(ptr, &st) || !S_ISREG(st.st_mode)) {
  82. perror_msg("line %d: file '%s' does not exist", line_no, ptr);
  83. continue;
  84. }
  85. } else if (mknod(ptr, mode, dev_makedev(major, minor + i*incr))) {
  86. perror_msg("line %d: can't create node '%s'", line_no, ptr);
  87. continue;
  88. }
  89. if (chown(ptr, uid, gid) || chmod(ptr, mode))
  90. perror_msg("line %d: can't chown/chmod '%s'", line_no, ptr);
  91. }
  92. }
  93. free(line);
  94. if (fp != stdin) fclose(fp);
  95. }