xref: /csrg-svn/bin/chmod/chmod.c (revision 66543)
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*66543Sbostic static char sccsid[] = "@(#)chmod.c	8.4 (Berkeley) 03/31/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
3224503Ssam main(argc, argv)
3334043Sbostic 	int argc;
3452070Sbostic 	char *argv[];
3516242Slayer {
3653782Selan 	register FTS *ftsp;
3739829Sbostic 	register FTSENT *p;
3839829Sbostic 	register int oct, omode;
3952070Sbostic 	mode_t *set;
40*66543Sbostic 	int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval;
4152070Sbostic 	char *ep, *mode;
4216242Slayer 
43*66543Sbostic 	Hflag = Lflag = Pflag = Rflag = fflag = hflag = 0;
44*66543Sbostic 	while ((ch = getopt(argc, argv, "HLPRXfgorstuwx")) != EOF)
4566445Sbostic 		switch (ch) {
4653782Selan 		case 'H':
4753782Selan 			Hflag = 1;
48*66543Sbostic 			Lflag = Pflag = 0;
4953782Selan 			break;
50*66543Sbostic 		case 'L':
51*66543Sbostic 			Lflag = 1;
52*66543Sbostic 			Hflag = Pflag = 0;
53*66543Sbostic 			break;
54*66543Sbostic 		case 'P':
55*66543Sbostic 			Pflag = 1;
56*66543Sbostic 			Hflag = Lflag = 0;
57*66543Sbostic 			break;
5824503Ssam 		case 'R':
59*66543Sbostic 			Rflag = 1;
6024503Ssam 			break;
61*66543Sbostic 		case 'f':		/* XXX: undocumented. */
6247072Sbostic 			fflag = 1;
6324503Ssam 			break;
6453782Selan 		case 'h':
65*66543Sbostic 			/*
66*66543Sbostic 			 * In System V (and probably POSIX.2) the -h option
67*66543Sbostic 			 * causes chmod to change the mode of the symbolic
68*66543Sbostic 			 * link.  4.4BSD's symbolic links don't have modes,
69*66543Sbostic 			 * so it's an undocumented noop.  Do syntax checking,
70*66543Sbostic 			 * though.
71*66543Sbostic 			 */
7253782Selan 			hflag = 1;
7353782Selan 			break;
7465163Sbostic 		/*
7566445Sbostic 		 * XXX
7665163Sbostic 		 * "-[rwx]" are valid mode commands.  If they are the entire
7765163Sbostic 		 * argument, getopt has moved past them, so decrement optind.
7865163Sbostic 		 * Regardless, we're done argument processing.
7965163Sbostic 		 */
8066445Sbostic 		case 'g': case 'o': case 'r': case 's':
8166445Sbostic 		case 't': case 'u': case 'w': case 'X': case 'x':
8266445Sbostic 			if (argv[optind - 1][0] == '-' &&
8366445Sbostic 			    argv[optind - 1][1] == ch &&
8466445Sbostic 			    argv[optind - 1][2] == '\0')
8565163Sbostic 				--optind;
8665163Sbostic 			goto done;
8734043Sbostic 		case '?':
8824503Ssam 		default:
8939829Sbostic 			usage();
9023482Smckusick 		}
9134043Sbostic done:	argv += optind;
9234043Sbostic 	argc -= optind;
9334043Sbostic 
9439829Sbostic 	if (argc < 2)
9539829Sbostic 		usage();
9639829Sbostic 
97*66543Sbostic 	fts_options = FTS_PHYSICAL;
98*66543Sbostic 	if (Rflag) {
99*66543Sbostic 		if (hflag)
100*66543Sbostic 			errx(1,
101*66543Sbostic 		"the -R and -h options may not be specified together.");
102*66543Sbostic 		if (Hflag)
103*66543Sbostic 			fts_options |= FTS_COMFOLLOW;
104*66543Sbostic 		if (Lflag) {
105*66543Sbostic 			fts_options &= ~FTS_PHYSICAL;
106*66543Sbostic 			fts_options |= FTS_LOGICAL;
107*66543Sbostic 		}
108*66543Sbostic 	}
109*66543Sbostic 
11039829Sbostic 	mode = *argv;
11139829Sbostic 	if (*mode >= '0' && *mode <= '7') {
11252070Sbostic 		omode = (int)strtol(mode, &ep, 8);
11352070Sbostic 		if (omode < 0 || *ep)
11458142Sbostic 			errx(1, "invalid file mode: %s", mode);
11539829Sbostic 		oct = 1;
11639829Sbostic 	} else {
11758142Sbostic 		if ((set = setmode(mode)) == NULL)
11858142Sbostic 			errx(1, "invalid file mode: %s", mode);
11939829Sbostic 		oct = 0;
12016242Slayer 	}
12134043Sbostic 
12253782Selan 	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
123*66543Sbostic 		err(1, NULL);
124*66543Sbostic 	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
12566445Sbostic 		switch (p->fts_info) {
12653782Selan 		case FTS_D:
127*66543Sbostic 			if (Rflag)		/* Change it at FTS_DP. */
128*66543Sbostic 				continue;
129*66543Sbostic 			fts_set(ftsp, p, FTS_SKIP);
13053782Selan 			break;
131*66543Sbostic 		case FTS_DC:			/* Ignore. */
132*66543Sbostic 			continue;
133*66543Sbostic 		case FTS_DNR:			/* Warn, chmod, continue. */
134*66543Sbostic 			errno = p->fts_errno;
135*66543Sbostic 			warn("%s", p->fts_path);
136*66543Sbostic 			rval = 1;
137*66543Sbostic 			break;
138*66543Sbostic 		case FTS_ERR:			/* Warn, continue. */
13953782Selan 		case FTS_NS:
140*66543Sbostic 			errno = p->fts_errno;
141*66543Sbostic 			warn("%s", p->fts_path);
142*66543Sbostic 			rval = 1;
143*66543Sbostic 			continue;
144*66543Sbostic 		case FTS_SL:			/* Ignore. */
145*66543Sbostic 		case FTS_SLNONE:
146*66543Sbostic 			/*
147*66543Sbostic 			 * The only symlinks that end up here are ones that
148*66543Sbostic 			 * don't point to anything and ones that we found
149*66543Sbostic 			 * doing a physical walk.
150*66543Sbostic 			 */
151*66543Sbostic 			continue;
152*66543Sbostic 		default:
15353782Selan 			break;
15453782Selan 		}
155*66543Sbostic 		if (chmod(p->fts_accpath, oct ? omode :
156*66543Sbostic 		    getmode(set, p->fts_statp->st_mode)) && !fflag) {
157*66543Sbostic 			warn(p->fts_path);
158*66543Sbostic 			rval = 1;
159*66543Sbostic 		}
160*66543Sbostic 	}
161*66543Sbostic 	exit(rval);
16216242Slayer }
16316242Slayer 
16452070Sbostic void
16539829Sbostic usage()
16616242Slayer {
167*66543Sbostic 	(void)fprintf(stderr,
168*66543Sbostic 	    "usage: chmod [-R [-H | -L | -P]] mode file ...\n");
16939829Sbostic 	exit(1);
17016242Slayer }
171