1 /* chown -- change user and group ownership of files
2 Copyright (C) 1989, 1990, 1991, 1995 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
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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>
42 #ifndef _POSIX_VERSION
43 struct passwd
*getpwnam ();
44 struct group
*getgrnam ();
45 struct group
*getgrgid ();
54 char *parse_user_spec ();
55 void strip_trailing_slashes ();
59 static int change_file_owner ();
60 static int change_dir_owner ();
61 static void describe_change ();
64 /* The name the program was run with. */
67 /* If nonzero, change the ownership of directories recursively. */
70 /* If nonzero, force silence (no error messages). */
71 static int force_silent
;
73 /* If nonzero, describe the files we process. */
76 /* If nonzero, describe only owners or groups that change. */
77 static int changes_only
;
79 /* The name of the user to which ownership of the files is being given. */
80 static char *username
;
82 /* The name of the group to which ownership of the files is being given. */
83 static char *groupname
;
85 /* If non-zero, display usage information and exit. */
88 /* If non-zero, print the version on standard output and exit. */
89 static int show_version
;
91 static struct option
const long_options
[] =
93 {"recursive", no_argument
, 0, 'R'},
94 {"changes", no_argument
, 0, 'c'},
95 {"silent", no_argument
, 0, 'f'},
96 {"quiet", no_argument
, 0, 'f'},
97 {"verbose", no_argument
, 0, 'v'},
98 {"help", no_argument
, &show_help
, 1},
99 {"version", no_argument
, &show_version
, 1},
108 uid_t user
= (uid_t
) -1; /* New uid; -1 if not to be changed. */
109 gid_t group
= (uid_t
) -1; /* New gid; -1 if not to be changed. */
114 program_name
= argv
[0];
115 recurse
= force_silent
= verbose
= changes_only
= 0;
117 while ((optc
= getopt_long (argc
, argv
, "Rcfv", long_options
, (int *) 0))
144 printf ("chown - %s\n", version_string
);
151 if (optind
>= argc
- 1)
153 error (0, 0, "too few arguments");
157 e
= parse_user_spec (argv
[optind
], &user
, &group
, &username
, &groupname
);
159 error (1, 0, "%s: %s", argv
[optind
], e
);
160 if (username
== NULL
)
163 for (++optind
; optind
< argc
; ++optind
)
165 strip_trailing_slashes (argv
[optind
]);
166 errors
|= change_file_owner (argv
[optind
], user
, group
);
172 /* Change the ownership of FILE to UID USER and GID GROUP.
173 If it is a directory and -R is given, recurse.
174 Return 0 if successful, 1 if errors occurred. */
177 change_file_owner (file
, user
, group
)
182 struct stat file_stats
;
187 if (lstat (file
, &file_stats
))
189 if (force_silent
== 0)
190 error (0, errno
, "%s", file
);
194 newuser
= user
== (uid_t
) -1 ? file_stats
.st_uid
: user
;
195 newgroup
= group
== (gid_t
) -1 ? file_stats
.st_gid
: group
;
196 if (newuser
!= file_stats
.st_uid
|| newgroup
!= file_stats
.st_gid
)
199 describe_change (file
, 1);
200 if (chown (file
, newuser
, newgroup
))
202 if (force_silent
== 0)
203 error (0, errno
, "%s", file
);
207 else if (verbose
&& changes_only
== 0)
208 describe_change (file
, 0);
210 if (recurse
&& S_ISDIR (file_stats
.st_mode
))
211 errors
|= change_dir_owner (file
, user
, group
, &file_stats
);
215 /* Recursively change the ownership of the files in directory DIR
216 to UID USER and GID GROUP.
217 STATP points to the results of lstat on DIR.
218 Return 0 if successful, 1 if errors occurred. */
221 change_dir_owner (dir
, user
, group
, statp
)
227 char *name_space
, *namep
;
228 char *path
; /* Full path of each entry to process. */
229 unsigned dirlength
; /* Length of `dir' and '\0'. */
230 unsigned filelength
; /* Length of each pathname to process. */
231 unsigned pathlength
; /* Bytes allocated for `path'. */
235 name_space
= savedir (dir
, statp
->st_size
);
236 if (name_space
== NULL
)
240 if (force_silent
== 0)
241 error (0, errno
, "%s", dir
);
245 error (1, 0, "virtual memory exhausted");
248 dirlength
= strlen (dir
) + 1; /* + 1 is for the trailing '/'. */
249 pathlength
= dirlength
+ 1;
250 /* Give `path' a dummy value; it will be reallocated before first use. */
251 path
= xmalloc (pathlength
);
253 path
[dirlength
- 1] = '/';
255 for (namep
= name_space
; *namep
; namep
+= filelength
- dirlength
)
257 filelength
= dirlength
+ strlen (namep
) + 1;
258 if (filelength
> pathlength
)
260 pathlength
= filelength
* 2;
261 path
= xrealloc (path
, pathlength
);
263 strcpy (path
+ dirlength
, namep
);
264 errors
|= change_file_owner (path
, user
, group
);
271 /* Tell the user the user and group names to which ownership of FILE
272 has been given; if CHANGED is zero, FILE had those owners already. */
275 describe_change (file
, changed
)
280 printf ("owner of %s changed to ", file
);
282 printf ("owner of %s retained as ", file
);
284 printf ("%s.%s\n", username
, groupname
);
286 printf ("%s\n", username
);
294 fprintf (stderr
, "Try `%s --help' for more information.\n",
299 Usage: %s [OPTION]... OWNER[.[GROUP]] FILE...\n\
300 or: %s [OPTION]... .[GROUP] FILE...\n\
302 program_name
, program_name
);
304 Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\
306 -c, --changes be verbose whenever change occurs\n\
307 -f, --silent, --quiet suppress most error messages\n\
308 -v, --verbose explain what is being done\n\
309 -R, --recursive change files and directories recursively\n\
310 --help display this help and exit\n\
311 --version output version information and exit\n\
313 Owner is unchanged if missing. Group is unchanged if missing, but changed\n\
314 to login group if implied by a period. A colon may replace the period.\n");