SCCS-vsn: bin/chmod/chmod.1 8.3
SCCS-vsn: bin/chmod/chmod.c 8.4
.\"
.\" %sccs.include.redist.roff%
.\"
.\"
.\" %sccs.include.redist.roff%
.\"
-.\" @(#)chmod.1 8.2 (Berkeley) %G%
+.\" @(#)chmod.1 8.3 (Berkeley) %G%
.Nd change file modes
.Sh SYNOPSIS
.Nm chmod
.Nd change file modes
.Sh SYNOPSIS
.Nm chmod
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
.Ar mode
.Ar file ...
.Sh DESCRIPTION
.Ar mode
.Ar file ...
.Sh DESCRIPTION
The options are as follows:
.Bl -tag -width Ds
.It Fl H
The options are as follows:
.Bl -tag -width Ds
.It Fl H
-When encountering a symbolic link on the command line, follow it. All other
-symbolic links encountered in the traversal are not followed.
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
-Traverse a file hierarchy.
-For each file that is of type directory,
-.Nm chmod
-changes the mode of all files in the file hierarchy below it followed
-by the mode of the directory itself.
-.It Fl h
-When encountering a symbolic link anywhere in the traversal, follow it.
+Change the modes of the file hierarchies rooted in the files
+instead of just the files themselves.
-The mode of a symbolic link is immutable, so unless the
-.Fl h
-or
+Symbolic links do not have modes, so unless the
+or
+.Fl L
+option is set,
.Nm chmod
on a symbolic link is a no-op.
.Nm chmod
on a symbolic link is a no-op.
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
.Pp
Only the owner of a file or the super-user is permitted to change
the mode of a file.
.Pp
Only the owner of a file or the super-user is permitted to change
the mode of a file.
.It Li 755
.It Li u=rwx,go=rx
.It Li u=rwx,go=u-w
.It Li 755
.It Li u=rwx,go=rx
.It Li u=rwx,go=u-w
-make a file readable/executable by everyone and writeable by the owner only.
+make a file readable/executable by everyone and writable by the owner only.
.Pp
.It Li go=
clear all mode bits for group and others.
.Pp
.It Li go=
clear all mode bits for group and others.
#endif /* not lint */
#ifndef lint
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)chmod.c 8.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)chmod.c 8.4 (Berkeley) %G%";
#endif /* not lint */
#include <sys/types.h>
#endif /* not lint */
#include <sys/types.h>
register FTSENT *p;
register int oct, omode;
mode_t *set;
register FTSENT *p;
register int oct, omode;
mode_t *set;
- int ch, fflag, rflag, hflag, Hflag;
- int fts_options, retval;
+ int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval;
- fts_options = FTS_PHYSICAL;
- fflag = rflag = hflag = Hflag = 0;
- while ((ch = getopt(argc, argv, "HRXfghorstuwx")) != EOF)
+ Hflag = Lflag = Pflag = Rflag = fflag = hflag = 0;
+ while ((ch = getopt(argc, argv, "HLPRXfgorstuwx")) != EOF)
switch (ch) {
case 'H':
Hflag = 1;
switch (ch) {
case 'H':
Hflag = 1;
- fts_options |= FTS_COMFOLLOW;
+ Lflag = Pflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = Pflag = 0;
+ break;
+ case 'P':
+ Pflag = 1;
+ Hflag = Lflag = 0;
- case 'f': /* XXX: no longer documented. */
+ case 'f': /* XXX: undocumented. */
fflag = 1;
break;
case 'h':
fflag = 1;
break;
case 'h':
+ /*
+ * In System V (and probably POSIX.2) the -h option
+ * causes chmod to change the mode of the symbolic
+ * link. 4.4BSD's symbolic links don't have modes,
+ * so it's an undocumented noop. Do syntax checking,
+ * though.
+ */
- fts_options &= ~FTS_PHYSICAL;
- fts_options |= FTS_LOGICAL;
+ fts_options = FTS_PHYSICAL;
+ if (Rflag) {
+ if (hflag)
+ errx(1,
+ "the -R and -h options may not be specified together.");
+ if (Hflag)
+ fts_options |= FTS_COMFOLLOW;
+ if (Lflag) {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+ }
+
mode = *argv;
if (*mode >= '0' && *mode <= '7') {
omode = (int)strtol(mode, &ep, 8);
mode = *argv;
if (*mode >= '0' && *mode <= '7') {
omode = (int)strtol(mode, &ep, 8);
if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
- err(1, "");
- while ((p = fts_read(ftsp)) != NULL)
+ err(1, NULL);
+ for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
switch (p->fts_info) {
case FTS_D:
switch (p->fts_info) {
case FTS_D:
- if (!rflag)
- fts_set(ftsp, p, FTS_SKIP);
- case FTS_SL:
- case FTS_SLNONE:
+ if (Rflag) /* Change it at FTS_DP. */
+ continue;
+ fts_set(ftsp, p, FTS_SKIP);
+ break;
+ case FTS_DC: /* Ignore. */
+ continue;
+ case FTS_DNR: /* Warn, chmod, continue. */
+ errno = p->fts_errno;
+ warn("%s", p->fts_path);
+ rval = 1;
- case FTS_DNR:
- case FTS_ERR:
+ case FTS_ERR: /* Warn, continue. */
- err(1, "%s", p->fts_path);
- default:
- if (p->fts_info == FTS_SL && !(hflag ||
- (Hflag && p->fts_level == FTS_ROOTLEVEL)))
- continue;
- if (chmod(p->fts_accpath, oct ? omode :
- getmode(set, p->fts_statp->st_mode)) && !fflag) {
- warn(p->fts_path);
- retval = 1;
- }
+ errno = p->fts_errno;
+ warn("%s", p->fts_path);
+ rval = 1;
+ continue;
+ case FTS_SL: /* Ignore. */
+ case FTS_SLNONE:
+ /*
+ * The only symlinks that end up here are ones that
+ * don't point to anything and ones that we found
+ * doing a physical walk.
+ */
+ continue;
+ default:
+ if (chmod(p->fts_accpath, oct ? omode :
+ getmode(set, p->fts_statp->st_mode)) && !fflag) {
+ warn(p->fts_path);
+ rval = 1;
+ }
+ }
+ exit(rval);
- (void)fprintf(stderr, "usage: chmod [-HRh] mode file ...\n");
+ (void)fprintf(stderr,
+ "usage: chmod [-R [-H | -L | -P]] mode file ...\n");