1 /* vi: set sw=4 ts=4: */
3 * Mini chmod implementation for busybox
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7 * Reworked by (C) 2002 Vladimir Oleynik <dzo@simtreas.ru>
8 * to correctly parse '-rwxgoa'
10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
13 //config: bool "chmod (5.5 kb)"
16 //config: chmod is used to change the access permission of files.
18 //applet:IF_CHMOD(APPLET_NOEXEC(chmod, chmod, BB_DIR_BIN, BB_SUID_DROP, chmod))
20 //kbuild:lib-$(CONFIG_CHMOD) += chmod.o
22 /* BB_AUDIT SUSv3 compliant */
23 /* BB_AUDIT GNU defects - unsupported long options. */
24 /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
26 //usage:#define chmod_trivial_usage
27 //usage: "[-R"IF_DESKTOP("cvf")"] MODE[,MODE]... FILE..."
28 //usage:#define chmod_full_usage "\n\n"
29 //usage: "MODE is octal number (bit pattern sstrwxrwxrwx) or [ugoa]{+|-|=}[rwxXst]"
31 //next 4 options are the same for chmod/chown/chgrp:
32 //usage: "\n -R Recurse"
34 //usage: "\n -c List changed files"
35 //usage: "\n -v Verbose"
36 //usage: "\n -f Hide errors"
39 //usage:#define chmod_example_usage
40 //usage: "$ ls -l /tmp/foo\n"
41 //usage: "-rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n"
42 //usage: "$ chmod u+x /tmp/foo\n"
43 //usage: "$ ls -l /tmp/foo\n"
44 //usage: "-rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo*\n"
45 //usage: "$ chmod 444 /tmp/foo\n"
46 //usage: "$ ls -l /tmp/foo\n"
47 //usage: "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n"
51 /* This is a NOEXEC applet. Be very careful! */
54 #define OPT_RECURSE (option_mask32 & 1)
55 #define OPT_VERBOSE (IF_DESKTOP(option_mask32 & 2) IF_NOT_DESKTOP(0))
56 #define OPT_CHANGED (IF_DESKTOP(option_mask32 & 4) IF_NOT_DESKTOP(0))
57 #define OPT_QUIET (IF_DESKTOP(option_mask32 & 8) IF_NOT_DESKTOP(0))
58 #define OPT_STR "R" IF_DESKTOP("vcf")
61 * chmod never changes the permissions of symbolic links; the chmod
62 * system call cannot change their permissions. This is not a problem
63 * since the permissions of symbolic links are never used.
64 * However, for each symbolic link listed on the command line, chmod changes
65 * the permissions of the pointed-to file. In contrast, chmod ignores
66 * symbolic links encountered during recursive directory traversals.
69 static int FAST_FUNC
fileAction(struct recursive_state
*state
,
75 /* match coreutils behavior */
76 if (state
->depth
== 0) {
77 /* statbuf holds lstat result, but we need stat (follow link) */
78 if (stat(fileName
, statbuf
))
80 } else { /* depth > 0: skip links */
81 if (S_ISLNK(statbuf
->st_mode
))
85 newmode
= bb_parse_mode((char *)state
->userData
, statbuf
->st_mode
);
86 if (newmode
== (mode_t
)-1)
87 bb_error_msg_and_die("invalid mode '%s'", (char *)state
->userData
);
89 if (chmod(fileName
, newmode
) == 0) {
92 && (statbuf
->st_mode
& 07777) != (newmode
& 07777))
95 printf("mode of '%s' changed to %04o (%s)\n", fileName
,
96 newmode
& 07777, bb_mode_string(modestr
, newmode
)+1);
102 bb_simple_perror_msg(fileName
);
106 int chmod_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
107 int chmod_main(int argc UNUSED_PARAM
, char **argv
)
109 int retval
= EXIT_SUCCESS
;
113 /* Convert first encountered -r into ar, -w into aw etc
114 * so that getopt would not eat it */
116 while ((arg
= *++argp
)) {
117 /* Mode spec must be the first arg (sans -R etc) */
118 /* (protect against mishandling e.g. "chmod 644 -r") */
123 /* An option. Not a -- or valid option? */
124 if (arg
[1] && !strchr("-"OPT_STR
, arg
[1])) {
131 getopt32(argv
, "^" OPT_STR
"\0" "-2");
134 /* Restore option-like mode if needed */
135 if (arg
) arg
[0] = '-';
137 /* Ok, ready to do the deed now */
140 if (!recursive_action(*argv
,
141 OPT_RECURSE
, // recurse
142 fileAction
, // file action
143 fileAction
, // dir action
146 retval
= EXIT_FAILURE
;
154 Security: chmod is too important and too subtle.
155 This is a test script (busybox chmod versus coreutils).
156 Run it in empty directory.
159 t1="/tmp/busybox chmod"
177 (cd test1; ls -lR) >out1
178 (cd test2; ls -lR) >out2
179 echo "chmod $1" >out.diff
180 if ! diff -u out1 out2 >>out.diff; then exit 1; fi
183 echo "If script produced 'out.diff' file, then at least one testcase failed"
184 create test1; create test2
191 tst "-R a+w linkfile"
193 tst "a-r,a+x linkfile"