xref: /original-bsd/bin/chmod/chmod.c (revision a95f03a8)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)chmod.c	5.22 (Berkeley) 06/01/92";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <errno.h>
21 #include <fts.h>
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 int retval;
28 
29 void err __P((const char *, ...));
30 void error __P((char *));
31 void usage __P((void));
32 
33 int
34 main(argc, argv)
35 	int argc;
36 	char *argv[];
37 {
38 	register FTS *ftsp;
39 	register FTSENT *p;
40 	register int oct, omode;
41 	struct stat sb;
42 	mode_t *set;
43 	int ch, fflag, rflag, hflag, Hflag;
44 	char *ep, *mode;
45 	int fts_options;
46 
47 	fts_options = FTS_PHYSICAL;
48 	fflag = rflag = hflag = Hflag = 0;
49 	while ((ch = getopt(argc, argv, "HRfhrwx")) != EOF)
50 		switch((char)ch) {
51 		case 'H':
52 			Hflag = 1;
53 			fts_options |= FTS_COMFOLLOW;
54 			break;
55 		case 'R':
56 			rflag = 1;
57 			break;
58 		case 'f':		/* no longer documented */
59 			fflag = 1;
60 			break;
61 		case 'h':
62 			hflag = 1;
63 			fts_options &= ~FTS_PHYSICAL;
64 			fts_options |= FTS_LOGICAL;
65 			break;
66 		case 'r':		/* "-[rwx]" are valid file modes */
67 		case 'w':
68 		case 'x':
69 			--optind;
70 			goto done;
71 		case '?':
72 		default:
73 			usage();
74 		}
75 done:	argv += optind;
76 	argc -= optind;
77 
78 	if (argc < 2)
79 		usage();
80 
81 	mode = *argv;
82 	if (*mode >= '0' && *mode <= '7') {
83 		omode = (int)strtol(mode, &ep, 8);
84 		if (omode < 0 || *ep)
85 			err("invalid file mode: %s", mode);
86 		oct = 1;
87 	} else {
88 		if (!(set = setmode(mode)))
89 			err("invalid file mode: %s", mode);
90 		oct = 0;
91 	}
92 
93 	retval = 0;
94 	if (oct)
95 		fts_options |= FTS_NOSTAT;
96 	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
97 			err("%s", strerror(errno));
98 	while (p = fts_read(ftsp))
99 		switch(p->fts_info) {
100 		case FTS_D:
101 			if (!rflag)
102 				fts_set(ftsp, p, FTS_SKIP);
103 			break;
104 		case FTS_DNR:
105 		case FTS_ERR:
106 		case FTS_NS:
107 			err("%s: %s", p->fts_path, strerror(errno));
108 		default:
109 			if (p->fts_info == FTS_SL &&
110 			    !(hflag ||
111 			    (Hflag && p->fts_level == FTS_ROOTLEVEL)))
112 				continue;
113 			if (chmod(p->fts_accpath, oct ? omode :
114 			    getmode(set, p->fts_statp->st_mode)) &&
115 			    !fflag)
116 				error(p->fts_path);
117 			break;
118 		}
119 	exit(retval);
120 }
121 
122 void
123 error(name)
124 	char *name;
125 {
126 	(void)fprintf(stderr, "chmod: %s: %s\n", name, strerror(errno));
127 	retval = 1;
128 }
129 
130 void
131 usage()
132 {
133 	(void)fprintf(stderr, "usage: chmod [-HRh] mode file ...\n");
134 	exit(1);
135 }
136 
137 #if __STDC__
138 #include <stdarg.h>
139 #else
140 #include <varargs.h>
141 #endif
142 
143 void
144 #if __STDC__
145 err(const char *fmt, ...)
146 #else
147 err(fmt, va_alist)
148 	char *fmt;
149         va_dcl
150 #endif
151 {
152 	va_list ap;
153 #if __STDC__
154 	va_start(ap, fmt);
155 #else
156 	va_start(ap);
157 #endif
158 	(void)fprintf(stderr, "chmod: ");
159 	(void)vfprintf(stderr, fmt, ap);
160 	va_end(ap);
161 	(void)fprintf(stderr, "\n");
162 	exit(1);
163 	/* NOTREACHED */
164 }
165