parse_mode.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * parse_mode implementation for busybox
  4. *
  5. * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
  6. *
  7. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  8. */
  9. /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
  10. #include <stdlib.h>
  11. #include <assert.h>
  12. #include <sys/stat.h>
  13. #include "libbb.h"
  14. #define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
  15. int bb_parse_mode(const char *s, mode_t *current_mode)
  16. {
  17. static const mode_t who_mask[] = {
  18. S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
  19. S_ISUID | S_IRWXU, /* u */
  20. S_ISGID | S_IRWXG, /* g */
  21. S_IRWXO /* o */
  22. };
  23. static const mode_t perm_mask[] = {
  24. S_IRUSR | S_IRGRP | S_IROTH, /* r */
  25. S_IWUSR | S_IWGRP | S_IWOTH, /* w */
  26. S_IXUSR | S_IXGRP | S_IXOTH, /* x */
  27. S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
  28. S_ISUID | S_ISGID, /* s */
  29. S_ISVTX /* t */
  30. };
  31. static const char who_chars[] = "augo";
  32. static const char perm_chars[] = "rwxXst";
  33. const char *p;
  34. mode_t wholist;
  35. mode_t permlist;
  36. mode_t mask;
  37. mode_t new_mode;
  38. char op;
  39. assert(s);
  40. if (((unsigned int)(*s - '0')) < 8) {
  41. unsigned long tmp;
  42. char *e;
  43. tmp = strtol(s, &e, 8);
  44. if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
  45. return 0;
  46. }
  47. *current_mode = tmp;
  48. return 1;
  49. }
  50. mask = umask(0);
  51. umask(mask);
  52. new_mode = *current_mode;
  53. /* Note: We allow empty clauses, and hence empty modes.
  54. * We treat an empty mode as no change to perms. */
  55. while (*s) { /* Process clauses. */
  56. if (*s == ',') { /* We allow empty clauses. */
  57. ++s;
  58. continue;
  59. }
  60. /* Get a wholist. */
  61. wholist = 0;
  62. WHO_LIST:
  63. p = who_chars;
  64. do {
  65. if (*p == *s) {
  66. wholist |= who_mask[(int)(p-who_chars)];
  67. if (!*++s) {
  68. return 0;
  69. }
  70. goto WHO_LIST;
  71. }
  72. } while (*++p);
  73. do { /* Process action list. */
  74. if ((*s != '+') && (*s != '-')) {
  75. if (*s != '=') {
  76. return 0;
  77. }
  78. /* Since op is '=', clear all bits corresponding to the
  79. * wholist, of all file bits if wholist is empty. */
  80. permlist = ~FILEMODEBITS;
  81. if (wholist) {
  82. permlist = ~wholist;
  83. }
  84. new_mode &= permlist;
  85. }
  86. op = *s++;
  87. /* Check for permcopy. */
  88. p = who_chars + 1; /* Skip 'a' entry. */
  89. do {
  90. if (*p == *s) {
  91. int i = 0;
  92. permlist = who_mask[(int)(p-who_chars)]
  93. & (S_IRWXU | S_IRWXG | S_IRWXO)
  94. & new_mode;
  95. do {
  96. if (permlist & perm_mask[i]) {
  97. permlist |= perm_mask[i];
  98. }
  99. } while (++i < 3);
  100. ++s;
  101. goto GOT_ACTION;
  102. }
  103. } while (*++p);
  104. /* It was not a permcopy, so get a permlist. */
  105. permlist = 0;
  106. PERM_LIST:
  107. p = perm_chars;
  108. do {
  109. if (*p == *s) {
  110. if ((*p != 'X')
  111. || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
  112. ) {
  113. permlist |= perm_mask[(int)(p-perm_chars)];
  114. }
  115. if (!*++s) {
  116. break;
  117. }
  118. goto PERM_LIST;
  119. }
  120. } while (*++p);
  121. GOT_ACTION:
  122. if (permlist) { /* The permlist was nonempty. */
  123. mode_t tmp = ~mask;
  124. if (wholist) {
  125. tmp = wholist;
  126. }
  127. permlist &= tmp;
  128. if (op == '-') {
  129. new_mode &= ~permlist;
  130. } else {
  131. new_mode |= permlist;
  132. }
  133. }
  134. } while (*s && (*s != ','));
  135. }
  136. *current_mode = new_mode;
  137. return 1;
  138. }