Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcmd/chmod.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1992-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* *
20
***********************************************************************/
21
#pragma prototyped
22
/*
23
* David Korn
24
* Glenn Fowler
25
* AT&T Research
26
*
27
* chmod
28
*/
29
30
static const char usage[] =
31
"[-?\n@(#)$Id: chmod (AT&T Research) 2012-04-20 $\n]"
32
USAGE_LICENSE
33
"[+NAME?chmod - change the access permissions of files]"
34
"[+DESCRIPTION?\bchmod\b changes the permission of each file "
35
"according to mode, which can be either a symbolic representation "
36
"of changes to make, or an octal number representing the bit "
37
"pattern for the new permissions.]"
38
"[+?Symbolic mode strings consist of one or more comma separated list "
39
"of operations that can be perfomed on the mode. Each operation is of "
40
"the form \auser\a \aop\a \aperm\a where \auser\a is zero or more of "
41
"the following letters:]{"
42
"[+u?User permission bits.]"
43
"[+g?Group permission bits.]"
44
"[+o?Other permission bits.]"
45
"[+a?All permission bits. This is the default if none are specified.]"
46
"}"
47
"[+?The \aperm\a portion consists of zero or more of the following letters:]{"
48
"[+r?Read permission.]"
49
"[+s?Setuid when \bu\b is selected for \awho\a and setgid when \bg\b "
50
"is selected for \awho\a.]"
51
"[+w?Write permission.]"
52
"[+x?Execute permission for files, search permission for directories.]"
53
"[+X?Same as \bx\b except that it is ignored for files that do not "
54
"already have at least one \bx\b bit set.]"
55
"[+l?Exclusive lock bit on systems that support it. Group execute "
56
"must be off.]"
57
"[+t?Sticky bit on systems that support it.]"
58
"}"
59
"[+?The \aop\a portion consists of one or more of the following characters:]{"
60
"[++?Cause the permission selected to be added to the existing "
61
"permissions. | is equivalent to +.]"
62
"[+-?Cause the permission selected to be removed to the existing "
63
"permissions.]"
64
"[+=?Cause the permission to be set to the given permissions.]"
65
"[+&?Cause the permission selected to be \aand\aed with the existing "
66
"permissions.]"
67
"[+^?Cause the permission selected to be propagated to more "
68
"restrictive groups.]"
69
"}"
70
"[+?Symbolic modes with the \auser\a portion omitted are subject to "
71
"\bumask\b(2) settings unless the \b=\b \aop\a or the "
72
"\b--ignore-umask\b option is specified.]"
73
"[+?A numeric mode is from one to four octal digits (0-7), "
74
"derived by adding up the bits with values 4, 2, and 1. "
75
"Any omitted digits are assumed to be leading zeros. The "
76
"first digit selects the set user ID (4) and set group ID "
77
"(2) and save text image (1) attributes. The second digit "
78
"selects permissions for the user who owns the file: read "
79
"(4), write (2), and execute (1); the third selects permissions"
80
"for other users in the file's group, with the same values; "
81
"and the fourth for other users not in the file's group, with "
82
"the same values.]"
83
84
"[+?For symbolic links, by default, \bchmod\b changes the mode on the file "
85
"referenced by the symbolic link, not on the symbolic link itself. "
86
"The \b-h\b options can be specified to change the mode of the link. "
87
"When traversing directories with \b-R\b, \bchmod\b either follows "
88
"symbolic links or does not follow symbolic links, based on the "
89
"options \b-H\b, \b-L\b, and \b-P\b. The configuration parameter "
90
"\bPATH_RESOLVE\b determines the default behavior if none of these "
91
"options is specified.]"
92
93
"[+?When the \b-c\b or \b-v\b options are specified, change notifications "
94
"are written to standard output using the format, "
95
"\b%s: mode changed to %0.4o (%s)\b, with arguments of the "
96
"pathname, the numeric mode, and the resulting permission bits as "
97
"would be displayed by the \bls\b command.]"
98
99
"[+?For backwards compatibility, if an invalid option is given that is a valid "
100
"symbolic mode specification, \bchmod\b treats this as a mode "
101
"specification rather than as an option specification.]"
102
103
"[H:metaphysical?Follow symbolic links for command arguments; otherwise don't "
104
"follow symbolic links when traversing directories.]"
105
"[L:logical|follow?Follow symbolic links when traversing directories.]"
106
"[P:physical|nofollow?Don't follow symbolic links when traversing directories.]"
107
"[R:recursive?Change the mode for files in subdirectories recursively.]"
108
"[c:changes?Describe only files whose permission actually change.]"
109
"[f:quiet|silent?Do not report files whose permissioins fail to change.]"
110
"[h|l:symlink?Change the mode of symbolic links on systems that "
111
"support \blchmod\b(2). Implies \b--physical\b.]"
112
"[i:ignore-umask?Ignore the \bumask\b(2) value in symbolic mode "
113
"expressions. This is probably how you expect \bchmod\b to work.]"
114
"[n:show?Show actions but do not change any file modes.]"
115
"[F:reference?Omit the \amode\a operand and use the mode of \afile\a "
116
"instead.]:[file]"
117
"[v:verbose?Describe changed permissions of all files.]"
118
"\n"
119
"\nmode file ...\n"
120
"\n"
121
"[+EXIT STATUS?]{"
122
"[+0?All files changed successfully.]"
123
"[+>0?Unable to change mode of one or more files.]"
124
"}"
125
"[+SEE ALSO?\bchgrp\b(1), \bchown\b(1), \blchmod\b(1), \btw\b(1), \bgetconf\b(1), "
126
"\bls\b(1), \bumask\b(2)]"
127
;
128
129
130
#if defined(__STDPP__directive) && defined(__STDPP__hide)
131
__STDPP__directive pragma pp:hide lchmod
132
#else
133
#define lchmod ______lchmod
134
#endif
135
136
#include <cmd.h>
137
#include <ls.h>
138
#include <fts_fix.h>
139
140
#ifndef ENOSYS
141
#define ENOSYS EINVAL
142
#endif
143
144
#include "FEATURE/symlink"
145
146
#if defined(__STDPP__directive) && defined(__STDPP__hide)
147
__STDPP__directive pragma pp:nohide lchmod
148
#else
149
#undef lchmod
150
#endif
151
152
extern int lchmod(const char*, mode_t);
153
154
/*
155
* NOTE: we only use the native lchmod() on symlinks just in case
156
* the implementation is a feckless stub
157
*/
158
159
int
160
b_chmod(int argc, char** argv, Shbltin_t* context)
161
{
162
register int mode;
163
register int force = 0;
164
register int flags;
165
register char* amode = 0;
166
register FTS* fts;
167
register FTSENT*ent;
168
char* last;
169
int (*chmodf)(const char*, mode_t);
170
int logical = 1;
171
int notify = 0;
172
int ignore = 0;
173
int show = 0;
174
int chlink = 0;
175
struct stat st;
176
177
cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY);
178
flags = fts_flags() | FTS_META | FTS_TOP | FTS_NOPOSTORDER | FTS_NOSEEDOTDIR;
179
180
/*
181
* NOTE: we diverge from the normal optget boilerplate
182
* to allow `chmod -x etc' to fall through
183
*/
184
185
for (;;)
186
{
187
switch (optget(argv, usage))
188
{
189
case 'c':
190
notify = 1;
191
continue;
192
case 'f':
193
force = 1;
194
continue;
195
case 'h':
196
chlink = 1;
197
continue;
198
case 'i':
199
ignore = 1;
200
continue;
201
case 'n':
202
show = 1;
203
continue;
204
case 'v':
205
notify = 2;
206
continue;
207
case 'F':
208
if (stat(opt_info.arg, &st))
209
error(ERROR_exit(1), "%s: cannot stat", opt_info.arg);
210
mode = st.st_mode;
211
amode = "";
212
continue;
213
case 'H':
214
flags |= FTS_META|FTS_PHYSICAL;
215
logical = 0;
216
continue;
217
case 'L':
218
flags &= ~(FTS_META|FTS_PHYSICAL);
219
logical = 0;
220
continue;
221
case 'P':
222
flags &= ~FTS_META;
223
flags |= FTS_PHYSICAL;
224
logical = 0;
225
continue;
226
case 'R':
227
flags &= ~FTS_TOP;
228
logical = 0;
229
continue;
230
case '?':
231
error(ERROR_usage(2), "%s", opt_info.arg);
232
break;
233
}
234
break;
235
}
236
argv += opt_info.index;
237
if (error_info.errors || !*argv || !amode && !*(argv + 1))
238
error(ERROR_usage(2), "%s", optusage(NiL));
239
if (chlink)
240
{
241
flags &= ~FTS_META;
242
flags |= FTS_PHYSICAL;
243
logical = 0;
244
}
245
if (logical)
246
flags &= ~(FTS_META|FTS_PHYSICAL);
247
if (ignore)
248
ignore = umask(0);
249
if (amode)
250
amode = 0;
251
else
252
{
253
amode = *argv++;
254
mode = strperm(amode, &last, 0);
255
if (*last)
256
{
257
if (ignore)
258
umask(ignore);
259
error(ERROR_exit(1), "%s: invalid mode", amode);
260
}
261
}
262
if (!(fts = fts_open(argv, flags, NiL)))
263
{
264
if (ignore)
265
umask(ignore);
266
error(ERROR_system(1), "%s: not found", *argv);
267
}
268
while (!sh_checksig(context) && (ent = fts_read(fts)))
269
switch (ent->fts_info)
270
{
271
case FTS_SL:
272
case FTS_SLNONE:
273
if (chlink)
274
{
275
#if _lib_lchmod
276
chmodf = lchmod;
277
goto commit;
278
#else
279
if (!force)
280
{
281
errno = ENOSYS;
282
error(ERROR_system(0), "%s: cannot change symlink mode", ent->fts_path);
283
}
284
#endif
285
}
286
break;
287
case FTS_F:
288
case FTS_D:
289
anyway:
290
chmodf = chmod;
291
#if _lib_lchmod
292
commit:
293
#endif
294
if (amode)
295
mode = strperm(amode, &last, ent->fts_statp->st_mode);
296
if (show || (*chmodf)(ent->fts_accpath, mode) >= 0)
297
{
298
if (notify == 2 || notify == 1 && (mode&S_IPERM) != (ent->fts_statp->st_mode&S_IPERM))
299
sfprintf(sfstdout, "%s: mode changed to %0.4o (%s)\n", ent->fts_path, mode, fmtmode(mode, 1)+1);
300
}
301
else if (!force)
302
error(ERROR_system(0), "%s: cannot change mode", ent->fts_path);
303
break;
304
case FTS_DC:
305
if (!force)
306
error(ERROR_warn(0), "%s: directory causes cycle", ent->fts_path);
307
break;
308
case FTS_DNR:
309
if (!force)
310
error(ERROR_system(0), "%s: cannot read directory", ent->fts_path);
311
goto anyway;
312
case FTS_DNX:
313
if (!force)
314
error(ERROR_system(0), "%s: cannot search directory", ent->fts_path);
315
goto anyway;
316
case FTS_NS:
317
if (!force)
318
error(ERROR_system(0), "%s: not found", ent->fts_path);
319
break;
320
}
321
fts_close(fts);
322
if (ignore)
323
umask(ignore);
324
return error_info.errors != 0;
325
}
326
327