xref: /csrg-svn/bin/chmod/chmod.c (revision 34043)
119840Sdist /*
2*34043Sbostic  * Copyright (c) 1980, 1988 Regents of the University of California.
319840Sdist  * All rights reserved.  The Berkeley software License Agreement
419840Sdist  * specifies the terms and conditions for redistribution.
519840Sdist  */
616242Slayer 
719840Sdist #ifndef lint
8*34043Sbostic char copyright[] =
9*34043Sbostic "@(#) Copyright (c) 1980, 1988 Regents of the University of California.\n\
10*34043Sbostic  All rights reserved.\n";
11*34043Sbostic #endif /* not lint */
1219840Sdist 
13*34043Sbostic #ifndef lint
14*34043Sbostic static char sccsid[] = "@(#)chmod.c	5.7 (Berkeley) 04/21/88";
15*34043Sbostic #endif /* not lint */
16*34043Sbostic 
1716242Slayer /*
1816242Slayer  * chmod options mode files
1916242Slayer  * where
2024503Ssam  *	mode is [ugoa][+-=][rwxXstugo] or an octal number
2124503Ssam  *	options are -Rf
2216242Slayer  */
2316242Slayer #include <stdio.h>
2416242Slayer #include <sys/types.h>
2516242Slayer #include <sys/stat.h>
2616242Slayer #include <sys/dir.h>
2716242Slayer 
28*34043Sbostic static int	fflag, rflag, retval, um;
29*34043Sbostic static char	*modestring, *ms;
3016242Slayer 
3124503Ssam main(argc, argv)
32*34043Sbostic 	int argc;
33*34043Sbostic 	char **argv;
3416242Slayer {
35*34043Sbostic 	extern char *optarg;
36*34043Sbostic 	extern int optind, opterr;
37*34043Sbostic 	int ch;
3816242Slayer 
39*34043Sbostic 	/*
40*34043Sbostic 	 * since "-[rwx]" etc. are valid file modes, we don't let getopt(3)
41*34043Sbostic 	 * print error messages, and we mess around with optind as necessary.
42*34043Sbostic 	 */
43*34043Sbostic 	opterr = 0;
44*34043Sbostic 	while ((ch = getopt(argc, argv, "Rf")) != EOF)
45*34043Sbostic 		switch((char)ch) {
4624503Ssam 		case 'R':
4723482Smckusick 			rflag++;
4824503Ssam 			break;
4924503Ssam 		case 'f':
5024503Ssam 			fflag++;
5124503Ssam 			break;
52*34043Sbostic 		case '?':
5324503Ssam 		default:
54*34043Sbostic 			--optind;
5524503Ssam 			goto done;
5623482Smckusick 		}
57*34043Sbostic done:	argv += optind;
58*34043Sbostic 	argc -= optind;
59*34043Sbostic 
60*34043Sbostic 	if (argc < 2) {
61*34043Sbostic 		fputs("usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n",
62*34043Sbostic 		    stderr);
63*34043Sbostic 		exit(-1);
6416242Slayer 	}
65*34043Sbostic 
66*34043Sbostic 	modestring = *argv;
6716242Slayer 	um = umask(0);
68*34043Sbostic 	(void)newmode((u_short)0);
69*34043Sbostic 
70*34043Sbostic 	while (*++argv)
71*34043Sbostic 		change(*argv);
72*34043Sbostic 	exit(retval);
7316242Slayer }
7416242Slayer 
75*34043Sbostic change(file)
76*34043Sbostic 	char *file;
7716242Slayer {
7824503Ssam 	register DIR *dirp;
7924503Ssam 	register struct direct *dp;
80*34043Sbostic 	struct stat buf;
8116242Slayer 
82*34043Sbostic 	if (lstat(file, &buf) || chmod(file, newmode(buf.st_mode))) {
83*34043Sbostic 		err(file);
84*34043Sbostic 		return;
8528353Smckusick 	}
86*34043Sbostic 	if (rflag && ((buf.st_mode & S_IFMT) == S_IFDIR)) {
87*34043Sbostic 		if (chdir(file) < 0 || !(dirp = opendir("."))) {
88*34043Sbostic 			err(file);
89*34043Sbostic 			return;
9018473Smckusick 		}
91*34043Sbostic 		for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
92*34043Sbostic 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
93*34043Sbostic 			    dp->d_name[1] == '.' && !dp->d_name[2]))
94*34043Sbostic 				continue;
95*34043Sbostic 			change(dp->d_name);
9624503Ssam 		}
97*34043Sbostic 		closedir(dirp);
98*34043Sbostic 		if (chdir("..")) {
99*34043Sbostic 			err("..");
100*34043Sbostic 			exit(fflag ? 0 : -1);
101*34043Sbostic 		}
10216242Slayer 	}
10316242Slayer }
10416242Slayer 
105*34043Sbostic err(s)
10624503Ssam 	char *s;
10724503Ssam {
108*34043Sbostic 	if (fflag)
109*34043Sbostic 		return;
110*34043Sbostic 	fputs("chmod: ", stderr);
111*34043Sbostic 	perror(s);
112*34043Sbostic 	retval = -1;
11324503Ssam }
11424503Ssam 
11516242Slayer newmode(nm)
116*34043Sbostic 	u_short nm;
11716242Slayer {
118*34043Sbostic 	register int o, m, b;
11916242Slayer 
12016242Slayer 	ms = modestring;
12116242Slayer 	m = abs();
12224503Ssam 	if (*ms == '\0')
12324503Ssam 		return (m);
12416242Slayer 	do {
12516242Slayer 		m = who();
12616242Slayer 		while (o = what()) {
127*34043Sbostic 			b = where((int)nm);
12816242Slayer 			switch (o) {
12916242Slayer 			case '+':
13016242Slayer 				nm |= b & m;
13116242Slayer 				break;
13216242Slayer 			case '-':
13316242Slayer 				nm &= ~(b & m);
13416242Slayer 				break;
13516242Slayer 			case '=':
13616242Slayer 				nm &= ~m;
13716242Slayer 				nm |= b & m;
13816242Slayer 				break;
13916242Slayer 			}
14016242Slayer 		}
14116242Slayer 	} while (*ms++ == ',');
142*34043Sbostic 	if (*--ms) {
143*34043Sbostic 		fputs("chmod: invalid mode.\n", stderr);
144*34043Sbostic 		exit(-1);
145*34043Sbostic 	}
146*34043Sbostic 	return ((int)nm);
14716242Slayer }
14816242Slayer 
14916242Slayer abs()
15016242Slayer {
151*34043Sbostic 	register int c, i;
15216242Slayer 
15316242Slayer 	i = 0;
15416242Slayer 	while ((c = *ms++) >= '0' && c <= '7')
15516242Slayer 		i = (i << 3) + (c - '0');
15616242Slayer 	ms--;
15724503Ssam 	return (i);
15816242Slayer }
15916242Slayer 
16024503Ssam #define	USER	05700	/* user's bits */
16124503Ssam #define	GROUP	02070	/* group's bits */
16224503Ssam #define	OTHER	00007	/* other's bits */
16324503Ssam #define	ALL	01777	/* all (note absence of setuid, etc) */
16424503Ssam 
16524503Ssam #define	READ	00444	/* read permit */
16624503Ssam #define	WRITE	00222	/* write permit */
16724503Ssam #define	EXEC	00111	/* exec permit */
16824503Ssam #define	SETID	06000	/* set[ug]id */
16924503Ssam #define	STICKY	01000	/* sticky bit */
17024503Ssam 
17116242Slayer who()
17216242Slayer {
173*34043Sbostic 	register int 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;
19324503Ssam 		return (m);
19416242Slayer 	}
19516242Slayer }
19616242Slayer 
19716242Slayer what()
19816242Slayer {
19916242Slayer 	switch (*ms) {
20016242Slayer 	case '+':
20116242Slayer 	case '-':
20216242Slayer 	case '=':
20324503Ssam 		return (*ms++);
20416242Slayer 	}
20524503Ssam 	return (0);
20616242Slayer }
20716242Slayer 
20816242Slayer where(om)
209*34043Sbostic 	register int om;
21016242Slayer {
211*34043Sbostic 	register int 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;
22724503Ssam 		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;
23916594Sralph 	case 'X':
24018473Smckusick 		if ((om & S_IFDIR) || (om & EXEC))
24118473Smckusick 			m |= EXEC;
24216594Sralph 		continue;
24316242Slayer 	case 's':
24416242Slayer 		m |= SETID;
24516242Slayer 		continue;
24616242Slayer 	case 't':
24716242Slayer 		m |= STICKY;
24816242Slayer 		continue;
24916242Slayer 	default:
25016242Slayer 		ms--;
25124503Ssam 		return (m);
25216242Slayer 	}
25316242Slayer }
254