xref: /original-bsd/bin/chmod/chmod.c (revision e66e06db)
1 /*
2  * Copyright (c) 1989, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1989, 1993, 1994\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)chmod.c	8.3 (Berkeley) 03/25/94";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 
21 #include <err.h>
22 #include <errno.h>
23 #include <fts.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 void usage __P((void));
30 
31 int
32 main(argc, argv)
33 	int argc;
34 	char *argv[];
35 {
36 	register FTS *ftsp;
37 	register FTSENT *p;
38 	register int oct, omode;
39 	mode_t *set;
40 	int ch, fflag, rflag, hflag, Hflag;
41 	int fts_options, retval;
42 	char *ep, *mode;
43 
44 	fts_options = FTS_PHYSICAL;
45 	fflag = rflag = hflag = Hflag = 0;
46 	while ((ch = getopt(argc, argv, "HRXfghorstuwx")) != EOF)
47 		switch (ch) {
48 		case 'H':
49 			Hflag = 1;
50 			fts_options |= FTS_COMFOLLOW;
51 			break;
52 		case 'R':
53 			rflag = 1;
54 			break;
55 		case 'f':		/* XXX: no longer documented. */
56 			fflag = 1;
57 			break;
58 		case 'h':
59 			hflag = 1;
60 			fts_options &= ~FTS_PHYSICAL;
61 			fts_options |= FTS_LOGICAL;
62 			break;
63 		/*
64 		 * XXX
65 		 * "-[rwx]" are valid mode commands.  If they are the entire
66 		 * argument, getopt has moved past them, so decrement optind.
67 		 * Regardless, we're done argument processing.
68 		 */
69 		case 'g': case 'o': case 'r': case 's':
70 		case 't': case 'u': case 'w': case 'X': case 'x':
71 			if (argv[optind - 1][0] == '-' &&
72 			    argv[optind - 1][1] == ch &&
73 			    argv[optind - 1][2] == '\0')
74 				--optind;
75 			goto done;
76 		case '?':
77 		default:
78 			usage();
79 		}
80 done:	argv += optind;
81 	argc -= optind;
82 
83 	if (argc < 2)
84 		usage();
85 
86 	mode = *argv;
87 	if (*mode >= '0' && *mode <= '7') {
88 		omode = (int)strtol(mode, &ep, 8);
89 		if (omode < 0 || *ep)
90 			errx(1, "invalid file mode: %s", mode);
91 		oct = 1;
92 	} else {
93 		if ((set = setmode(mode)) == NULL)
94 			errx(1, "invalid file mode: %s", mode);
95 		oct = 0;
96 	}
97 
98 	retval = 0;
99 	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
100 		err(1, "");
101 	while ((p = fts_read(ftsp)) != NULL)
102 		switch (p->fts_info) {
103 		case FTS_D:
104 			if (!rflag)
105 				fts_set(ftsp, p, FTS_SKIP);
106 		case FTS_SL:
107 		case FTS_SLNONE:
108 			break;
109 		case FTS_DNR:
110 		case FTS_ERR:
111 		case FTS_NS:
112 			err(1, "%s", p->fts_path);
113 		default:
114 			if (p->fts_info == FTS_SL && !(hflag ||
115 			    (Hflag && p->fts_level == FTS_ROOTLEVEL)))
116 				continue;
117 			if (chmod(p->fts_accpath, oct ? omode :
118 			    getmode(set, p->fts_statp->st_mode)) && !fflag) {
119 				warn(p->fts_path);
120 				retval = 1;
121 			}
122 			break;
123 		}
124 	exit(retval);
125 }
126 
127 void
128 usage()
129 {
130 	(void)fprintf(stderr, "usage: chmod [-HRh] mode file ...\n");
131 	exit(1);
132 }
133