xref: /csrg-svn/bin/chmod/chmod.c (revision 16594)
1*16594Sralph static char *sccsid = "@(#)chmod.c	4.4 06/18/84";
216242Slayer 
316242Slayer /*
416242Slayer  * chmod options mode files
516242Slayer  * where
616242Slayer  *	mode	is [ugoa][+-=][rwxstugo] 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;
2816270Slayer int	rflag, debug, Xflag;
2916242Slayer 
3016242Slayer main(argc,argv)
3116242Slayer char **argv;
3216242Slayer {
3316242Slayer 	register i;
3416270Slayer 	register char *p, *flags;
3516242Slayer 	struct	stat st;
3616242Slayer 
3716242Slayer 	if (argc < 3) {
3816242Slayer 		fprintf(stderr
3916270Slayer 			,"Usage: chmod [-RX] [ugoa][+-=][rwxstugo] file ...\n");
4016242Slayer 		exit(-1);
4116242Slayer 	}
4216270Slayer 
4316242Slayer 	argv++, --argc;
4416270Slayer 	if (*argv[0] == '-') {
4516270Slayer 		for (flags = argv[0]; *flags; ++flags)
4616270Slayer 			switch (*flags) {
4716270Slayer 			  case '-':			break;
4816270Slayer 			  case 'R':	rflag++;	break;
4916270Slayer 			  case 'X': 	Xflag++;	break;
5016270Slayer 			}
5116270Slayer 		argv++, argc--;
5216242Slayer 	}
5316270Slayer 
5416242Slayer 	modestring = argv[0];
5516242Slayer 
5616242Slayer 	um = umask(0);
5716242Slayer 	(void) newmode(0);
5816242Slayer 	for (i = 1; i < argc; i++) {
5916242Slayer 		p = argv[i];
60*16594Sralph 		if (stat(p, &st) < 0) {
6116242Slayer 			fprintf(stderr, "chmod: can't access %s\n", p);
6216242Slayer 			++status;
6316242Slayer 			continue;
6416242Slayer 		}
6516242Slayer 		if (rflag && st.st_mode & S_IFDIR) {
6616242Slayer 			status += chmodr(p, newmode(st.st_mode));
6716242Slayer 		} else if (chmod(p, newmode(st.st_mode)) < 0) {
6816242Slayer 			fprintf(stderr, "chmod: can't change %s\n", p);
6916242Slayer 			++status;
7016242Slayer 			continue;
7116242Slayer 		}
7216242Slayer 	}
7316242Slayer 	exit(status);
7416242Slayer }
7516242Slayer 
7616242Slayer chmodr(dir, mode)
7716242Slayer 	char	*dir;
7816242Slayer {
7916242Slayer #define CHECK(name,sbuf)\
80*16594Sralph 	if (stat(name, sbuf) < 0) {\
8116242Slayer 		fprintf(stderr, "chmod: can't access %s\n", dp->d_name);\
8216242Slayer 		return(1);\
8316242Slayer 	}
8416242Slayer 
8516242Slayer 	register DIR		*dirp;
8616242Slayer 	register struct direct	*dp;
8716242Slayer 	register struct stat	st;
8816242Slayer 	char			savedir[1024];
8916242Slayer 
9016242Slayer 	if (getwd(savedir) == 0) {
9116242Slayer 		fprintf(stderr, "chmod: %s\n", savedir);
9216242Slayer 		exit(255);
9316242Slayer 	}
9416242Slayer 
9516242Slayer 	/*
9616242Slayer 	** chmod what we are given before doing it's contents
9716242Slayer 	*/
9816242Slayer 	chmod(dir, newmode(mode));
9916242Slayer 
10016242Slayer 	chdir(dir);
10116242Slayer 	if ((dirp = opendir(".")) == NULL) {
10216242Slayer 		perror(dir);
10316242Slayer 		return(1);
10416242Slayer 	}
10516242Slayer 	dp = readdir(dirp);
10616242Slayer 	dp = readdir(dirp); /* read "." and ".." */
10716242Slayer 	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
10816242Slayer 		CHECK(dp->d_name, &st);
10916242Slayer 		chmod(dp->d_name, newmode(st.st_mode));
11016242Slayer 		if (st.st_mode & S_IFDIR)
11116242Slayer 			chmodr(dp->d_name, mode);
11216242Slayer 	}
11316242Slayer 	closedir(dirp);
11416242Slayer 	chdir(savedir);
11516242Slayer 	return(0);
11616242Slayer }
11716242Slayer 
11816242Slayer newmode(nm)
11916242Slayer unsigned nm;
12016242Slayer {
12116242Slayer 	register o, m, b;
12216242Slayer 	int savem;
12316242Slayer 
12416242Slayer 	ms = modestring;
12516242Slayer 	savem = nm;
12616242Slayer 	m = abs();
12716242Slayer 	if (!*ms) {
12816242Slayer 		nm = m;
12916242Slayer 		goto ret;
13016242Slayer 	}
13116242Slayer 	do {
13216242Slayer 		m = who();
13316242Slayer 		while (o = what()) {
13416242Slayer 			b = where(nm);
13516242Slayer 			switch (o) {
13616242Slayer 			case '+':
13716242Slayer 				nm |= b & m;
13816242Slayer 				break;
13916242Slayer 			case '-':
14016242Slayer 				nm &= ~(b & m);
14116242Slayer 				break;
14216242Slayer 			case '=':
14316242Slayer 				nm &= ~m;
14416242Slayer 				nm |= b & m;
14516242Slayer 				break;
14616242Slayer 			}
14716242Slayer 		}
14816242Slayer 	} while (*ms++ == ',');
14916242Slayer 	if (*--ms) {
15016242Slayer 		fprintf(stderr, "chmod: invalid mode\n");
15116242Slayer 		exit(255);
15216242Slayer 	}
15316242Slayer ret:
15416270Slayer 	if (Xflag && ((savem & S_IFDIR) || (savem & S_IEXEC)))
15516270Slayer 		nm = nm | ((nm & 0444) >> 2);
15616242Slayer 	return(nm);
15716242Slayer }
15816242Slayer 
15916242Slayer abs()
16016242Slayer {
16116242Slayer 	register c, i;
16216242Slayer 
16316242Slayer 	i = 0;
16416242Slayer 	while ((c = *ms++) >= '0' && c <= '7')
16516242Slayer 		i = (i << 3) + (c - '0');
16616242Slayer 	ms--;
16716242Slayer 	return(i);
16816242Slayer }
16916242Slayer 
17016242Slayer who()
17116242Slayer {
17216242Slayer 	register m;
17316242Slayer 
17416242Slayer 	m = 0;
17516242Slayer 	for (;;) switch (*ms++) {
17616242Slayer 	case 'u':
17716242Slayer 		m |= USER;
17816242Slayer 		continue;
17916242Slayer 	case 'g':
18016242Slayer 		m |= GROUP;
18116242Slayer 		continue;
18216242Slayer 	case 'o':
18316242Slayer 		m |= OTHER;
18416242Slayer 		continue;
18516242Slayer 	case 'a':
18616242Slayer 		m |= ALL;
18716242Slayer 		continue;
18816242Slayer 	default:
18916242Slayer 		ms--;
19016242Slayer 		if (m == 0)
19116242Slayer 			m = ALL & ~um;
19216242Slayer 		return m;
19316242Slayer 	}
19416242Slayer }
19516242Slayer 
19616242Slayer what()
19716242Slayer {
19816242Slayer 
19916242Slayer 	switch (*ms) {
20016242Slayer 	case '+':
20116242Slayer 	case '-':
20216242Slayer 	case '=':
20316242Slayer 		return *ms++;
20416242Slayer 	}
20516242Slayer 	return(0);
20616242Slayer }
20716242Slayer 
20816242Slayer where(om)
20916242Slayer register om;
21016242Slayer {
21116242Slayer 	register m;
21216242Slayer 
21316242Slayer  	m = 0;
21416242Slayer 	switch (*ms) {
21516242Slayer 	case 'u':
21616242Slayer 		m = (om & USER) >> 6;
21716242Slayer 		goto dup;
21816242Slayer 	case 'g':
21916242Slayer 		m = (om & GROUP) >> 3;
22016242Slayer 		goto dup;
22116242Slayer 	case 'o':
22216242Slayer 		m = (om & OTHER);
22316242Slayer 	dup:
22416242Slayer 		m &= (READ|WRITE|EXEC);
22516242Slayer 		m |= (m << 3) | (m << 6);
22616242Slayer 		++ms;
22716242Slayer 		return m;
22816242Slayer 	}
22916242Slayer 	for (;;) switch (*ms++) {
23016242Slayer 	case 'r':
23116242Slayer 		m |= READ;
23216242Slayer 		continue;
23316242Slayer 	case 'w':
23416242Slayer 		m |= WRITE;
23516242Slayer 		continue;
23616242Slayer 	case 'x':
23716242Slayer 		m |= EXEC;
23816242Slayer 		continue;
239*16594Sralph 	case 'X':
240*16594Sralph 		Xflag++;
241*16594Sralph 		continue;
24216242Slayer 	case 's':
24316242Slayer 		m |= SETID;
24416242Slayer 		continue;
24516242Slayer 	case 't':
24616242Slayer 		m |= STICKY;
24716242Slayer 		continue;
24816242Slayer 	default:
24916242Slayer 		ms--;
25016242Slayer 		return m;
25116242Slayer 	}
25216242Slayer }
253