commit 4bed2006c240fc08a99a22188f8c50155b05907a
Author: FRIGN <[email protected]>
Date:   Thu Mar 5 19:08:28 2015 +0100

    Audit chmod(1)
    
    1) Update manpage, refactor the HLP-section and other wordings.
    2) BUGFIX: If chmod() fails, don't recurse.
    3) Rewrite the arg-loop, fixing several issues:
       BUGFIX: Handle multi-flags (e.g. -RH)
       BUGFIX: Properly handle the termination flag --, error on e.g. --x
       BUGFIX: Error out on an empty flag -.
    4) Refactor logic after the arg-loop, which is now simpler thanks
       to argv-incremention.

diff --git a/README b/README
index d6d6b3f..d4ecd58 100644
--- a/README
+++ b/README
@@ -13,7 +13,7 @@ The following tools are implemented ('*' == finished, '#' == 
UTF-8 support,
 =*  cal             yes                          none
 =*| cat             yes                          none
 =*  chgrp           yes                          none
-=*  chmod           yes                          none
+=*| chmod           yes                          none
 =*  chown           yes                          none
 =*| chroot          non-posix                    none
 =*  cksum           yes                          none
diff --git a/chmod.1 b/chmod.1
index 08ad958..52a2da5 100644
--- a/chmod.1
+++ b/chmod.1
@@ -1,9 +1,9 @@
-.Dd January 17, 2015
+.Dd March 5, 2015
 .Dt CHMOD 1
 .Os sbase
 .Sh NAME
 .Nm chmod
-.Nd change file mode
+.Nd change file modes
 .Sh SYNOPSIS
 .Nm
 .Oo
@@ -14,8 +14,10 @@
 .Ar file ...
 .Sh DESCRIPTION
 .Nm
-changes the file mode of the given
-.Ar files .
+changes the file mode of each
+.Ar file
+to
+.Ar mode .
 .Pp
 If
 .Ar mode
@@ -59,12 +61,13 @@ read | write | execute | setuid and setgid | sticky
 .It Fl R
 Change modes recursively.
 .It Fl H
-Only dereference symbolic links that are passed as command line arguments when
-recursively traversing directories.
+Dereference
+.Ar file
+if it is a symbolic link.
 .It Fl L
-Always dereference symbolic links while recursively traversing directories.
+Dereference all symbolic links.
 .It Fl P
-Don't dereference symbolic links (default).
+Preserve symbolic links. This is the default.
 .El
 .Sh SEE ALSO
 .Xr chgrp 1 ,
diff --git a/chmod.c b/chmod.c
index a29b04a..2436721 100644
--- a/chmod.c
+++ b/chmod.c
@@ -24,8 +24,7 @@ chmodr(const char *path, int depth)
        if (chmod(path, m) < 0) {
                weprintf("chmod %s:", path);
                ret = 1;
-       }
-       if (Rflag)
+       } else if (Rflag)
                recurse(path, chmodr, depth);
 }
 
@@ -40,37 +39,48 @@ main(int argc, char *argv[])
 {
        size_t i;
 
-       argv0 = argv[0];
-       for (i = 1; i < argc && argv[i][0] == '-'; i++) {
-               switch (argv[i][1]) {
-               case 'R':
-                       Rflag = 1;
-                       break;
-               case 'H':
-               case 'L':
-               case 'P':
-                       recurse_follow = argv[i][1];
-                       break;
-               case 'r': case 'w': case 'x': case 's': case 't':
-                       /*
-                        * -[rwxst] are valid modes so do not interpret
-                        * them as options - in any case we are done if
-                        * we hit this case
-                        */
-                       goto done;
-               default:
+       argv0 = *(argv++);
+       argc--;
+       for (; *argv && (*argv)[0] == '-'; argc--, argv++) {
+               if (!(*argv)[1])
                        usage();
+               for (i = 1; (*argv)[i]; i++) {
+                       switch ((*argv)[i]) {
+                       case 'R':
+                               Rflag = 1;
+                               break;
+                       case 'H':
+                       case 'L':
+                       case 'P':
+                               recurse_follow = (*argv)[i];
+                               break;
+                       case 'r': case 'w': case 'x': case 's': case 't':
+                               /* -[rwxst] are valid modes, so we're done */
+                               if (i == 1)
+                                       goto done;
+                               /* fallthrough */
+                       case '-':
+                               /* -- terminator */
+                               if (i == 1 && !(*argv)[i + 1]) {
+                                       argv++;
+                                       argc--;
+                                       goto done;
+                               }
+                               /* fallthrough */
+                       default:
+                               usage();
+                       }
                }
        }
 done:
        mask = getumask();
-       modestr = argv[i];
+       modestr = *argv;
 
-       if (argc - i - 1 < 1)
+       if (argc < 2)
                usage();
 
-       for (++i; i < argc; i++)
-               chmodr(argv[i], 0);
+       for (--argc, ++argv; *argv; argc--, argv++)
+               chmodr(*argv, 0);
 
        return ret;
 }

Reply via email to