chmod.c revision 1557
1139749Simp/*
276479Swpaul * Copyright (c) 1989, 1993, 1994
376479Swpaul *	The Regents of the University of California.  All rights reserved.
476479Swpaul *
576479Swpaul * Redistribution and use in source and binary forms, with or without
676479Swpaul * modification, are permitted provided that the following conditions
776479Swpaul * are met:
876479Swpaul * 1. Redistributions of source code must retain the above copyright
976479Swpaul *    notice, this list of conditions and the following disclaimer.
1076479Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1176479Swpaul *    notice, this list of conditions and the following disclaimer in the
1276479Swpaul *    documentation and/or other materials provided with the distribution.
1376479Swpaul * 3. All advertising materials mentioning features or use of this software
1476479Swpaul *    must display the following acknowledgement:
1576479Swpaul *	This product includes software developed by the University of
1676479Swpaul *	California, Berkeley and its contributors.
1776479Swpaul * 4. Neither the name of the University nor the names of its contributors
1876479Swpaul *    may be used to endorse or promote products derived from this software
1976479Swpaul *    without specific prior written permission.
2076479Swpaul *
2176479Swpaul * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2276479Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2376479Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2476479Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2576479Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2676479Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2776479Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2876479Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2976479Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3076479Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3176479Swpaul * SUCH DAMAGE.
3276479Swpaul */
3376479Swpaul
34119418Sobrien#ifndef lint
35119418Sobrienstatic char copyright[] =
36119418Sobrien"@(#) Copyright (c) 1989, 1993, 1994\n\
3776479Swpaul	The Regents of the University of California.  All rights reserved.\n";
3876479Swpaul#endif /* not lint */
3976479Swpaul
4076479Swpaul#ifndef lint
4176479Swpaulstatic char sccsid[] = "@(#)chmod.c	8.8 (Berkeley) 4/1/94";
4276479Swpaul#endif /* not lint */
4376479Swpaul
4476479Swpaul#include <sys/types.h>
4576479Swpaul#include <sys/stat.h>
4676479Swpaul
4776479Swpaul#include <err.h>
4876479Swpaul#include <errno.h>
4976479Swpaul#include <fts.h>
5076479Swpaul#include <stdio.h>
5176479Swpaul#include <stdlib.h>
5276479Swpaul#include <string.h>
5376479Swpaul#include <unistd.h>
5476479Swpaul
5576479Swpaulvoid usage __P((void));
5676479Swpaul
5776479Swpaulint
5876479Swpaulmain(argc, argv)
5976479Swpaul	int argc;
6076479Swpaul	char *argv[];
6176479Swpaul{
6276479Swpaul	FTS *ftsp;
6376479Swpaul	FTSENT *p;
6476479Swpaul	mode_t *set;
6576479Swpaul	long val;
6676479Swpaul	int oct, omode;
6776479Swpaul	int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval;
6876479Swpaul	char *ep, *mode;
6976479Swpaul
7076479Swpaul	Hflag = Lflag = Pflag = Rflag = fflag = hflag = 0;
7176479Swpaul	while ((ch = getopt(argc, argv, "HLPRXfgorstuwx")) != EOF)
7276479Swpaul		switch (ch) {
7378323Swpaul		case 'H':
7478323Swpaul			Hflag = 1;
7578323Swpaul			Lflag = Pflag = 0;
7678323Swpaul			break;
7778323Swpaul		case 'L':
7878323Swpaul			Lflag = 1;
7978323Swpaul			Hflag = Pflag = 0;
8078323Swpaul			break;
8178323Swpaul		case 'P':
8278323Swpaul			Pflag = 1;
8378323Swpaul			Hflag = Lflag = 0;
8478323Swpaul			break;
8578323Swpaul		case 'R':
8678323Swpaul			Rflag = 1;
8778323Swpaul			break;
8878323Swpaul		case 'f':		/* XXX: undocumented. */
8976479Swpaul			fflag = 1;
9076479Swpaul			break;
91150968Sglebius		case 'h':
92150968Sglebius			/*
93150968Sglebius			 * In System V (and probably POSIX.2) the -h option
94150968Sglebius			 * causes chmod to change the mode of the symbolic
9576479Swpaul			 * link.  4.4BSD's symbolic links don't have modes,
9676479Swpaul			 * so it's an undocumented noop.  Do syntax checking,
97192506Syongari			 * though.
98192506Syongari			 */
99192506Syongari			hflag = 1;
100192506Syongari			break;
101192506Syongari		/*
10276479Swpaul		 * XXX
103129879Sphk		 * "-[rwx]" are valid mode commands.  If they are the entire
104192506Syongari		 * argument, getopt has moved past them, so decrement optind.
105192506Syongari		 * Regardless, we're done argument processing.
10676479Swpaul		 */
107192506Syongari		case 'g': case 'o': case 'r': case 's':
108192506Syongari		case 't': case 'u': case 'w': case 'X': case 'x':
10976479Swpaul			if (argv[optind - 1][0] == '-' &&
110192506Syongari			    argv[optind - 1][1] == ch &&
11176479Swpaul			    argv[optind - 1][2] == '\0')
11276479Swpaul				--optind;
11376479Swpaul			goto done;
11476479Swpaul		case '?':
11576479Swpaul		default:
11676479Swpaul			usage();
11776479Swpaul		}
11876479Swpauldone:	argv += optind;
11976479Swpaul	argc -= optind;
120226995Smarius
12176479Swpaul	if (argc < 2)
12276479Swpaul		usage();
123119285Simp
124119285Simp	fts_options = FTS_PHYSICAL;
12576479Swpaul	if (Rflag) {
126192506Syongari		if (hflag)
12776479Swpaul			errx(1,
12876522Swpaul		"the -R and -h options may not be specified together.");
12976479Swpaul		if (Hflag)
130192506Syongari			fts_options |= FTS_COMFOLLOW;
131192506Syongari		if (Lflag) {
132192506Syongari			fts_options &= ~FTS_PHYSICAL;
133113506Smdodd			fts_options |= FTS_LOGICAL;
134113506Smdodd		}
13576479Swpaul	}
13676479Swpaul
13776479Swpaul	mode = *argv;
13876479Swpaul	if (*mode >= '0' && *mode <= '7') {
13976479Swpaul		errno = 0;
14076479Swpaul		val = strtol(mode, &ep, 8);
14176479Swpaul		if (val > INT_MAX || val < 0)
142242625Sdim			errno = ERANGE;
14376479Swpaul		if (errno)
14476479Swpaul			err(1, "invalid file mode: %s", mode);
14576479Swpaul		if (*ep)
14676479Swpaul			errx(1, "invalid file mode: %s", mode);
14776479Swpaul		omode = val;
14899497Salfred		oct = 1;
14999497Salfred	} else {
15099497Salfred		if ((set = setmode(mode)) == NULL)
151192506Syongari			errx(1, "invalid file mode: %s", mode);
152192506Syongari		oct = 0;
153192506Syongari	}
15476479Swpaul
155192506Syongari	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
156192506Syongari		err(1, NULL);
157192506Syongari	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
158192506Syongari		switch (p->fts_info) {
159192506Syongari		case FTS_D:
160135250Swpaul			if (Rflag)		/* Change it at FTS_DP. */
161193105Sattilio				continue;
16299497Salfred			fts_set(ftsp, p, FTS_SKIP);
16399497Salfred			break;
16499497Salfred		case FTS_DNR:			/* Warn, chmod, continue. */
165192506Syongari			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
16699497Salfred			rval = 1;
167135250Swpaul			break;
16899497Salfred		case FTS_ERR:			/* Warn, continue. */
16999497Salfred		case FTS_NS:
170135250Swpaul			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
171192506Syongari			rval = 1;
17299497Salfred			continue;
173192506Syongari		case FTS_SL:			/* Ignore. */
174192506Syongari		case FTS_SLNONE:
175192506Syongari			/*
176192506Syongari			 * The only symlinks that end up here are ones that
17776479Swpaul			 * don't point to anything and ones that we found
17899497Salfred			 * doing a physical walk.
17999497Salfred			 */
18099497Salfred			continue;
181192294Syongari		default:
182192506Syongari			break;
18376479Swpaul		}
18499497Salfred		if (chmod(p->fts_accpath, oct ? omode :
18599497Salfred		    getmode(set, p->fts_statp->st_mode)) && !fflag) {
18699497Salfred			warn(p->fts_path);
18776479Swpaul			rval = 1;
188192506Syongari		}
18999497Salfred	}
190192506Syongari	if (errno)
191192506Syongari		err(1, "fts_read");
192192506Syongari	exit(rval);
19399497Salfred}
19499497Salfred
195192506Syongarivoid
196192506Syongariusage()
197192506Syongari{
19876479Swpaul	(void)fprintf(stderr,
199226995Smarius	    "usage: chmod [-R [-H | -L | -P]] mode file ...\n");
200226995Smarius	exit(1);
201226995Smarius}
202226995Smarius