xref: /csrg-svn/bin/chmod/chmod.c (revision 66600)
119840Sdist /*
266445Sbostic  * Copyright (c) 1989, 1993, 1994
363597Sbostic  *	The Regents of the University of California.  All rights reserved.
439829Sbostic  *
542527Sbostic  * %sccs.include.redist.c%
619840Sdist  */
716242Slayer 
819840Sdist #ifndef lint
963597Sbostic static char copyright[] =
1066445Sbostic "@(#) Copyright (c) 1989, 1993, 1994\n\
1163597Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1234043Sbostic #endif /* not lint */
1319840Sdist 
1434043Sbostic #ifndef lint
15*66600Sbostic static char sccsid[] = "@(#)chmod.c	8.8 (Berkeley) 04/01/94";
1634043Sbostic #endif /* not lint */
1734043Sbostic 
1816242Slayer #include <sys/types.h>
1916242Slayer #include <sys/stat.h>
2058142Sbostic 
2158142Sbostic #include <err.h>
2252070Sbostic #include <errno.h>
2339829Sbostic #include <fts.h>
2439829Sbostic #include <stdio.h>
2552070Sbostic #include <stdlib.h>
2642010Sbostic #include <string.h>
2758142Sbostic #include <unistd.h>
2816242Slayer 
2952070Sbostic void usage __P((void));
3052070Sbostic 
3152070Sbostic int
main(argc,argv)3224503Ssam main(argc, argv)
3334043Sbostic 	int argc;
3452070Sbostic 	char *argv[];
3516242Slayer {
3666544Sbostic 	FTS *ftsp;
3766544Sbostic 	FTSENT *p;
3852070Sbostic 	mode_t *set;
3966544Sbostic 	long val;
4066544Sbostic 	int oct, omode;
4166543Sbostic 	int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval;
4252070Sbostic 	char *ep, *mode;
4316242Slayer 
4466543Sbostic 	Hflag = Lflag = Pflag = Rflag = fflag = hflag = 0;
4566543Sbostic 	while ((ch = getopt(argc, argv, "HLPRXfgorstuwx")) != EOF)
4666445Sbostic 		switch (ch) {
4753782Selan 		case 'H':
4853782Selan 			Hflag = 1;
4966543Sbostic 			Lflag = Pflag = 0;
5053782Selan 			break;
5166543Sbostic 		case 'L':
5266543Sbostic 			Lflag = 1;
5366543Sbostic 			Hflag = Pflag = 0;
5466543Sbostic 			break;
5566543Sbostic 		case 'P':
5666543Sbostic 			Pflag = 1;
5766543Sbostic 			Hflag = Lflag = 0;
5866543Sbostic 			break;
5924503Ssam 		case 'R':
6066543Sbostic 			Rflag = 1;
6124503Ssam 			break;
6266543Sbostic 		case 'f':		/* XXX: undocumented. */
6347072Sbostic 			fflag = 1;
6424503Ssam 			break;
6553782Selan 		case 'h':
6666543Sbostic 			/*
6766543Sbostic 			 * In System V (and probably POSIX.2) the -h option
6866543Sbostic 			 * causes chmod to change the mode of the symbolic
6966543Sbostic 			 * link.  4.4BSD's symbolic links don't have modes,
7066543Sbostic 			 * so it's an undocumented noop.  Do syntax checking,
7166543Sbostic 			 * though.
7266543Sbostic 			 */
7353782Selan 			hflag = 1;
7453782Selan 			break;
7565163Sbostic 		/*
7666445Sbostic 		 * XXX
7765163Sbostic 		 * "-[rwx]" are valid mode commands.  If they are the entire
7865163Sbostic 		 * argument, getopt has moved past them, so decrement optind.
7965163Sbostic 		 * Regardless, we're done argument processing.
8065163Sbostic 		 */
8166445Sbostic 		case 'g': case 'o': case 'r': case 's':
8266445Sbostic 		case 't': case 'u': case 'w': case 'X': case 'x':
8366445Sbostic 			if (argv[optind - 1][0] == '-' &&
8466445Sbostic 			    argv[optind - 1][1] == ch &&
8566445Sbostic 			    argv[optind - 1][2] == '\0')
8665163Sbostic 				--optind;
8765163Sbostic 			goto done;
8834043Sbostic 		case '?':
8924503Ssam 		default:
9039829Sbostic 			usage();
9123482Smckusick 		}
9234043Sbostic done:	argv += optind;
9334043Sbostic 	argc -= optind;
9434043Sbostic 
9539829Sbostic 	if (argc < 2)
9639829Sbostic 		usage();
9739829Sbostic 
9866543Sbostic 	fts_options = FTS_PHYSICAL;
9966543Sbostic 	if (Rflag) {
10066543Sbostic 		if (hflag)
10166543Sbostic 			errx(1,
10266543Sbostic 		"the -R and -h options may not be specified together.");
10366543Sbostic 		if (Hflag)
10466543Sbostic 			fts_options |= FTS_COMFOLLOW;
10566543Sbostic 		if (Lflag) {
10666543Sbostic 			fts_options &= ~FTS_PHYSICAL;
10766543Sbostic 			fts_options |= FTS_LOGICAL;
10866543Sbostic 		}
10966543Sbostic 	}
11066543Sbostic 
11139829Sbostic 	mode = *argv;
11239829Sbostic 	if (*mode >= '0' && *mode <= '7') {
11366544Sbostic 		errno = 0;
11466544Sbostic 		val = strtol(mode, &ep, 8);
11566544Sbostic 		if (val > INT_MAX || val < 0)
11666544Sbostic 			errno = ERANGE;
11766544Sbostic 		if (errno)
11866544Sbostic 			err(1, "invalid file mode: %s", mode);
11966544Sbostic 		if (*ep)
12058142Sbostic 			errx(1, "invalid file mode: %s", mode);
12166544Sbostic 		omode = val;
12239829Sbostic 		oct = 1;
12339829Sbostic 	} else {
12458142Sbostic 		if ((set = setmode(mode)) == NULL)
12558142Sbostic 			errx(1, "invalid file mode: %s", mode);
12639829Sbostic 		oct = 0;
12716242Slayer 	}
12834043Sbostic 
12953782Selan 	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
13066543Sbostic 		err(1, NULL);
13166543Sbostic 	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
13266445Sbostic 		switch (p->fts_info) {
13353782Selan 		case FTS_D:
13466543Sbostic 			if (Rflag)		/* Change it at FTS_DP. */
13566543Sbostic 				continue;
13666543Sbostic 			fts_set(ftsp, p, FTS_SKIP);
13753782Selan 			break;
13866543Sbostic 		case FTS_DNR:			/* Warn, chmod, continue. */
139*66600Sbostic 			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
14066543Sbostic 			rval = 1;
14166543Sbostic 			break;
14266543Sbostic 		case FTS_ERR:			/* Warn, continue. */
14353782Selan 		case FTS_NS:
144*66600Sbostic 			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
14566543Sbostic 			rval = 1;
14666543Sbostic 			continue;
14766543Sbostic 		case FTS_SL:			/* Ignore. */
14866543Sbostic 		case FTS_SLNONE:
14966543Sbostic 			/*
15066543Sbostic 			 * The only symlinks that end up here are ones that
15166543Sbostic 			 * don't point to anything and ones that we found
15266543Sbostic 			 * doing a physical walk.
15366543Sbostic 			 */
15466543Sbostic 			continue;
15566543Sbostic 		default:
15653782Selan 			break;
15753782Selan 		}
15866543Sbostic 		if (chmod(p->fts_accpath, oct ? omode :
15966543Sbostic 		    getmode(set, p->fts_statp->st_mode)) && !fflag) {
16066543Sbostic 			warn(p->fts_path);
16166543Sbostic 			rval = 1;
16266543Sbostic 		}
16366543Sbostic 	}
16466549Sbostic 	if (errno)
16566549Sbostic 		err(1, "fts_read");
16666543Sbostic 	exit(rval);
16716242Slayer }
16816242Slayer 
16952070Sbostic void
usage()17039829Sbostic usage()
17116242Slayer {
17266543Sbostic 	(void)fprintf(stderr,
17366543Sbostic 	    "usage: chmod [-R [-H | -L | -P]] mode file ...\n");
17439829Sbostic 	exit(1);
17516242Slayer }
176