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

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