parse_mode.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. */
  22. /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
  23. #include <stdlib.h>
  24. #include <assert.h>
  25. #include <sys/stat.h>
  26. #include "libbb.h"
  27. #define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
  28. int bb_parse_mode(const char *s, mode_t *current_mode)
  29. {
  30. static const mode_t who_mask[] = {
  31. S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
  32. S_ISUID | S_IRWXU, /* u */
  33. S_ISGID | S_IRWXG, /* g */
  34. S_IRWXO /* o */
  35. };
  36. static const mode_t perm_mask[] = {
  37. S_IRUSR | S_IRGRP | S_IROTH, /* r */
  38. S_IWUSR | S_IWGRP | S_IWOTH, /* w */
  39. S_IXUSR | S_IXGRP | S_IXOTH, /* x */
  40. S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
  41. S_ISUID | S_ISGID, /* s */
  42. S_ISVTX /* t */
  43. };
  44. static const char who_chars[] = "augo";
  45. static const char perm_chars[] = "rwxXst";
  46. const char *p;
  47. mode_t wholist;
  48. mode_t permlist;
  49. mode_t mask;
  50. mode_t new_mode;
  51. char op;
  52. assert(s);
  53. if (((unsigned int)(*s - '0')) < 8) {
  54. unsigned long tmp;
  55. char *e;
  56. tmp = strtol(s, &e, 8);
  57. if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
  58. return 0;
  59. }
  60. *current_mode = tmp;
  61. return 1;
  62. }
  63. mask = umask(0);
  64. umask(mask);
  65. new_mode = *current_mode;
  66. /* Note: We allow empty clauses, and hence empty modes.
  67. * We treat an empty mode as no change to perms. */
  68. while (*s) { /* Process clauses. */
  69. if (*s == ',') { /* We allow empty clauses. */
  70. ++s;
  71. continue;
  72. }
  73. /* Get a wholist. */
  74. wholist = 0;
  75. WHO_LIST:
  76. p = who_chars;
  77. do {
  78. if (*p == *s) {
  79. wholist |= who_mask[(int)(p-who_chars)];
  80. if (!*++s) {
  81. return 0;
  82. }
  83. goto WHO_LIST;
  84. }
  85. } while (*++p);
  86. do { /* Process action list. */
  87. if ((*s != '+') && (*s != '-')) {
  88. if (*s != '=') {
  89. return 0;
  90. }
  91. /* Since op is '=', clear all bits corresponding to the
  92. * wholist, of all file bits if wholist is empty. */
  93. permlist = ~FILEMODEBITS;
  94. if (wholist) {
  95. permlist = ~wholist;
  96. }
  97. new_mode &= permlist;
  98. }
  99. op = *s++;
  100. /* Check for permcopy. */
  101. p = who_chars + 1; /* Skip 'a' entry. */
  102. do {
  103. if (*p == *s) {
  104. int i = 0;
  105. permlist = who_mask[(int)(p-who_chars)]
  106. & (S_IRWXU | S_IRWXG | S_IRWXO)
  107. & new_mode;
  108. do {
  109. if (permlist & perm_mask[i]) {
  110. permlist |= perm_mask[i];
  111. }
  112. } while (++i < 3);
  113. ++s;
  114. goto GOT_ACTION;
  115. }
  116. } while (*++p);
  117. /* It was not a permcopy, so get a permlist. */
  118. permlist = 0;
  119. PERM_LIST:
  120. p = perm_chars;
  121. do {
  122. if (*p == *s) {
  123. if ((*p != 'X')
  124. || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
  125. ) {
  126. permlist |= perm_mask[(int)(p-perm_chars)];
  127. }
  128. if (!*++s) {
  129. break;
  130. }
  131. goto PERM_LIST;
  132. }
  133. } while (*++p);
  134. GOT_ACTION:
  135. if (permlist) { /* The permlist was nonempty. */
  136. mode_t tmp = ~mask;
  137. if (wholist) {
  138. tmp = wholist;
  139. }
  140. permlist &= tmp;
  141. if (op == '-') {
  142. new_mode &= ~permlist;
  143. } else {
  144. new_mode |= permlist;
  145. }
  146. }
  147. } while (*s && (*s != ','));
  148. }
  149. *current_mode = new_mode;
  150. return 1;
  151. }