master xplshn/aruu / shared / libutil / mode.c
  1/* See LICENSE file for copyright and license details. */
  2#include <stdlib.h>
  3#include <string.h>
  4#include <sys/stat.h>
  5#include <unistd.h>
  6
  7#include "../util.h"
  8
  9mode_t
 10getumask(void)
 11{
 12	mode_t mask = umask(0);
 13	umask(mask);
 14	return mask;
 15}
 16
 17mode_t
 18parsemode(const char *str, mode_t mode, mode_t mask)
 19{
 20	char *end;
 21	const char *p = str;
 22	int octal, op;
 23	mode_t who, perm, clear;
 24
 25	octal = strtol(str, &end, 8);
 26	if (*end == '\0') {
 27		if (octal < 0 || octal > 07777)
 28			eprintf("%s: invalid mode\n", str);
 29		return octal;
 30	}
 31next:
 32	/* first, determine which bits we will be modifying */
 33	for (who = 0; *p; p++) {
 34		switch (*p) {
 35		/* masks */
 36		case 'u':
 37			who |= S_IRWXU|S_ISUID;
 38			continue;
 39		case 'g':
 40			who |= S_IRWXG|S_ISGID;
 41			continue;
 42		case 'o':
 43			who |= S_IRWXO|S_ISVTX;
 44			continue;
 45		case 'a':
 46			who |= S_IRWXU|S_ISUID|S_IRWXG|S_ISGID|S_IRWXO|S_ISVTX;
 47			continue;
 48		}
 49		break;
 50	}
 51	if (who) {
 52		clear = who;
 53	} else {
 54		clear = S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO;
 55		who = ~mask;
 56	}
 57	while (*p) {
 58		switch (*p) {
 59		/* opers */
 60		case '=':
 61		case '+':
 62		case '-':
 63			op = (int)*p;
 64			break;
 65		default:
 66			eprintf("%s: invalid mode\n", str);
 67		}
 68
 69		perm = 0;
 70		switch (*++p) {
 71		/* copy */
 72		case 'u':
 73			if (mode & S_IRUSR)
 74				perm |= S_IRUSR|S_IRGRP|S_IROTH;
 75			if (mode & S_IWUSR)
 76				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
 77			if (mode & S_IXUSR)
 78				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
 79			if (mode & S_ISUID)
 80				perm |= S_ISUID|S_ISGID;
 81			p++;
 82			break;
 83		case 'g':
 84			if (mode & S_IRGRP)
 85				perm |= S_IRUSR|S_IRGRP|S_IROTH;
 86			if (mode & S_IWGRP)
 87				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
 88			if (mode & S_IXGRP)
 89				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
 90			if (mode & S_ISGID)
 91				perm |= S_ISUID|S_ISGID;
 92			p++;
 93			break;
 94		case 'o':
 95			if (mode & S_IROTH)
 96				perm |= S_IRUSR|S_IRGRP|S_IROTH;
 97			if (mode & S_IWOTH)
 98				perm |= S_IWUSR|S_IWGRP|S_IWOTH;
 99			if (mode & S_IXOTH)
100				perm |= S_IXUSR|S_IXGRP|S_IXOTH;
101			p++;
102			break;
103		default:
104			for (; *p; p++) {
105				switch (*p) {
106				/* modes */
107				case 'r':
108					perm |= S_IRUSR|S_IRGRP|S_IROTH;
109					break;
110				case 'w':
111					perm |= S_IWUSR|S_IWGRP|S_IWOTH;
112					break;
113				case 'x':
114					perm |= S_IXUSR|S_IXGRP|S_IXOTH;
115					break;
116				case 'X':
117					if (S_ISDIR(mode) || mode & (S_IXUSR|S_IXGRP|S_IXOTH))
118						perm |= S_IXUSR|S_IXGRP|S_IXOTH;
119					break;
120				case 's':
121					perm |= S_ISUID|S_ISGID;
122					break;
123				case 't':
124					perm |= S_ISVTX;
125					break;
126				default:
127					goto apply;
128				}
129			}
130		}
131
132apply:
133		/* apply */
134		switch (op) {
135		case '=':
136			mode &= ~clear;
137			/* fallthrough */
138		case '+':
139			mode |= perm & who;
140			break;
141		case '-':
142			mode &= ~(perm & who);
143			break;
144		}
145		/* if we hit a comma, move on to the next clause */
146		if (*p == ',') {
147			p++;
148			goto next;
149		}
150	}
151	return mode & ~S_IFMT;
152}