change the -f flag to ONLY mask errors in changing owner/group
new manual page, started from the POSIX.2 manual page
use FTS to walk the tree
SCCS-vsn: usr.sbin/chown/Makefile 5.4
SCCS-vsn: usr.sbin/chown/chown.8 6.4
SCCS-vsn: usr.sbin/chown/chown.c 5.16
-# @(#)Makefile 5.3 (Berkeley) %G%
+# @(#)Makefile 5.4 (Berkeley) %G%
MAN1= chgrp.0
MAN8= chown.0
LINKS= ${BINDIR}/chown /usr/bin/chgrp
MAN1= chgrp.0
MAN8= chown.0
LINKS= ${BINDIR}/chown /usr/bin/chgrp
-.\" Copyright (c) 1980 Regents of the University of California.
-.\" All rights reserved. The Berkeley software License Agreement
-.\" specifies the terms and conditions for redistribution.
+.\" Copyright (c) 1990 The Regents of the University of California.
+.\" All rights reserved.
-.\" @(#)chown.8 6.3 (Berkeley) %G%
+.\" %sccs.include.redist.man%
+.\"
+.\" @(#)chown.8 6.4 (Berkeley) %G%
.\"
.TH CHOWN 8 ""
.UC 4
.SH NAME
.\"
.TH CHOWN 8 ""
.UC 4
.SH NAME
+chown \- change file owner and group
-.B chown
-[
-.B \-Rf
-]
-owner[.group] file ...
+.nf
+.ft B
+chown [-Rf] [owner][:group] file ...
-changes the owner of the
-.I files
-to
-.IR owner .
-The owner may be either a decimal UID or
-a login name found in the password file.
-An optional group may also be specified.
-The group may be either a decimal GID or
-a group name found in the group-ID file.
+sets the user ID and/or the group ID of the specified files.
+.PP
+The options are as follows:
+.TP
+-R
+Change the user ID and/or the group ID for the file hierarchies rooted
+in the files instead of just the files themselves.
+.TP
+-f
+Don't report any failure to change file owner or group, nor modify
+the exit status to reflect such failures.
+.PP
+The
+.I owner
+and
+.I group
+operands are both optional, but at least one must be specified; if
+the group operand is specified, it must be preceded by a colon (``:'')
+character.
-Only the super-user can change owner,
-in order to simplify accounting procedures.
-No errors, except for usage errors, are reported when the
-.B \-f
-(force) option is given.
+The
+.I owner
+should be either a numeric user ID or a user name.
+If a user name is also a numeric user ID, the operand is used as a
+user name.
+The
+.I group
+should be either a numeric group ID or a group name.
+If a group name is also a numeric group ID, the operand is used as a
+group name.
-When the
-.B \-R
-option is given,
+Only the super-user may change the owner of a file in order to
+simplify accounting procedures and to prevent the circumvention
+of system security.
+.PP
+The owner and group of symbolic links are themselves changed instead
+of the file to which the link points.
+.PP
+The
+.I chown
+utility exits 0 on success, and >0 if an error occurs.
+.SH COMPATIBILITY
+Previous versions of the
-recursively descends its directory arguments
-setting the specified owner.
-When symbolic links are encountered, their ownership is changed,
-but they are not traversed.
+utility used the dot (``.'') character to distinguish the group name.
+This has been changed to be a colon (``:'') character so that user and
+group names may contain the dot character.
+chgrp(1), find(1), chown(2)
#endif /* not lint */
#ifndef lint
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)chown.c 5.15 (Berkeley) %G%";
+static char sccsid[] = "@(#)chown.c 5.16 (Berkeley) %G%";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <dirent.h>
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <stdio.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <stdio.h>
#include <ctype.h>
int ischown, uid, gid, fflag, rflag, retval;
char *gname, *myname;
int ischown, uid, gid, fflag, rflag, retval;
char *gname, *myname;
+ register FTS *fts;
+ register FTSENT *p;
register char *cp;
int ch;
register char *cp;
int ch;
- char curpath[MAXPATHLEN], *reset, *index(), *rindex();
myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
ischown = myname[2] == 'o';
myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
ischown = myname[2] == 'o';
while ((ch = getopt(argc, argv, "Rf")) != EOF)
switch((char)ch) {
case 'R':
while ((ch = getopt(argc, argv, "Rf")) != EOF)
switch((char)ch) {
case 'R':
break;
case '?':
default:
break;
case '?':
default:
if (cp = index(*argv, '.')) {
*cp++ = '\0';
setgid(cp);
if (cp = index(*argv, '.')) {
*cp++ = '\0';
setgid(cp);
+ } else
+#endif
+ if (cp = index(*argv, ':')) {
+ *cp++ = '\0';
+ setgid(cp);
+ }
- while (*++argv) {
- if (reset = index(*argv, '/'))
- (void)getwd(curpath);
- change(*argv);
- if (reset && chdir(curpath)) {
- if (fflag)
- exit(0);
- err(curpath);
- exit(-1);
+ if (rflag) {
+ if (!(fts = ftsopen(++argv, FTS_NOSTAT|FTS_PHYSICAL, 0))) {
+ (void)fprintf(stderr,
+ "%s: %s.\n", myname, strerror(errno));
+ exit(1);
+ while (p = ftsread(fts)) {
+ if (p->fts_info == FTS_D)
+ continue;
+ if (p->fts_info == FTS_ERR) {
+ error(p->fts_path);
+ continue;
+ }
+ if (chown(p->fts_accpath, uid, gid) && !fflag)
+ chownerr(p->fts_path);
+ }
+ exit(retval);
+ while (*++argv)
+ if (chown(*argv, uid, gid) && !fflag)
+ chownerr(*argv);
gid = atoi(gname);
else {
if (!(gr = getgrnam(gname))) {
gid = atoi(gname);
else {
if (!(gr = getgrnam(gname))) {
(void)fprintf(stderr, "%s: unknown group id: %s\n",
myname, gname);
(void)fprintf(stderr, "%s: unknown group id: %s\n",
myname, gname);
uid = atoi(beg);
else {
if (!(pwd = getpwnam(beg))) {
uid = atoi(beg);
else {
if (!(pwd = getpwnam(beg))) {
(void)fprintf(stderr,
"chown: unknown user id: %s\n", beg);
(void)fprintf(stderr,
"chown: unknown user id: %s\n", beg);
-change(file)
- char *file;
-{
- register DIR *dirp;
- register struct dirent *dp;
- struct stat buf;
-
- if (chown(file, uid, gid)) {
- chownerr(file);
- return;
- }
- if (!rflag)
- return;
- if (lstat(file, &buf)) {
- err(file);
- return;
- }
- if ((buf.st_mode & S_IFMT) == S_IFDIR) {
- if (chdir(file) < 0 || !(dirp = opendir("."))) {
- err(file);
- return;
- }
- for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
- if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
- dp->d_name[1] == '.' && !dp->d_name[2]))
- continue;
- change(dp->d_name);
- }
- closedir(dirp);
- if (chdir("..")) {
- err("..");
- exit(fflag ? 0 : -1);
- }
- }
-}
-
chownerr(file)
char *file;
{
chownerr(file)
char *file;
{
static int euid = -1, ngroups = -1;
/* check for chown without being root */
if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
if (fflag)
exit(0);
static int euid = -1, ngroups = -1;
/* check for chown without being root */
if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
if (fflag)
exit(0);
+ error(file);
+ exit(1);
}
/* check group membership; kernel just returns EPERM */
if (gid != -1 && ngroups == -1) {
}
/* check group membership; kernel just returns EPERM */
if (gid != -1 && ngroups == -1) {
(void)fprintf(stderr,
"%s: you are not a member of group %s.\n",
myname, gname);
(void)fprintf(stderr,
"%s: you are not a member of group %s.\n",
myname, gname);
+ if (!fflag)
+ error(file);
+error(name)
+ char *name;
- extern int errno;
- char *strerror();
-
- if (fflag)
- return;
- (void)fprintf(stderr, "%s: %s: %s\n", myname, s, strerror(errno));
- retval = -1;
+ (void)fprintf(stderr, "%s: %s: %s\n", myname, name, strerror(errno));
+ retval = 1;
}
usage()
{
(void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
}
usage()
{
(void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
- ischown ? "owner[.group]" : "group");
- exit(-1);
+ ischown ? "[owner][:group]" : "group");
+ exit(1);