xref: /csrg-svn/bin/chmod/chmod.c (revision 19840)
1*19840Sdist /*
2*19840Sdist  * Copyright (c) 1980 Regents of the University of California.
3*19840Sdist  * All rights reserved.  The Berkeley software License Agreement
4*19840Sdist  * specifies the terms and conditions for redistribution.
5*19840Sdist  */
616242Slayer 
7*19840Sdist #ifndef lint
8*19840Sdist static char sccsid[] = "@(#)chmod.c	5.1 (Berkeley) 04/30/85";
9*19840Sdist #endif not lint
10*19840Sdist 
1116242Slayer /*
1216242Slayer  * chmod options mode files
1316242Slayer  * where
1418473Smckusick  *	mode	is [ugoa][+-=][rwxXstugo] or a octal number
1516242Slayer  *	options are -R
1616242Slayer  */
1716242Slayer #include <stdio.h>
1816242Slayer #include <sys/types.h>
1916242Slayer #include <sys/stat.h>
2016242Slayer #include <sys/dir.h>
2116242Slayer 
2216242Slayer #define	USER	05700	/* user's bits */
2316242Slayer #define	GROUP	02070	/* group's bits */
2416242Slayer #define	OTHER	00007	/* other's bits */
2516242Slayer #define	ALL	01777	/* all (note absence of setuid, etc) */
2616242Slayer 
2716242Slayer #define	READ	00444	/* read permit */
2816242Slayer #define	WRITE	00222	/* write permit */
2916242Slayer #define	EXEC	00111	/* exec permit */
3016242Slayer #define	SETID	06000	/* set[ug]id */
3116242Slayer #define	STICKY	01000	/* sticky bit */
3216242Slayer 
3316242Slayer char	*modestring, *ms;
3416242Slayer int	um;
3516242Slayer int	status;
3618473Smckusick int	rflag, debug;
3716242Slayer 
3816242Slayer main(argc,argv)
3916242Slayer char **argv;
4016242Slayer {
4116242Slayer 	register i;
4216270Slayer 	register char *p, *flags;
4316242Slayer 	struct	stat st;
4416242Slayer 
4518473Smckusick usage:
4616242Slayer 	if (argc < 3) {
4716242Slayer 		fprintf(stderr
4818473Smckusick 			,"Usage: chmod [-R] [ugoa][+-=][rwxXstugo] file ...\n");
4916242Slayer 		exit(-1);
5016242Slayer 	}
5116270Slayer 
5216242Slayer 	argv++, --argc;
5316270Slayer 	if (*argv[0] == '-') {
5416270Slayer 		for (flags = argv[0]; *flags; ++flags)
5516270Slayer 			switch (*flags) {
5616270Slayer 			  case '-':			break;
5716270Slayer 			  case 'R':	rflag++;	break;
5818473Smckusick 			  default: 	argc = 0;	goto usage;
5916270Slayer 			}
6016270Slayer 		argv++, argc--;
6116242Slayer 	}
6216270Slayer 
6316242Slayer 	modestring = argv[0];
6416242Slayer 
6516242Slayer 	um = umask(0);
6616242Slayer 	(void) newmode(0);
6716242Slayer 	for (i = 1; i < argc; i++) {
6816242Slayer 		p = argv[i];
6916594Sralph 		if (stat(p, &st) < 0) {
7016242Slayer 			fprintf(stderr, "chmod: can't access %s\n", p);
7116242Slayer 			++status;
7216242Slayer 			continue;
7316242Slayer 		}
7416242Slayer 		if (rflag && st.st_mode & S_IFDIR) {
7516242Slayer 			status += chmodr(p, newmode(st.st_mode));
7616242Slayer 		} else if (chmod(p, newmode(st.st_mode)) < 0) {
7716242Slayer 			fprintf(stderr, "chmod: can't change %s\n", p);
7816242Slayer 			++status;
7916242Slayer 			continue;
8016242Slayer 		}
8116242Slayer 	}
8216242Slayer 	exit(status);
8316242Slayer }
8416242Slayer 
8516242Slayer chmodr(dir, mode)
8616242Slayer 	char	*dir;
8716242Slayer {
8816242Slayer 	register DIR		*dirp;
8916242Slayer 	register struct direct	*dp;
9016242Slayer 	register struct stat	st;
9116242Slayer 	char			savedir[1024];
9216242Slayer 
9316242Slayer 	if (getwd(savedir) == 0) {
9416242Slayer 		fprintf(stderr, "chmod: %s\n", savedir);
9516242Slayer 		exit(255);
9616242Slayer 	}
9716242Slayer 
9816242Slayer 	/*
9916242Slayer 	** chmod what we are given before doing it's contents
10016242Slayer 	*/
10116242Slayer 	chmod(dir, newmode(mode));
10216242Slayer 
10316242Slayer 	chdir(dir);
10416242Slayer 	if ((dirp = opendir(".")) == NULL) {
10516242Slayer 		perror(dir);
10616242Slayer 		return(1);
10716242Slayer 	}
10816242Slayer 	dp = readdir(dirp);
10916242Slayer 	dp = readdir(dirp); /* read "." and ".." */
11016242Slayer 	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
11118473Smckusick 		if (stat(dp->d_name, &st) < 0) {
11218473Smckusick 			fprintf(stderr, "chmod: can't access %s\n", dp->d_name);
11318473Smckusick 			return(1);
11418473Smckusick 		}
11516242Slayer 		chmod(dp->d_name, newmode(st.st_mode));
11616242Slayer 		if (st.st_mode & S_IFDIR)
11716242Slayer 			chmodr(dp->d_name, mode);
11816242Slayer 	}
11916242Slayer 	closedir(dirp);
12016242Slayer 	chdir(savedir);
12116242Slayer 	return(0);
12216242Slayer }
12316242Slayer 
12416242Slayer newmode(nm)
12516242Slayer unsigned nm;
12616242Slayer {
12716242Slayer 	register o, m, b;
12816242Slayer 	int savem;
12916242Slayer 
13016242Slayer 	ms = modestring;
13116242Slayer 	savem = nm;
13216242Slayer 	m = abs();
13318473Smckusick 	if (!*ms)
13418473Smckusick 		return(m);
13516242Slayer 	do {
13616242Slayer 		m = who();
13716242Slayer 		while (o = what()) {
13816242Slayer 			b = where(nm);
13916242Slayer 			switch (o) {
14016242Slayer 			case '+':
14116242Slayer 				nm |= b & m;
14216242Slayer 				break;
14316242Slayer 			case '-':
14416242Slayer 				nm &= ~(b & m);
14516242Slayer 				break;
14616242Slayer 			case '=':
14716242Slayer 				nm &= ~m;
14816242Slayer 				nm |= b & m;
14916242Slayer 				break;
15016242Slayer 			}
15116242Slayer 		}
15216242Slayer 	} while (*ms++ == ',');
15316242Slayer 	if (*--ms) {
15416242Slayer 		fprintf(stderr, "chmod: invalid mode\n");
15516242Slayer 		exit(255);
15616242Slayer 	}
15716242Slayer 	return(nm);
15816242Slayer }
15916242Slayer 
16016242Slayer abs()
16116242Slayer {
16216242Slayer 	register c, i;
16316242Slayer 
16416242Slayer 	i = 0;
16516242Slayer 	while ((c = *ms++) >= '0' && c <= '7')
16616242Slayer 		i = (i << 3) + (c - '0');
16716242Slayer 	ms--;
16816242Slayer 	return(i);
16916242Slayer }
17016242Slayer 
17116242Slayer who()
17216242Slayer {
17316242Slayer 	register m;
17416242Slayer 
17516242Slayer 	m = 0;
17616242Slayer 	for (;;) switch (*ms++) {
17716242Slayer 	case 'u':
17816242Slayer 		m |= USER;
17916242Slayer 		continue;
18016242Slayer 	case 'g':
18116242Slayer 		m |= GROUP;
18216242Slayer 		continue;
18316242Slayer 	case 'o':
18416242Slayer 		m |= OTHER;
18516242Slayer 		continue;
18616242Slayer 	case 'a':
18716242Slayer 		m |= ALL;
18816242Slayer 		continue;
18916242Slayer 	default:
19016242Slayer 		ms--;
19116242Slayer 		if (m == 0)
19216242Slayer 			m = ALL & ~um;
19316242Slayer 		return m;
19416242Slayer 	}
19516242Slayer }
19616242Slayer 
19716242Slayer what()
19816242Slayer {
19916242Slayer 
20016242Slayer 	switch (*ms) {
20116242Slayer 	case '+':
20216242Slayer 	case '-':
20316242Slayer 	case '=':
20416242Slayer 		return *ms++;
20516242Slayer 	}
20616242Slayer 	return(0);
20716242Slayer }
20816242Slayer 
20916242Slayer where(om)
21016242Slayer register om;
21116242Slayer {
21216242Slayer 	register m;
21316242Slayer 
21416242Slayer  	m = 0;
21516242Slayer 	switch (*ms) {
21616242Slayer 	case 'u':
21716242Slayer 		m = (om & USER) >> 6;
21816242Slayer 		goto dup;
21916242Slayer 	case 'g':
22016242Slayer 		m = (om & GROUP) >> 3;
22116242Slayer 		goto dup;
22216242Slayer 	case 'o':
22316242Slayer 		m = (om & OTHER);
22416242Slayer 	dup:
22516242Slayer 		m &= (READ|WRITE|EXEC);
22616242Slayer 		m |= (m << 3) | (m << 6);
22716242Slayer 		++ms;
22816242Slayer 		return m;
22916242Slayer 	}
23016242Slayer 	for (;;) switch (*ms++) {
23116242Slayer 	case 'r':
23216242Slayer 		m |= READ;
23316242Slayer 		continue;
23416242Slayer 	case 'w':
23516242Slayer 		m |= WRITE;
23616242Slayer 		continue;
23716242Slayer 	case 'x':
23816242Slayer 		m |= EXEC;
23916242Slayer 		continue;
24016594Sralph 	case 'X':
24118473Smckusick 		if ((om & S_IFDIR) || (om & EXEC))
24218473Smckusick 			m |= EXEC;
24316594Sralph 		continue;
24416242Slayer 	case 's':
24516242Slayer 		m |= SETID;
24616242Slayer 		continue;
24716242Slayer 	case 't':
24816242Slayer 		m |= STICKY;
24916242Slayer 		continue;
25016242Slayer 	default:
25116242Slayer 		ms--;
25216242Slayer 		return m;
25316242Slayer 	}
25416242Slayer }
255