xref: /original-bsd/bin/chmod/chmod.c (revision 37071c60)
1 /*
2  * Copyright (c) 1989, 1993
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\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.2 (Berkeley) 12/16/93";
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, "HRfhrwx")) != EOF)
47 		switch((char)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':		/* 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 		 * "-[rwx]" are valid mode commands.  If they are the entire
65 		 * argument, getopt has moved past them, so decrement optind.
66 		 * Regardless, we're done argument processing.
67 		 */
68 		case 'r':
69 			if (!strcmp(argv[optind - 1], "-r"))
70 				--optind;
71 			goto done;
72 		case 'w':
73 			if (!strcmp(argv[optind - 1], "-w"))
74 				--optind;
75 			goto done;
76 		case 'x':
77 			if (!strcmp(argv[optind - 1], "-x"))
78 				--optind;
79 			goto done;
80 		case '?':
81 		default:
82 			usage();
83 		}
84 done:	argv += optind;
85 	argc -= optind;
86 
87 	if (argc < 2)
88 		usage();
89 
90 	mode = *argv;
91 	if (*mode >= '0' && *mode <= '7') {
92 		omode = (int)strtol(mode, &ep, 8);
93 		if (omode < 0 || *ep)
94 			errx(1, "invalid file mode: %s", mode);
95 		oct = 1;
96 	} else {
97 		if ((set = setmode(mode)) == NULL)
98 			errx(1, "invalid file mode: %s", mode);
99 		oct = 0;
100 	}
101 
102 	retval = 0;
103 	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
104 		err(1, "");
105 	while (p = fts_read(ftsp))
106 		switch(p->fts_info) {
107 		case FTS_D:
108 			if (!rflag)
109 				fts_set(ftsp, p, FTS_SKIP);
110 		case FTS_SL:
111 		case FTS_SLNONE:
112 			break;
113 		case FTS_DNR:
114 		case FTS_ERR:
115 		case FTS_NS:
116 			err(1, "%s", p->fts_path);
117 		default:
118 			if (p->fts_info == FTS_SL && !(hflag ||
119 			    (Hflag && p->fts_level == FTS_ROOTLEVEL)))
120 				continue;
121 			if (chmod(p->fts_accpath, oct ? omode :
122 			    getmode(set, p->fts_statp->st_mode)) && !fflag) {
123 				warn(p->fts_path);
124 				retval = 1;
125 			}
126 			break;
127 		}
128 	exit(retval);
129 }
130 
131 void
132 usage()
133 {
134 	(void)fprintf(stderr, "usage: chmod [-HRh] mode file ...\n");
135 	exit(1);
136 }
137