blob: c4f8fa0b257c8228d3857e62011ef2e3c1e58598 [file] [log] [blame]
Eric Andersen9f0fedb2001-04-24 18:07:19 +00001/* vi: set sw=4 ts=4: */
2/*
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003 * Mini chmod implementation for busybox
Eric Andersen9f0fedb2001-04-24 18:07:19 +00004 *
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
Eric Andersen9f0fedb2001-04-24 18:07:19 +00006 *
Eric Andersend274b532002-10-10 03:47:01 +00007 * Reworked by (C) 2002 Vladimir Oleynik <dzo@simtreas.ru>
8 * to correctly parse '-rwxgoa'
9 *
Bernhard Reutner-Fischer20f40002006-01-30 17:17:14 +000010 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersen9f0fedb2001-04-24 18:07:19 +000011 */
12
Manuel Novoa III cad53642003-03-19 09:13:01 +000013/* BB_AUDIT SUSv3 compliant */
Denis Vlasenkofefb2792006-10-27 15:13:54 +000014/* BB_AUDIT GNU defects - unsupported long options. */
Manuel Novoa III cad53642003-03-19 09:13:01 +000015/* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
16
Eric Andersen9f0fedb2001-04-24 18:07:19 +000017#include "busybox.h"
Eric Andersen9f0fedb2001-04-24 18:07:19 +000018
Denis Vlasenkofefb2792006-10-27 15:13:54 +000019#define OPT_RECURSE (option_mask32 & 1)
20#define OPT_VERBOSE (USE_DESKTOP(option_mask32 & 2) SKIP_DESKTOP(0))
21#define OPT_CHANGED (USE_DESKTOP(option_mask32 & 4) SKIP_DESKTOP(0))
22#define OPT_QUIET (USE_DESKTOP(option_mask32 & 8) SKIP_DESKTOP(0))
23#define OPT_STR ("-R" USE_DESKTOP("vcf"))
24
Denis Vlasenko51b4c922006-10-27 16:07:20 +000025/* TODO:
26 * chmod never changes the permissions of symbolic links; the chmod
27 * system call cannot change their permissions. This is not a problem
28 * since the permissions of symbolic links are never used.
29 * However, for each symbolic link listed on the command line, chmod changes
30 * the permissions of the pointed-to file. In contrast, chmod ignores
31 * symbolic links encountered during recursive directory traversals.
32 */
33
Eric Andersen9f0fedb2001-04-24 18:07:19 +000034static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
35{
Denis Vlasenkofefb2792006-10-27 15:13:54 +000036 mode_t newmode = statbuf->st_mode;
Denis Vlasenko51b4c922006-10-27 16:07:20 +000037
38 // TODO: match GNU behavior:
39 // if (depth > 0 && S_ISLNK(statbuf->st_mode)) return TRUE;
40 // if (depth == 0) follow link
41
Denis Vlasenkofefb2792006-10-27 15:13:54 +000042 if (!bb_parse_mode((char *)junk, &newmode))
43 bb_error_msg_and_die("invalid mode: %s", (char *)junk);
44
45 if (chmod(fileName, statbuf->st_mode) == 0) {
46 if (OPT_VERBOSE /* -v verbose? or -c changed? */
47 || (OPT_CHANGED && statbuf->st_mode != newmode)
48 ) {
49 printf("mode of '%s' changed to %04o (%s)\n", fileName,
Denis Vlasenko51b4c922006-10-27 16:07:20 +000050 newmode & 07777, bb_mode_string(newmode)+1);
Denis Vlasenkofefb2792006-10-27 15:13:54 +000051 }
52 return TRUE;
53 }
54 if (!OPT_QUIET) /* not silent (-f)? */
55 bb_perror_msg("%s", fileName);
56 return FALSE;
Eric Andersen9f0fedb2001-04-24 18:07:19 +000057}
58
Denis Vlasenkofefb2792006-10-27 15:13:54 +000059int chmod_main(int argc, char **argv)
Eric Andersen9f0fedb2001-04-24 18:07:19 +000060{
Manuel Novoa III cad53642003-03-19 09:13:01 +000061 int retval = EXIT_SUCCESS;
Denis Vlasenkofefb2792006-10-27 15:13:54 +000062 char *arg, **argp;
Eric Andersend274b532002-10-10 03:47:01 +000063 char *smode;
Eric Andersen9f0fedb2001-04-24 18:07:19 +000064
Denis Vlasenko51b4c922006-10-27 16:07:20 +000065 /* Convert first encountered -r into a-r, -w into a-w etc */
Denis Vlasenkofefb2792006-10-27 15:13:54 +000066 argp = argv + 1;
67 while ((arg = *argp)) {
Denis Vlasenko51b4c922006-10-27 16:07:20 +000068 /* Mode spec must be the first arg (sans -R etc) */
69 /* (protect against mishandling e.g. "chmod 644 -r") */
Denis Vlasenkofefb2792006-10-27 15:13:54 +000070 if (arg[0] != '-')
71 break;
72 /* An option. Not a -- or valid option? */
73 if (arg[1] && !strchr(OPT_STR, arg[1])) {
74 argp[0] = xasprintf("a%s", arg);
75 break;
Eric Andersen9f0fedb2001-04-24 18:07:19 +000076 }
Denis Vlasenkofefb2792006-10-27 15:13:54 +000077 argp++;
Eric Andersen9f0fedb2001-04-24 18:07:19 +000078 }
Denis Vlasenkofefb2792006-10-27 15:13:54 +000079 /* "chmod -rzzz abc" will say "invalid mode: a-rzzz"!
80 * It is easily fixable, but deemed not worth the code */
Eric Andersen9f0fedb2001-04-24 18:07:19 +000081
Denis Vlasenkofefb2792006-10-27 15:13:54 +000082 opt_complementary = "-2";
83 getopt32(argc, argv, OPT_STR + 1); /* Reuse string */
84 argv += optind;
Eric Andersend274b532002-10-10 03:47:01 +000085
Denis Vlasenkofefb2792006-10-27 15:13:54 +000086 smode = *argv++;
Manuel Novoa III cad53642003-03-19 09:13:01 +000087
Eric Andersen9f0fedb2001-04-24 18:07:19 +000088 /* Ok, ready to do the deed now */
Manuel Novoa III cad53642003-03-19 09:13:01 +000089 do {
Denis Vlasenko51b4c922006-10-27 16:07:20 +000090 if (!recursive_action(*argv,
91 OPT_RECURSE, // recurse
92 FALSE, // follow links: GNU doesn't
93 FALSE, // depth first
94 fileAction, // file action
95 fileAction, // dir action
96 smode) // user data
97 ) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000098 retval = EXIT_FAILURE;
Eric Andersen9f0fedb2001-04-24 18:07:19 +000099 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000100 } while (*++argv);
101
102 return retval;
Eric Andersen9f0fedb2001-04-24 18:07:19 +0000103}