source: MondoRescue/branches/3.3/mindi-busybox/coreutils/chown.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 6.0 KB
Line 
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 source tree.
8 */
9
10/* BB_AUDIT SUSv3 defects - none? */
11/* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */
12
13//usage:#define chown_trivial_usage
14//usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... USER[:[GRP]] FILE..."
15//usage:#define chown_full_usage "\n\n"
16//usage: "Change the owner and/or group of each FILE to USER and/or GRP\n"
17//usage: "\n -R Recurse"
18//usage: "\n -h Affect symlinks instead of symlink targets"
19//usage: IF_DESKTOP(
20//usage: "\n -L Traverse all symlinks to directories"
21//usage: "\n -H Traverse symlinks on command line only"
22//usage: "\n -P Don't traverse symlinks (default)"
23//usage: "\n -c List changed files"
24//usage: "\n -v List all files"
25//usage: "\n -f Hide errors"
26//usage: )
27//usage:
28//usage:#define chown_example_usage
29//usage: "$ ls -l /tmp/foo\n"
30//usage: "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n"
31//usage: "$ chown root /tmp/foo\n"
32//usage: "$ ls -l /tmp/foo\n"
33//usage: "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n"
34//usage: "$ chown root.root /tmp/foo\n"
35//usage: "ls -l /tmp/foo\n"
36//usage: "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n"
37
38#include "libbb.h"
39
40/* This is a NOEXEC applet. Be very careful! */
41
42
43#define OPT_STR ("Rh" IF_DESKTOP("vcfLHP"))
44#define BIT_RECURSE 1
45#define OPT_RECURSE (opt & 1)
46#define OPT_NODEREF (opt & 2)
47#define OPT_VERBOSE (IF_DESKTOP(opt & 0x04) IF_NOT_DESKTOP(0))
48#define OPT_CHANGED (IF_DESKTOP(opt & 0x08) IF_NOT_DESKTOP(0))
49#define OPT_QUIET (IF_DESKTOP(opt & 0x10) IF_NOT_DESKTOP(0))
50/* POSIX options
51 * -L traverse every symbolic link to a directory encountered
52 * -H if a command line argument is a symbolic link to a directory, traverse it
53 * -P do not traverse any symbolic links (default)
54 * We do not conform to the following:
55 * "Specifying more than one of -H, -L, and -P is not an error.
56 * The last option specified shall determine the behavior of the utility." */
57/* -L */
58#define BIT_TRAVERSE 0x20
59#define OPT_TRAVERSE (IF_DESKTOP(opt & BIT_TRAVERSE) IF_NOT_DESKTOP(0))
60/* -H or -L */
61#define BIT_TRAVERSE_TOP (0x20|0x40)
62#define OPT_TRAVERSE_TOP (IF_DESKTOP(opt & BIT_TRAVERSE_TOP) IF_NOT_DESKTOP(0))
63
64#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS
65static const char chown_longopts[] ALIGN1 =
66 "recursive\0" No_argument "R"
67 "dereference\0" No_argument "\xff"
68 "no-dereference\0" No_argument "h"
69# if ENABLE_DESKTOP
70 "changes\0" No_argument "c"
71 "silent\0" No_argument "f"
72 "quiet\0" No_argument "f"
73 "verbose\0" No_argument "v"
74# endif
75 ;
76#endif
77
78typedef int (*chown_fptr)(const char *, uid_t, gid_t);
79
80struct param_t {
81 struct bb_uidgid_t ugid;
82 chown_fptr chown_func;
83};
84
85static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf,
86 void *vparam, int depth UNUSED_PARAM)
87{
88#define param (*(struct param_t*)vparam)
89#define opt option_mask32
90 uid_t u = (param.ugid.uid == (uid_t)-1L) ? statbuf->st_uid : param.ugid.uid;
91 gid_t g = (param.ugid.gid == (gid_t)-1L) ? statbuf->st_gid : param.ugid.gid;
92
93 if (param.chown_func(fileName, u, g) == 0) {
94 if (OPT_VERBOSE
95 || (OPT_CHANGED && (statbuf->st_uid != u || statbuf->st_gid != g))
96 ) {
97 printf("changed ownership of '%s' to %u:%u\n",
98 fileName, (unsigned)u, (unsigned)g);
99 }
100 return TRUE;
101 }
102 if (!OPT_QUIET)
103 bb_simple_perror_msg(fileName);
104 return FALSE;
105#undef opt
106#undef param
107}
108
109int chown_main(int argc UNUSED_PARAM, char **argv)
110{
111 int retval = EXIT_SUCCESS;
112 int opt, flags;
113 struct param_t param;
114
115#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS
116 applet_long_options = chown_longopts;
117#endif
118 opt_complementary = "-2";
119 opt = getopt32(argv, OPT_STR);
120 argv += optind;
121
122 /* This matches coreutils behavior (almost - see below) */
123 param.chown_func = chown;
124 if (OPT_NODEREF
125 /* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */
126 IF_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE)
127 ) {
128 param.chown_func = lchown;
129 }
130
131 flags = ACTION_DEPTHFIRST; /* match coreutils order */
132 if (OPT_RECURSE)
133 flags |= ACTION_RECURSE;
134 if (OPT_TRAVERSE_TOP)
135 flags |= ACTION_FOLLOWLINKS_L0; /* -H/-L: follow links on depth 0 */
136 if (OPT_TRAVERSE)
137 flags |= ACTION_FOLLOWLINKS; /* follow links if -L */
138
139 parse_chown_usergroup_or_die(&param.ugid, argv[0]);
140
141 /* Ok, ready to do the deed now */
142 while (*++argv) {
143 if (!recursive_action(*argv,
144 flags, /* flags */
145 fileAction, /* file action */
146 fileAction, /* dir action */
147 &param, /* user data */
148 0) /* depth */
149 ) {
150 retval = EXIT_FAILURE;
151 }
152 }
153
154 return retval;
155}
156
157/*
158Testcase. Run in empty directory.
159
160#!/bin/sh
161t1="/tmp/busybox chown"
162t2="/usr/bin/chown"
163create() {
164 rm -rf $1; mkdir $1
165 (
166 cd $1 || exit 1
167 mkdir dir dir2
168 >up
169 >file
170 >dir/file
171 >dir2/file
172 ln -s dir linkdir
173 ln -s file linkfile
174 ln -s ../up dir/linkup
175 ln -s ../dir2 dir/linkupdir2
176 )
177 chown -R 0:0 $1
178}
179tst() {
180 create test1
181 create test2
182 echo "[$1]" >>test1.out
183 echo "[$1]" >>test2.out
184 (cd test1; $t1 $1) >>test1.out 2>&1
185 (cd test2; $t2 $1) >>test2.out 2>&1
186 (cd test1; ls -lnR) >out1
187 (cd test2; ls -lnR) >out2
188 echo "chown $1" >out.diff
189 if ! diff -u out1 out2 >>out.diff; then exit 1; fi
190 rm out.diff
191}
192tst_for_each() {
193 tst "$1 1:1 file"
194 tst "$1 1:1 dir"
195 tst "$1 1:1 linkdir"
196 tst "$1 1:1 linkfile"
197}
198echo "If script produced 'out.diff' file, then at least one testcase failed"
199>test1.out
200>test2.out
201# These match coreutils 6.8:
202tst_for_each "-v"
203tst_for_each "-vR"
204tst_for_each "-vRP"
205tst_for_each "-vRL"
206tst_for_each "-vRH"
207tst_for_each "-vh"
208tst_for_each "-vhR"
209tst_for_each "-vhRP"
210tst_for_each "-vhRL"
211tst_for_each "-vhRH"
212# Fix `name' in coreutils output
213sed 's/`/'"'"'/g' -i test2.out
214# Compare us with coreutils output
215diff -u test1.out test2.out
216
217*/
Note: See TracBrowser for help on using the repository browser.