Commit | Line | Data |
---|---|---|
bcf1365c | 1 | /* |
1d544238 | 2 | * Copyright (c) 1989, 1993, 1994 |
e58705cc | 3 | * The Regents of the University of California. All rights reserved. |
6aa2c2f8 | 4 | * |
27c71911 | 5 | * %sccs.include.redist.c% |
bcf1365c DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
e58705cc | 9 | static char copyright[] = |
1d544238 | 10 | "@(#) Copyright (c) 1989, 1993, 1994\n\ |
e58705cc | 11 | The Regents of the University of California. All rights reserved.\n"; |
8cc66a82 KB |
12 | #endif /* not lint */ |
13 | ||
14 | #ifndef lint | |
5c6924c1 | 15 | static char sccsid[] = "@(#)chmod.c 8.7 (Berkeley) %G%"; |
8cc66a82 | 16 | #endif /* not lint */ |
473911a1 | 17 | |
473911a1 KL |
18 | #include <sys/types.h> |
19 | #include <sys/stat.h> | |
9da2e0c8 KB |
20 | |
21 | #include <err.h> | |
a22be226 | 22 | #include <errno.h> |
6aa2c2f8 KB |
23 | #include <fts.h> |
24 | #include <stdio.h> | |
a22be226 | 25 | #include <stdlib.h> |
6ebcb998 | 26 | #include <string.h> |
9da2e0c8 | 27 | #include <unistd.h> |
473911a1 | 28 | |
a22be226 KB |
29 | void usage __P((void)); |
30 | ||
31 | int | |
3d6dbb93 | 32 | main(argc, argv) |
8cc66a82 | 33 | int argc; |
a22be226 | 34 | char *argv[]; |
473911a1 | 35 | { |
c92c4ac3 KB |
36 | FTS *ftsp; |
37 | FTSENT *p; | |
a22be226 | 38 | mode_t *set; |
c92c4ac3 KB |
39 | long val; |
40 | int oct, omode; | |
17beb503 | 41 | int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval; |
a22be226 | 42 | char *ep, *mode; |
6aa2c2f8 | 43 | |
17beb503 KB |
44 | Hflag = Lflag = Pflag = Rflag = fflag = hflag = 0; |
45 | while ((ch = getopt(argc, argv, "HLPRXfgorstuwx")) != EOF) | |
1d544238 | 46 | switch (ch) { |
87038c50 EA |
47 | case 'H': |
48 | Hflag = 1; | |
17beb503 KB |
49 | Lflag = Pflag = 0; |
50 | break; | |
51 | case 'L': | |
52 | Lflag = 1; | |
53 | Hflag = Pflag = 0; | |
54 | break; | |
55 | case 'P': | |
56 | Pflag = 1; | |
57 | Hflag = Lflag = 0; | |
87038c50 | 58 | break; |
3d6dbb93 | 59 | case 'R': |
17beb503 | 60 | Rflag = 1; |
3d6dbb93 | 61 | break; |
17beb503 | 62 | case 'f': /* XXX: undocumented. */ |
36c26652 | 63 | fflag = 1; |
3d6dbb93 | 64 | break; |
87038c50 | 65 | case 'h': |
17beb503 KB |
66 | /* |
67 | * In System V (and probably POSIX.2) the -h option | |
68 | * causes chmod to change the mode of the symbolic | |
69 | * link. 4.4BSD's symbolic links don't have modes, | |
70 | * so it's an undocumented noop. Do syntax checking, | |
71 | * though. | |
72 | */ | |
87038c50 | 73 | hflag = 1; |
87038c50 | 74 | break; |
8c57dfdf | 75 | /* |
1d544238 | 76 | * XXX |
8c57dfdf KB |
77 | * "-[rwx]" are valid mode commands. If they are the entire |
78 | * argument, getopt has moved past them, so decrement optind. | |
79 | * Regardless, we're done argument processing. | |
80 | */ | |
1d544238 KB |
81 | case 'g': case 'o': case 'r': case 's': |
82 | case 't': case 'u': case 'w': case 'X': case 'x': | |
83 | if (argv[optind - 1][0] == '-' && | |
84 | argv[optind - 1][1] == ch && | |
85 | argv[optind - 1][2] == '\0') | |
8c57dfdf | 86 | --optind; |
3d6dbb93 | 87 | goto done; |
6aa2c2f8 KB |
88 | case '?': |
89 | default: | |
90 | usage(); | |
fe196551 | 91 | } |
8cc66a82 KB |
92 | done: argv += optind; |
93 | argc -= optind; | |
94 | ||
6aa2c2f8 KB |
95 | if (argc < 2) |
96 | usage(); | |
97 | ||
17beb503 KB |
98 | fts_options = FTS_PHYSICAL; |
99 | if (Rflag) { | |
100 | if (hflag) | |
101 | errx(1, | |
102 | "the -R and -h options may not be specified together."); | |
103 | if (Hflag) | |
104 | fts_options |= FTS_COMFOLLOW; | |
105 | if (Lflag) { | |
106 | fts_options &= ~FTS_PHYSICAL; | |
107 | fts_options |= FTS_LOGICAL; | |
108 | } | |
109 | } | |
110 | ||
6aa2c2f8 KB |
111 | mode = *argv; |
112 | if (*mode >= '0' && *mode <= '7') { | |
c92c4ac3 KB |
113 | errno = 0; |
114 | val = strtol(mode, &ep, 8); | |
115 | if (val > INT_MAX || val < 0) | |
116 | errno = ERANGE; | |
117 | if (errno) | |
118 | err(1, "invalid file mode: %s", mode); | |
119 | if (*ep) | |
9da2e0c8 | 120 | errx(1, "invalid file mode: %s", mode); |
c92c4ac3 | 121 | omode = val; |
6aa2c2f8 KB |
122 | oct = 1; |
123 | } else { | |
9da2e0c8 KB |
124 | if ((set = setmode(mode)) == NULL) |
125 | errx(1, "invalid file mode: %s", mode); | |
6aa2c2f8 | 126 | oct = 0; |
473911a1 | 127 | } |
8cc66a82 | 128 | |
87038c50 | 129 | if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) |
17beb503 KB |
130 | err(1, NULL); |
131 | for (rval = 0; (p = fts_read(ftsp)) != NULL;) { | |
1d544238 | 132 | switch (p->fts_info) { |
87038c50 | 133 | case FTS_D: |
17beb503 KB |
134 | if (Rflag) /* Change it at FTS_DP. */ |
135 | continue; | |
136 | fts_set(ftsp, p, FTS_SKIP); | |
137 | break; | |
17beb503 KB |
138 | case FTS_DNR: /* Warn, chmod, continue. */ |
139 | errno = p->fts_errno; | |
140 | warn("%s", p->fts_path); | |
141 | rval = 1; | |
87038c50 | 142 | break; |
17beb503 | 143 | case FTS_ERR: /* Warn, continue. */ |
87038c50 | 144 | case FTS_NS: |
17beb503 KB |
145 | errno = p->fts_errno; |
146 | warn("%s", p->fts_path); | |
147 | rval = 1; | |
148 | continue; | |
149 | case FTS_SL: /* Ignore. */ | |
150 | case FTS_SLNONE: | |
151 | /* | |
152 | * The only symlinks that end up here are ones that | |
153 | * don't point to anything and ones that we found | |
154 | * doing a physical walk. | |
155 | */ | |
156 | continue; | |
157 | default: | |
87038c50 EA |
158 | break; |
159 | } | |
17beb503 KB |
160 | if (chmod(p->fts_accpath, oct ? omode : |
161 | getmode(set, p->fts_statp->st_mode)) && !fflag) { | |
162 | warn(p->fts_path); | |
163 | rval = 1; | |
164 | } | |
165 | } | |
6c1af4dd KB |
166 | if (errno) |
167 | err(1, "fts_read"); | |
17beb503 | 168 | exit(rval); |
473911a1 KL |
169 | } |
170 | ||
a22be226 | 171 | void |
6aa2c2f8 | 172 | usage() |
473911a1 | 173 | { |
17beb503 KB |
174 | (void)fprintf(stderr, |
175 | "usage: chmod [-R [-H | -L | -P]] mode file ...\n"); | |
a22be226 KB |
176 | exit(1); |
177 | } |