xref: /csrg-svn/bin/chmod/chmod.c (revision 18473)
1*18473Smckusick static char *sccsid = "@(#)chmod.c	4.5 03/20/85";
216242Slayer 
316242Slayer /*
416242Slayer  * chmod options mode files
516242Slayer  * where
6*18473Smckusick  *	mode	is [ugoa][+-=][rwxXstugo] or a octal number
716242Slayer  *	options are -R
816242Slayer  */
916242Slayer #include <stdio.h>
1016242Slayer #include <sys/types.h>
1116242Slayer #include <sys/stat.h>
1216242Slayer #include <sys/dir.h>
1316242Slayer 
1416242Slayer #define	USER	05700	/* user's bits */
1516242Slayer #define	GROUP	02070	/* group's bits */
1616242Slayer #define	OTHER	00007	/* other's bits */
1716242Slayer #define	ALL	01777	/* all (note absence of setuid, etc) */
1816242Slayer 
1916242Slayer #define	READ	00444	/* read permit */
2016242Slayer #define	WRITE	00222	/* write permit */
2116242Slayer #define	EXEC	00111	/* exec permit */
2216242Slayer #define	SETID	06000	/* set[ug]id */
2316242Slayer #define	STICKY	01000	/* sticky bit */
2416242Slayer 
2516242Slayer char	*modestring, *ms;
2616242Slayer int	um;
2716242Slayer int	status;
28*18473Smckusick int	rflag, debug;
2916242Slayer 
3016242Slayer main(argc,argv)
3116242Slayer char **argv;
3216242Slayer {
3316242Slayer 	register i;
3416270Slayer 	register char *p, *flags;
3516242Slayer 	struct	stat st;
3616242Slayer 
37*18473Smckusick usage:
3816242Slayer 	if (argc < 3) {
3916242Slayer 		fprintf(stderr
40*18473Smckusick 			,"Usage: chmod [-R] [ugoa][+-=][rwxXstugo] file ...\n");
4116242Slayer 		exit(-1);
4216242Slayer 	}
4316270Slayer 
4416242Slayer 	argv++, --argc;
4516270Slayer 	if (*argv[0] == '-') {
4616270Slayer 		for (flags = argv[0]; *flags; ++flags)
4716270Slayer 			switch (*flags) {
4816270Slayer 			  case '-':			break;
4916270Slayer 			  case 'R':	rflag++;	break;
50*18473Smckusick 			  default: 	argc = 0;	goto usage;
5116270Slayer 			}
5216270Slayer 		argv++, argc--;
5316242Slayer 	}
5416270Slayer 
5516242Slayer 	modestring = argv[0];
5616242Slayer 
5716242Slayer 	um = umask(0);
5816242Slayer 	(void) newmode(0);
5916242Slayer 	for (i = 1; i < argc; i++) {
6016242Slayer 		p = argv[i];
6116594Sralph 		if (stat(p, &st) < 0) {
6216242Slayer 			fprintf(stderr, "chmod: can't access %s\n", p);
6316242Slayer 			++status;
6416242Slayer 			continue;
6516242Slayer 		}
6616242Slayer 		if (rflag && st.st_mode & S_IFDIR) {
6716242Slayer 			status += chmodr(p, newmode(st.st_mode));
6816242Slayer 		} else if (chmod(p, newmode(st.st_mode)) < 0) {
6916242Slayer 			fprintf(stderr, "chmod: can't change %s\n", p);
7016242Slayer 			++status;
7116242Slayer 			continue;
7216242Slayer 		}
7316242Slayer 	}
7416242Slayer 	exit(status);
7516242Slayer }
7616242Slayer 
7716242Slayer chmodr(dir, mode)
7816242Slayer 	char	*dir;
7916242Slayer {
8016242Slayer 	register DIR		*dirp;
8116242Slayer 	register struct direct	*dp;
8216242Slayer 	register struct stat	st;
8316242Slayer 	char			savedir[1024];
8416242Slayer 
8516242Slayer 	if (getwd(savedir) == 0) {
8616242Slayer 		fprintf(stderr, "chmod: %s\n", savedir);
8716242Slayer 		exit(255);
8816242Slayer 	}
8916242Slayer 
9016242Slayer 	/*
9116242Slayer 	** chmod what we are given before doing it's contents
9216242Slayer 	*/
9316242Slayer 	chmod(dir, newmode(mode));
9416242Slayer 
9516242Slayer 	chdir(dir);
9616242Slayer 	if ((dirp = opendir(".")) == NULL) {
9716242Slayer 		perror(dir);
9816242Slayer 		return(1);
9916242Slayer 	}
10016242Slayer 	dp = readdir(dirp);
10116242Slayer 	dp = readdir(dirp); /* read "." and ".." */
10216242Slayer 	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
103*18473Smckusick 		if (stat(dp->d_name, &st) < 0) {
104*18473Smckusick 			fprintf(stderr, "chmod: can't access %s\n", dp->d_name);
105*18473Smckusick 			return(1);
106*18473Smckusick 		}
10716242Slayer 		chmod(dp->d_name, newmode(st.st_mode));
10816242Slayer 		if (st.st_mode & S_IFDIR)
10916242Slayer 			chmodr(dp->d_name, mode);
11016242Slayer 	}
11116242Slayer 	closedir(dirp);
11216242Slayer 	chdir(savedir);
11316242Slayer 	return(0);
11416242Slayer }
11516242Slayer 
11616242Slayer newmode(nm)
11716242Slayer unsigned nm;
11816242Slayer {
11916242Slayer 	register o, m, b;
12016242Slayer 	int savem;
12116242Slayer 
12216242Slayer 	ms = modestring;
12316242Slayer 	savem = nm;
12416242Slayer 	m = abs();
125*18473Smckusick 	if (!*ms)
126*18473Smckusick 		return(m);
12716242Slayer 	do {
12816242Slayer 		m = who();
12916242Slayer 		while (o = what()) {
13016242Slayer 			b = where(nm);
13116242Slayer 			switch (o) {
13216242Slayer 			case '+':
13316242Slayer 				nm |= b & m;
13416242Slayer 				break;
13516242Slayer 			case '-':
13616242Slayer 				nm &= ~(b & m);
13716242Slayer 				break;
13816242Slayer 			case '=':
13916242Slayer 				nm &= ~m;
14016242Slayer 				nm |= b & m;
14116242Slayer 				break;
14216242Slayer 			}
14316242Slayer 		}
14416242Slayer 	} while (*ms++ == ',');
14516242Slayer 	if (*--ms) {
14616242Slayer 		fprintf(stderr, "chmod: invalid mode\n");
14716242Slayer 		exit(255);
14816242Slayer 	}
14916242Slayer 	return(nm);
15016242Slayer }
15116242Slayer 
15216242Slayer abs()
15316242Slayer {
15416242Slayer 	register c, i;
15516242Slayer 
15616242Slayer 	i = 0;
15716242Slayer 	while ((c = *ms++) >= '0' && c <= '7')
15816242Slayer 		i = (i << 3) + (c - '0');
15916242Slayer 	ms--;
16016242Slayer 	return(i);
16116242Slayer }
16216242Slayer 
16316242Slayer who()
16416242Slayer {
16516242Slayer 	register m;
16616242Slayer 
16716242Slayer 	m = 0;
16816242Slayer 	for (;;) switch (*ms++) {
16916242Slayer 	case 'u':
17016242Slayer 		m |= USER;
17116242Slayer 		continue;
17216242Slayer 	case 'g':
17316242Slayer 		m |= GROUP;
17416242Slayer 		continue;
17516242Slayer 	case 'o':
17616242Slayer 		m |= OTHER;
17716242Slayer 		continue;
17816242Slayer 	case 'a':
17916242Slayer 		m |= ALL;
18016242Slayer 		continue;
18116242Slayer 	default:
18216242Slayer 		ms--;
18316242Slayer 		if (m == 0)
18416242Slayer 			m = ALL & ~um;
18516242Slayer 		return m;
18616242Slayer 	}
18716242Slayer }
18816242Slayer 
18916242Slayer what()
19016242Slayer {
19116242Slayer 
19216242Slayer 	switch (*ms) {
19316242Slayer 	case '+':
19416242Slayer 	case '-':
19516242Slayer 	case '=':
19616242Slayer 		return *ms++;
19716242Slayer 	}
19816242Slayer 	return(0);
19916242Slayer }
20016242Slayer 
20116242Slayer where(om)
20216242Slayer register om;
20316242Slayer {
20416242Slayer 	register m;
20516242Slayer 
20616242Slayer  	m = 0;
20716242Slayer 	switch (*ms) {
20816242Slayer 	case 'u':
20916242Slayer 		m = (om & USER) >> 6;
21016242Slayer 		goto dup;
21116242Slayer 	case 'g':
21216242Slayer 		m = (om & GROUP) >> 3;
21316242Slayer 		goto dup;
21416242Slayer 	case 'o':
21516242Slayer 		m = (om & OTHER);
21616242Slayer 	dup:
21716242Slayer 		m &= (READ|WRITE|EXEC);
21816242Slayer 		m |= (m << 3) | (m << 6);
21916242Slayer 		++ms;
22016242Slayer 		return m;
22116242Slayer 	}
22216242Slayer 	for (;;) switch (*ms++) {
22316242Slayer 	case 'r':
22416242Slayer 		m |= READ;
22516242Slayer 		continue;
22616242Slayer 	case 'w':
22716242Slayer 		m |= WRITE;
22816242Slayer 		continue;
22916242Slayer 	case 'x':
23016242Slayer 		m |= EXEC;
23116242Slayer 		continue;
23216594Sralph 	case 'X':
233*18473Smckusick 		if ((om & S_IFDIR) || (om & EXEC))
234*18473Smckusick 			m |= EXEC;
23516594Sralph 		continue;
23616242Slayer 	case 's':
23716242Slayer 		m |= SETID;
23816242Slayer 		continue;
23916242Slayer 	case 't':
24016242Slayer 		m |= STICKY;
24116242Slayer 		continue;
24216242Slayer 	default:
24316242Slayer 		ms--;
24416242Slayer 		return m;
24516242Slayer 	}
24616242Slayer }
247