POSIX 1003.2B/D9 symbolic links
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Fri, 1 Apr 1994 07:32:04 +0000 (23:32 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Fri, 1 Apr 1994 07:32:04 +0000 (23:32 -0800)
SCCS-vsn: bin/chmod/chmod.1 8.3
SCCS-vsn: bin/chmod/chmod.c 8.4

usr/src/bin/chmod/chmod.1
usr/src/bin/chmod/chmod.c

index 0d6cccb..f129eb2 100644 (file)
@@ -6,7 +6,7 @@
 .\"
 .\" %sccs.include.redist.roff%
 .\"
 .\"
 .\" %sccs.include.redist.roff%
 .\"
-.\"    @(#)chmod.1     8.2 (Berkeley) %G%
+.\"    @(#)chmod.1     8.3 (Berkeley) %G%
 .\"
 .Dd 
 .Dt CHMOD 1
 .\"
 .Dd 
 .Dt CHMOD 1
 .Nd change file modes
 .Sh SYNOPSIS
 .Nm chmod
 .Nd change file modes
 .Sh SYNOPSIS
 .Nm chmod
-.Op Fl HRh
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
 .Ar mode
 .Ar file ...
 .Sh DESCRIPTION
 .Ar mode
 .Ar file ...
 .Sh DESCRIPTION
@@ -30,25 +33,40 @@ operand.
 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.
 .It Fl R
 .It Fl R
-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.
 .El
 .Pp
 .El
 .Pp
-The mode of a symbolic link is immutable, so unless the
-.Fl h
-or
+Symbolic links do not have modes, so unless the
 .Fl H
 .Fl H
-flag is set,
+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.
@@ -216,7 +234,7 @@ already searchable/executable by anyone.
 .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.
index e0f2c9f..17e0b4f 100644 (file)
@@ -12,7 +12,7 @@ static char copyright[] =
 #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>
@@ -37,28 +37,39 @@ main(argc, argv)
        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;
        char *ep, *mode;
 
        char *ep, *mode;
 
-       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;
                        break;
                case 'R':
                        break;
                case 'R':
-                       rflag = 1;
+                       Rflag = 1;
                        break;
                        break;
-               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.
+                        */
                        hflag = 1;
                        hflag = 1;
-                       fts_options &= ~FTS_PHYSICAL;
-                       fts_options |= FTS_LOGICAL;
                        break;
                /*
                 * XXX
                        break;
                /*
                 * XXX
@@ -83,6 +94,19 @@ done:        argv += optind;
        if (argc < 2)
                usage();
 
        if (argc < 2)
                usage();
 
+       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);
@@ -95,38 +119,52 @@ done:      argv += optind;
                oct = 0;
        }
 
                oct = 0;
        }
 
-       retval = 0;
        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;
                        break;
                        break;
-               case FTS_DNR:
-               case FTS_ERR:
+               case FTS_ERR:                   /* Warn, continue. */
                case FTS_NS:
                case FTS_NS:
-                       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:
                        break;
                }
                        break;
                }
-       exit(retval);
+               if (chmod(p->fts_accpath, oct ? omode :
+                   getmode(set, p->fts_statp->st_mode)) && !fflag) {
+                       warn(p->fts_path);
+                       rval = 1;
+               }
+       }
+       exit(rval);
 }
 
 void
 usage()
 {
 }
 
 void
 usage()
 {
-       (void)fprintf(stderr, "usage: chmod [-HRh] mode file ...\n");
+       (void)fprintf(stderr,
+           "usage: chmod [-R [-H | -L | -P]] mode file ...\n");
        exit(1);
 }
        exit(1);
 }