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 ();
49 # define endpwent() ((void) 0)
53 char *parse_user_spec ();
54 void strip_trailing_slashes ();
58 static int change_dir_owner
__P ((char *dir
, uid_t user
, gid_t group
,
61 /* The name the program was run with. */
64 /* If nonzero, change the ownership of directories recursively. */
67 /* If nonzero, force silence (no error messages). */
68 static int force_silent
;
70 /* If nonzero, describe the files we process. */
73 /* If nonzero, describe only owners or groups that change. */
74 static int changes_only
;
76 /* The name of the user to which ownership of the files is being given. */
77 static char *username
;
79 /* The name of the group to which ownership of the files is being given. */
80 static char *groupname
;
82 /* If nonzero, display usage information and exit. */
85 /* If nonzero, print the version on standard output and exit. */
86 static int show_version
;
88 static struct option
const long_options
[] =
90 {"recursive", no_argument
, 0, 'R'},
91 {"changes", no_argument
, 0, 'c'},
92 {"silent", no_argument
, 0, 'f'},
93 {"quiet", no_argument
, 0, 'f'},
94 {"verbose", no_argument
, 0, 'v'},
95 {"help", no_argument
, &show_help
, 1},
96 {"version", no_argument
, &show_version
, 1},
100 /* Tell the user the user and group names to which ownership of FILE
101 has been given; if CHANGED is zero, FILE had those owners already. */
104 describe_change (char *file
, int changed
)
107 printf (_("owner of %s changed to "), file
);
109 printf (_("owner of %s retained as "), file
);
111 printf ("%s.%s\n", username
, groupname
);
113 printf ("%s\n", username
);
116 /* Change the ownership of FILE to UID USER and GID GROUP.
117 If it is a directory and -R is given, recurse.
118 Return 0 if successful, 1 if errors occurred. */
121 change_file_owner (char *file
, uid_t user
, gid_t group
)
123 struct stat file_stats
;
128 if (lstat (file
, &file_stats
))
130 if (force_silent
== 0)
131 error (0, errno
, "%s", file
);
135 newuser
= user
== (uid_t
) -1 ? file_stats
.st_uid
: user
;
136 newgroup
= group
== (gid_t
) -1 ? file_stats
.st_gid
: group
;
137 if (newuser
!= file_stats
.st_uid
|| newgroup
!= file_stats
.st_gid
)
140 describe_change (file
, 1);
141 if (chown (file
, newuser
, newgroup
))
143 if (force_silent
== 0)
144 error (0, errno
, "%s", file
);
148 else if (verbose
&& changes_only
== 0)
149 describe_change (file
, 0);
151 if (recurse
&& S_ISDIR (file_stats
.st_mode
))
152 errors
|= change_dir_owner (file
, user
, group
, &file_stats
);
156 /* Recursively change the ownership of the files in directory DIR
157 to UID USER and GID GROUP.
158 STATP points to the results of lstat on DIR.
159 Return 0 if successful, 1 if errors occurred. */
162 change_dir_owner (char *dir
, uid_t user
, gid_t group
, struct stat
*statp
)
164 char *name_space
, *namep
;
165 char *path
; /* Full path of each entry to process. */
166 unsigned dirlength
; /* Length of `dir' and '\0'. */
167 unsigned filelength
; /* Length of each pathname to process. */
168 unsigned pathlength
; /* Bytes allocated for `path'. */
172 name_space
= savedir (dir
, statp
->st_size
);
173 if (name_space
== NULL
)
177 if (force_silent
== 0)
178 error (0, errno
, "%s", dir
);
182 error (1, 0, _("virtual memory exhausted"));
185 dirlength
= strlen (dir
) + 1; /* + 1 is for the trailing '/'. */
186 pathlength
= dirlength
+ 1;
187 /* Give `path' a dummy value; it will be reallocated before first use. */
188 path
= xmalloc (pathlength
);
190 path
[dirlength
- 1] = '/';
192 for (namep
= name_space
; *namep
; namep
+= filelength
- dirlength
)
194 filelength
= dirlength
+ strlen (namep
) + 1;
195 if (filelength
> pathlength
)
197 pathlength
= filelength
* 2;
198 path
= xrealloc (path
, pathlength
);
200 strcpy (path
+ dirlength
, namep
);
201 errors
|= change_file_owner (path
, user
, group
);
212 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
217 Usage: %s [OPTION]... OWNER[.[GROUP]] FILE...\n\
218 or: %s [OPTION]... .[GROUP] FILE...\n\
220 program_name
, program_name
);
222 Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\
224 -c, --changes be verbose whenever change occurs\n\
225 -f, --silent, --quiet suppress most error messages\n\
226 -v, --verbose explain what is being done\n\
227 -R, --recursive change files and directories recursively\n\
228 --help display this help and exit\n\
229 --version output version information and exit\n\
231 Owner is unchanged if missing. Group is unchanged if missing, but changed\n\
232 to login group if implied by a period. A colon may replace the period.\n"));
238 main (int argc
, char **argv
)
240 uid_t user
= (uid_t
) -1; /* New uid; -1 if not to be changed. */
241 gid_t group
= (uid_t
) -1; /* New gid; -1 if not to be changed. */
246 program_name
= argv
[0];
247 setlocale (LC_ALL
, "");
248 bindtextdomain (PACKAGE
, LOCALEDIR
);
249 textdomain (PACKAGE
);
251 recurse
= force_silent
= verbose
= changes_only
= 0;
253 while ((optc
= getopt_long (argc
, argv
, "Rcfv", long_options
, (int *) 0))
280 printf ("chown - %s\n", version_string
);
287 if (optind
>= argc
- 1)
289 error (0, 0, _("too few arguments"));
293 e
= parse_user_spec (argv
[optind
], &user
, &group
, &username
, &groupname
);
295 error (1, 0, "%s: %s", argv
[optind
], e
);
296 if (username
== NULL
)
299 for (++optind
; optind
< argc
; ++optind
)
301 strip_trailing_slashes (argv
[optind
]);
302 errors
|= change_file_owner (argv
[optind
], user
, group
);