Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/coreutils/chown.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC revision 1123 by niro, Wed Aug 18 21:56:57 2010 UTC
# Line 7  Line 7 
7   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.   * 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. */  /* BB_AUDIT SUSv3 defects - none? */
 /* BB_AUDIT GNU defects - unsupported long options. */  
11  /* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */  /* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */
12    
13  #include "busybox.h"  #include "libbb.h"
14    
15  static struct bb_uidgid_t ugid = { -1, -1 };  /* This is a NOEXEC applet. Be very careful! */
16    
 static int (*chown_func)(const char *, uid_t, gid_t) = chown;  
17    
18  #define OPT_RECURSE (option_mask32 & 1)  #define OPT_STR     ("Rh" IF_DESKTOP("vcfLHP"))
19  #define OPT_NODEREF (option_mask32 & 2)  #define BIT_RECURSE 1
20  #define OPT_VERBOSE (USE_DESKTOP(option_mask32 & 4) SKIP_DESKTOP(0))  #define OPT_RECURSE (opt & 1)
21  #define OPT_CHANGED (USE_DESKTOP(option_mask32 & 8) SKIP_DESKTOP(0))  #define OPT_NODEREF (opt & 2)
22  #define OPT_QUIET   (USE_DESKTOP(option_mask32 & 0x10) SKIP_DESKTOP(0))  #define OPT_VERBOSE (IF_DESKTOP(opt & 0x04) IF_NOT_DESKTOP(0))
23  #define OPT_STR     ("Rh" USE_DESKTOP("vcf"))  #define OPT_CHANGED (IF_DESKTOP(opt & 0x08) IF_NOT_DESKTOP(0))
24    #define OPT_QUIET   (IF_DESKTOP(opt & 0x10) IF_NOT_DESKTOP(0))
25  /* TODO:  /* POSIX options
  * -H if a command line argument is a symbolic link to a directory, traverse it  
26   * -L traverse every symbolic link to a directory encountered   * -L traverse every symbolic link to a directory encountered
27     * -H if a command line argument is a symbolic link to a directory, traverse it
28   * -P do not traverse any symbolic links (default)   * -P do not traverse any symbolic links (default)
29   */   * We do not conform to the following:
30     * "Specifying more than one of -H, -L, and -P is not an error.
31     * The last option specified shall determine the behavior of the utility." */
32    /* -L */
33    #define BIT_TRAVERSE 0x20
34    #define OPT_TRAVERSE (IF_DESKTOP(opt & BIT_TRAVERSE) IF_NOT_DESKTOP(0))
35    /* -H or -L */
36    #define BIT_TRAVERSE_TOP (0x20|0x40)
37    #define OPT_TRAVERSE_TOP (IF_DESKTOP(opt & BIT_TRAVERSE_TOP) IF_NOT_DESKTOP(0))
38    
39    #if ENABLE_FEATURE_CHOWN_LONG_OPTIONS
40    static const char chown_longopts[] ALIGN1 =
41     "recursive\0"        No_argument   "R"
42     "dereference\0"      No_argument   "\xff"
43     "no-dereference\0"   No_argument   "h"
44    # if ENABLE_DESKTOP
45     "changes\0"          No_argument   "c"
46     "silent\0"           No_argument   "f"
47     "quiet\0"            No_argument   "f"
48     "verbose\0"          No_argument   "v"
49    # endif
50     ;
51    #endif
52    
53    typedef int (*chown_fptr)(const char *, uid_t, gid_t);
54    
55    struct param_t {
56     struct bb_uidgid_t ugid;
57     chown_fptr chown_func;
58    };
59    
60  static int fileAction(const char *fileName, struct stat *statbuf,  static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf,
61   void ATTRIBUTE_UNUSED *junk, int depth)   void *vparam, int depth UNUSED_PARAM)
62  {  {
63   // TODO: -H/-L/-P  #define param  (*(struct param_t*)vparam)
64   // if (depth ... && S_ISLNK(statbuf->st_mode)) ....  #define opt option_mask32
65     uid_t u = (param.ugid.uid == (uid_t)-1L) ? statbuf->st_uid : param.ugid.uid;
66     gid_t g = (param.ugid.gid == (gid_t)-1L) ? statbuf->st_gid : param.ugid.gid;
67    
68   if (!chown_func(fileName,   if (param.chown_func(fileName, u, g) == 0) {
  (ugid.uid == (uid_t)-1) ? statbuf->st_uid : ugid.uid,  
  (ugid.gid == (gid_t)-1) ? statbuf->st_gid : ugid.gid)  
  ) {  
69   if (OPT_VERBOSE   if (OPT_VERBOSE
70   || (OPT_CHANGED && (statbuf->st_uid != ugid.uid || statbuf->st_gid != ugid.gid))   || (OPT_CHANGED && (statbuf->st_uid != u || statbuf->st_gid != g))
71   ) {   ) {
72   printf("changed ownership of '%s' to %u:%u\n",   printf("changed ownership of '%s' to %u:%u\n",
73   fileName, ugid.uid, ugid.gid);   fileName, (unsigned)u, (unsigned)g);
74   }   }
75   return TRUE;   return TRUE;
76   }   }
77   if (!OPT_QUIET)   if (!OPT_QUIET)
78   bb_perror_msg("%s", fileName); /* A filename can have % in it... */   bb_simple_perror_msg(fileName);
79   return FALSE;   return FALSE;
80    #undef opt
81    #undef param
82  }  }
83    
84  int chown_main(int argc, char **argv)  int chown_main(int argc UNUSED_PARAM, char **argv)
85  {  {
  char *groupName;  
86   int retval = EXIT_SUCCESS;   int retval = EXIT_SUCCESS;
87     int opt, flags;
88     struct param_t param;
89    
90     /* Just -1 might not work: uid_t may be unsigned long */
91     param.ugid.uid = -1L;
92     param.ugid.gid = -1L;
93    
94    #if ENABLE_FEATURE_CHOWN_LONG_OPTIONS
95     applet_long_options = chown_longopts;
96    #endif
97   opt_complementary = "-2";   opt_complementary = "-2";
98   getopt32(argc, argv, OPT_STR);   opt = getopt32(argv, OPT_STR);
99   argv += optind;   argv += optind;
100    
101   if (OPT_NODEREF) chown_func = lchown;   /* This matches coreutils behavior (almost - see below) */
102     param.chown_func = chown;
103   /* First, check if there is a group name here */   if (OPT_NODEREF
104   groupName = strchr(*argv, '.'); /* deprecated? */      /* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */
105   if (!groupName)      IF_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE)
106   groupName = strchr(*argv, ':');   ) {
107   else   param.chown_func = lchown;
  *groupName = ':'; /* replace '.' with ':' */  
   
  /* First, try parsing "user[:[group]]" */  
  if (!groupName) { /* "user" */  
  ugid.uid = get_ug_id(*argv, xuname2uid);  
  } else if (groupName == *argv) { /* ":group" */  
  ugid.gid = get_ug_id(groupName + 1, xgroup2gid);  
  } else {  
  if (!groupName[1]) /* "user:" */  
  *groupName = '\0';  
  if (!get_uidgid(&ugid, *argv, 1))  
  bb_error_msg_and_die("unknown user/group %s", *argv);  
108   }   }
109    
110     flags = ACTION_DEPTHFIRST; /* match coreutils order */
111     if (OPT_RECURSE)
112     flags |= ACTION_RECURSE;
113     if (OPT_TRAVERSE_TOP)
114     flags |= ACTION_FOLLOWLINKS_L0; /* -H/-L: follow links on depth 0 */
115     if (OPT_TRAVERSE)
116     flags |= ACTION_FOLLOWLINKS; /* follow links if -L */
117    
118     parse_chown_usergroup_or_die(&param.ugid, argv[0]);
119    
120   /* Ok, ready to do the deed now */   /* Ok, ready to do the deed now */
121   argv++;   while (*++argv) {
  do {  
122   if (!recursive_action(*argv,   if (!recursive_action(*argv,
123   OPT_RECURSE, // recurse   flags,          /* flags */
124   FALSE,          // follow links: TODO: -H/-L/-P   fileAction,     /* file action */
125   FALSE,          // depth first   fileAction,     /* dir action */
126   fileAction,     // file action   &param,         /* user data */
127   fileAction,     // dir action   0)              /* depth */
  NULL,           // user data  
  0)              // depth  
128   ) {   ) {
129   retval = EXIT_FAILURE;   retval = EXIT_FAILURE;
130   }   }
131   } while (*++argv);   }
132    
133   return retval;   return retval;
134  }  }
135    
136    /*
137    Testcase. Run in empty directory.
138    
139    #!/bin/sh
140    t1="/tmp/busybox chown"
141    t2="/usr/bin/chown"
142    create() {
143        rm -rf $1; mkdir $1
144        (
145        cd $1 || exit 1
146        mkdir dir dir2
147        >up
148        >file
149        >dir/file
150        >dir2/file
151        ln -s dir linkdir
152        ln -s file linkfile
153        ln -s ../up dir/linkup
154        ln -s ../dir2 dir/linkupdir2
155        )
156        chown -R 0:0 $1
157    }
158    tst() {
159        create test1
160        create test2
161        echo "[$1]" >>test1.out
162        echo "[$1]" >>test2.out
163        (cd test1; $t1 $1) >>test1.out 2>&1
164        (cd test2; $t2 $1) >>test2.out 2>&1
165        (cd test1; ls -lnR) >out1
166        (cd test2; ls -lnR) >out2
167        echo "chown $1" >out.diff
168        if ! diff -u out1 out2 >>out.diff; then exit 1; fi
169        rm out.diff
170    }
171    tst_for_each() {
172        tst "$1 1:1 file"
173        tst "$1 1:1 dir"
174        tst "$1 1:1 linkdir"
175        tst "$1 1:1 linkfile"
176    }
177    echo "If script produced 'out.diff' file, then at least one testcase failed"
178    >test1.out
179    >test2.out
180    # These match coreutils 6.8:
181    tst_for_each "-v"
182    tst_for_each "-vR"
183    tst_for_each "-vRP"
184    tst_for_each "-vRL"
185    tst_for_each "-vRH"
186    tst_for_each "-vh"
187    tst_for_each "-vhR"
188    tst_for_each "-vhRP"
189    tst_for_each "-vhRL"
190    tst_for_each "-vhRH"
191    # Fix `name' in coreutils output
192    sed 's/`/'"'"'/g' -i test2.out
193    # Compare us with coreutils output
194    diff -u test1.out test2.out
195    
196    */

Legend:
Removed from v.532  
changed lines
  Added in v.1123