summaryrefslogtreecommitdiff
path: root/libbb/parse_mode.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbb/parse_mode.c')
-rw-r--r--libbb/parse_mode.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c
new file mode 100644
index 0000000..33a8781
--- /dev/null
+++ b/libbb/parse_mode.c
@@ -0,0 +1,138 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) tons of folks. Tracking down who wrote what
+ * isn't something I'm going to worry about... If you wrote something
+ * here, please feel free to acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
+ * Permission has been granted to redistribute this code under the GPL.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+
+/* This function parses the sort of string you might pass
+ * to chmod (i.e. [ugoa]{+|-|=}[rwxst] ) and returns the
+ * correct mode described by the string. */
+extern int parse_mode(const char *s, mode_t * theMode)
+{
+ static const mode_t group_set[] = {
+ S_ISUID | S_IRWXU, /* u */
+ S_ISGID | S_IRWXG, /* g */
+ S_IRWXO, /* o */
+ S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */
+ };
+
+ static const mode_t mode_set[] = {
+ S_IRUSR | S_IRGRP | S_IROTH, /* r */
+ S_IWUSR | S_IWGRP | S_IWOTH, /* w */
+ S_IXUSR | S_IXGRP | S_IXOTH, /* x */
+ S_ISUID | S_ISGID, /* s */
+ S_ISVTX /* t */
+ };
+
+ static const char group_string[] = "ugoa";
+ static const char mode_string[] = "rwxst";
+
+ const char *p;
+
+ mode_t andMode =
+ S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+ mode_t orMode = 0;
+ mode_t mode;
+ mode_t groups;
+ char type;
+ char c;
+
+ if (s==NULL) {
+ return (FALSE);
+ }
+
+ do {
+ mode = 0;
+ groups = 0;
+ NEXT_GROUP:
+ if ((c = *s++) == '\0') {
+ return -1;
+ }
+ for (p=group_string ; *p ; p++) {
+ if (*p == c) {
+ groups |= group_set[(int)(p-group_string)];
+ goto NEXT_GROUP;
+ }
+ }
+ switch (c) {
+ case '=':
+ case '+':
+ case '-':
+ type = c;
+ if (groups == 0) { /* The default is "all" */
+ groups |= S_ISUID | S_ISGID | S_ISVTX
+ | S_IRWXU | S_IRWXG | S_IRWXO;
+ }
+ break;
+ default:
+ if ((c < '0') || (c > '7') || (mode | groups)) {
+ return (FALSE);
+ } else {
+ *theMode = strtol(--s, NULL, 8);
+ return (TRUE);
+ }
+ }
+
+ NEXT_MODE:
+ if (((c = *s++) != '\0') && (c != ',')) {
+ for (p=mode_string ; *p ; p++) {
+ if (*p == c) {
+ mode |= mode_set[(int)(p-mode_string)];
+ goto NEXT_MODE;
+ }
+ }
+ break; /* We're done so break out of loop.*/
+ }
+ switch (type) {
+ case '=':
+ andMode &= ~(groups); /* Now fall through. */
+ case '+':
+ orMode |= mode & groups;
+ break;
+ case '-':
+ andMode &= ~(mode & groups);
+ orMode &= ~(mode & groups);
+ break;
+ }
+ } while (c == ',');
+
+ *theMode &= andMode;
+ *theMode |= orMode;
+
+ return TRUE;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/