1 /* chown -- change user and group ownership of files
2 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21 -------------|-------------------------+-------------------------|
22 g unchanged | --- | chown u |
23 r |-------------------------+-------------------------|
24 o explicit | chgrp g or chown .g | chown u.g |
25 u |-------------------------+-------------------------|
26 p from passwd| --- | chown u. |
27 |-------------------------+-------------------------|
29 Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
33 #include <sys/types.h>
41 #ifndef _POSIX_VERSION
42 struct passwd
*getpwnam ();
43 struct group
*getgrnam ();
44 struct group
*getgrgid ();
48 # define endpwent() ((void) 0)
52 # define LCHOWN(FILE, OWNER, GROUP) lchown (FILE, OWNER, GROUP)
54 # define LCHOWN(FILE, OWNER, GROUP) 1
58 char *parse_user_spec ();
59 void strip_trailing_slashes ();
63 static int change_dir_owner
__P ((char *dir
, uid_t user
, gid_t group
,
66 /* The name the program was run with. */
69 /* If nonzero, and the systems has support for it, change the ownership
70 of symbolic links rather than any files they point to. */
71 static int change_symlinks
;
73 /* If nonzero, change the ownership of directories recursively. */
76 /* If nonzero, force silence (no error messages). */
77 static int force_silent
;
79 /* If nonzero, describe the files we process. */
82 /* If nonzero, describe only owners or groups that change. */
83 static int changes_only
;
85 /* The name of the user to which ownership of the files is being given. */
86 static char *username
;
88 /* The name of the group to which ownership of the files is being given. */
89 static char *groupname
;
91 /* If nonzero, display usage information and exit. */
94 /* If nonzero, print the version on standard output and exit. */
95 static int show_version
;
97 static struct option
const long_options
[] =
99 {"recursive", no_argument
, 0, 'R'},
100 {"changes", no_argument
, 0, 'c'},
101 {"no-dereference", no_argument
, 0, 'h'},
102 {"quiet", no_argument
, 0, 'f'},
103 {"silent", no_argument
, 0, 'f'},
104 {"verbose", no_argument
, 0, 'v'},
105 {"help", no_argument
, &show_help
, 1},
106 {"version", no_argument
, &show_version
, 1},
110 /* Tell the user the user and group names to which ownership of FILE
111 has been given; if CHANGED is zero, FILE had those owners already. */
114 describe_change (char *file
, int changed
)
117 printf (_("owner of %s changed to "), file
);
119 printf (_("owner of %s retained as "), file
);
121 printf ("%s.%s\n", username
, groupname
);
123 printf ("%s\n", username
);
126 /* Change the ownership of FILE to UID USER and GID GROUP.
127 If it is a directory and -R is given, recurse.
128 Return 0 if successful, 1 if errors occurred. */
131 change_file_owner (char *file
, uid_t user
, gid_t group
)
133 struct stat file_stats
;
138 if (lstat (file
, &file_stats
))
140 if (force_silent
== 0)
141 error (0, errno
, "%s", file
);
145 newuser
= user
== (uid_t
) -1 ? file_stats
.st_uid
: user
;
146 newgroup
= group
== (gid_t
) -1 ? file_stats
.st_gid
: group
;
147 if (newuser
!= file_stats
.st_uid
|| newgroup
!= file_stats
.st_gid
)
152 describe_change (file
, 1);
155 fail
= LCHOWN (file
, newuser
, newgroup
);
157 fail
= chown (file
, newuser
, newgroup
);
161 if (force_silent
== 0)
162 error (0, errno
, "%s", file
);
166 else if (verbose
&& changes_only
== 0)
167 describe_change (file
, 0);
169 if (recurse
&& S_ISDIR (file_stats
.st_mode
))
170 errors
|= change_dir_owner (file
, user
, group
, &file_stats
);
174 /* Recursively change the ownership of the files in directory DIR
175 to UID USER and GID GROUP.
176 STATP points to the results of lstat on DIR.
177 Return 0 if successful, 1 if errors occurred. */
180 change_dir_owner (char *dir
, uid_t user
, gid_t group
, struct stat
*statp
)
182 char *name_space
, *namep
;
183 char *path
; /* Full path of each entry to process. */
184 unsigned dirlength
; /* Length of `dir' and '\0'. */
185 unsigned filelength
; /* Length of each pathname to process. */
186 unsigned pathlength
; /* Bytes allocated for `path'. */
190 name_space
= savedir (dir
, statp
->st_size
);
191 if (name_space
== NULL
)
195 if (force_silent
== 0)
196 error (0, errno
, "%s", dir
);
200 error (1, 0, _("virtual memory exhausted"));
203 dirlength
= strlen (dir
) + 1; /* + 1 is for the trailing '/'. */
204 pathlength
= dirlength
+ 1;
205 /* Give `path' a dummy value; it will be reallocated before first use. */
206 path
= xmalloc (pathlength
);
208 path
[dirlength
- 1] = '/';
210 for (namep
= name_space
; *namep
; namep
+= filelength
- dirlength
)
212 filelength
= dirlength
+ strlen (namep
) + 1;
213 if (filelength
> pathlength
)
215 pathlength
= filelength
* 2;
216 path
= xrealloc (path
, pathlength
);
218 strcpy (path
+ dirlength
, namep
);
219 errors
|= change_file_owner (path
, user
, group
);
230 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
235 Usage: %s [OPTION]... OWNER[.[GROUP]] FILE...\n\
236 or: %s [OPTION]... .[GROUP] FILE...\n\
238 program_name
, program_name
);
240 Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\
242 -c, --changes be verbose whenever change occurs\n\
243 -h, --no-dereference affect symbolic links instead of any referenced file\n\
244 (available only on systems with lchown system call)\n\
245 -f, --silent, --quiet suppress most error messages\n\
246 -v, --verbose explain what is being done\n\
247 -R, --recursive change files and directories recursively\n\
248 --help display this help and exit\n\
249 --version output version information and exit\n\
251 Owner is unchanged if missing. Group is unchanged if missing, but changed\n\
252 to login group if implied by a period. A colon may replace the period.\n"));
258 main (int argc
, char **argv
)
260 uid_t user
= (uid_t
) -1; /* New uid; -1 if not to be changed. */
261 gid_t group
= (uid_t
) -1; /* New gid; -1 if not to be changed. */
266 program_name
= argv
[0];
267 setlocale (LC_ALL
, "");
268 bindtextdomain (PACKAGE
, LOCALEDIR
);
269 textdomain (PACKAGE
);
271 recurse
= force_silent
= verbose
= changes_only
= 0;
273 while ((optc
= getopt_long (argc
, argv
, "Rcfhv", long_options
, (int *) 0))
303 printf ("chown - %s\n", PACKAGE_VERSION
);
310 if (optind
>= argc
- 1)
312 error (0, 0, _("too few arguments"));
319 error (1, 0, _("--no-dereference (-h) is not supported on this system"));
323 e
= parse_user_spec (argv
[optind
], &user
, &group
, &username
, &groupname
);
325 error (1, 0, "%s: %s", argv
[optind
], e
);
326 if (username
== NULL
)
329 for (++optind
; optind
< argc
; ++optind
)
331 strip_trailing_slashes (argv
[optind
]);
332 errors
|= change_file_owner (argv
[optind
], user
, group
);