fddce7cf13d4b96cd567d189509d242a8b6b911a
[oweals/busybox.git] / coreutils / chown.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini chown implementation for busybox
4  *
5  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  */
9
10 /* BB_AUDIT SUSv3 defects - unsupported options -H, -L, and -P. */
11 /* BB_AUDIT GNU defects - unsupported long options. */
12 /* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */
13
14 #include "busybox.h"
15
16 static uid_t uid = -1;
17 static gid_t gid = -1;
18
19 static int (*chown_func)(const char *, uid_t, gid_t) = chown;
20
21 #define OPT_RECURSE (option_mask32 & 1)
22 #define OPT_NODEREF (option_mask32 & 2)
23 #define OPT_VERBOSE (USE_DESKTOP(option_mask32 & 4) SKIP_DESKTOP(0))
24 #define OPT_CHANGED (USE_DESKTOP(option_mask32 & 8) SKIP_DESKTOP(0))
25 #define OPT_QUIET   (USE_DESKTOP(option_mask32 & 0x10) SKIP_DESKTOP(0))
26 #define OPT_STR     ("Rh" USE_DESKTOP("vcf"))
27
28 /* TODO:
29  * -H if a command line argument is a symbolic link to a directory, traverse it
30  * -L traverse every symbolic link to a directory encountered
31  * -P do not traverse any symbolic links (default)
32  */
33
34 static int fileAction(const char *fileName, struct stat *statbuf,
35                 void ATTRIBUTE_UNUSED *junk, int depth)
36 {
37         // TODO: -H/-L/-P
38         // if (depth ... && S_ISLNK(statbuf->st_mode)) ....
39
40         if (!chown_func(fileName,
41                                 (uid == (uid_t)-1) ? statbuf->st_uid : uid,
42                                 (gid == (gid_t)-1) ? statbuf->st_gid : gid)) {
43                 if (OPT_VERBOSE
44                  || (OPT_CHANGED && (statbuf->st_uid != uid || statbuf->st_gid != gid))
45                 ) {
46                         printf("changed ownership of '%s' to %u:%u\n", fileName, uid, gid);
47                 }
48                 return TRUE;
49         }
50         if (!OPT_QUIET)
51                 bb_perror_msg("%s", fileName);  /* A filename can have % in it... */
52         return FALSE;
53 }
54
55 int chown_main(int argc, char **argv)
56 {
57         int retval = EXIT_SUCCESS;
58         char *groupName;
59
60         opt_complementary = "-2";
61         getopt32(argc, argv, OPT_STR);
62
63         if (OPT_NODEREF) chown_func = lchown;
64
65         argv += optind;
66
67         /* First, check if there is a group name here */
68         groupName = strchr(*argv, '.');
69         if (!groupName) {
70                 groupName = strchr(*argv, ':');
71         }
72
73         /* Check for the username and groupname */
74         if (groupName) {
75                 *groupName++ = '\0';
76                 gid = get_ug_id(groupName, bb_xgetgrnam);
77         }
78         if (--groupName != *argv)
79                 uid = get_ug_id(*argv, bb_xgetpwnam);
80         ++argv;
81
82         /* Ok, ready to do the deed now */
83         do {
84                 if (!recursive_action(*argv,
85                                 OPT_RECURSE,    // recurse
86                                 FALSE,          // follow links: TODO: -H/-L/-P
87                                 FALSE,          // depth first
88                                 fileAction,     // file action
89                                 fileAction,     // dir action
90                                 NULL,           // user data
91                                 0)              // depth 
92                 ) {
93                         retval = EXIT_FAILURE;
94                 }
95         } while (*++argv);
96
97         return retval;
98 }