break out special local mail processing (e.g., mapping to the
[unix-history] / usr / src / bin / chmod / chmod.c
CommitLineData
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 9static 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
8cd86009 15static char sccsid[] = "@(#)chmod.c 8.8 (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
29void usage __P((void));
30
31int
3d6dbb93 32main(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
92done: 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 138 case FTS_DNR: /* Warn, chmod, continue. */
8cd86009 139 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
17beb503 140 rval = 1;
87038c50 141 break;
17beb503 142 case FTS_ERR: /* Warn, continue. */
87038c50 143 case FTS_NS:
8cd86009 144 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
17beb503
KB
145 rval = 1;
146 continue;
147 case FTS_SL: /* Ignore. */
148 case FTS_SLNONE:
149 /*
150 * The only symlinks that end up here are ones that
151 * don't point to anything and ones that we found
152 * doing a physical walk.
153 */
154 continue;
155 default:
87038c50
EA
156 break;
157 }
17beb503
KB
158 if (chmod(p->fts_accpath, oct ? omode :
159 getmode(set, p->fts_statp->st_mode)) && !fflag) {
160 warn(p->fts_path);
161 rval = 1;
162 }
163 }
6c1af4dd
KB
164 if (errno)
165 err(1, "fts_read");
17beb503 166 exit(rval);
473911a1
KL
167}
168
a22be226 169void
6aa2c2f8 170usage()
473911a1 171{
17beb503
KB
172 (void)fprintf(stderr,
173 "usage: chmod [-R [-H | -L | -P]] mode file ...\n");
a22be226
KB
174 exit(1);
175}