Subject: bin/2689: [dM] chmod(1)/setmode(3) symbolic mode improvement
To: None <gnats-bugs@NetBSD.ORG>
From: der Mouse <mouse@Holo.Rodents.Montreal.QC.CA>
List: netbsd-bugs
Date: 08/12/1996 13:14:14
>Number:         2689
>Category:       bin
>Synopsis:       [dM] chmod(1)/setmode(3) symbolic mode improvement
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Mon Aug 12 13:35:02 1996
>Last-Modified:
>Originator:     der Mouse
>Organization:
	Dis-
>Release:        -current sup (1.2 release branch), today, 12 Aug 1996:
>Environment:
	Any
>Description:
	These patches make setmode(3), and therefore chmod(1), accept
	symbolic modes such as are printed by ls(1), with the ability
	to "don't-care" out bits by replacing characters with dots.
	chmod.c needed touching because with these changes, a mode
	argument can begin with --, which confuses getopt(3).
>How-To-Repeat:
	Wish you could take a mode from ls and hand it to chmod.
	Notice you can't.
	Sigh.
>Fix:
	Here's what I've done.  I also did some fiddle edits in
	chmod.1, mostly replacing "``foo''" with ".Dq foo" for various
	values of foo.

--- OLD/bin/chmod/chmod.1	Thu Jan  1 00:00:00 1970
+++ NEW/bin/chmod/chmod.1	Thu Jan  1 00:00:00 1970
@@ -132,7 +132,13 @@
 .Pp
 The symbolic mode is described by the following grammar:
 .Bd -literal -offset indent
-mode         ::= clause [, clause ...]
+mode         ::= ls_mode | op_mode
+ls_mode      ::= ls_r ls_w ls_xs ls_r ls_w ls_xs ls_r ls_w ls_xt
+ls_r         ::= r | \- | .
+ls_w         ::= w | \- | .
+ls_xs        ::= x | s | S | \- | .
+ls_xt        ::= x | t | T | \- | .
+op_mode      ::= clause [, clause ...]
 clause       ::= [who ...] [action ...] last_action
 action       ::= op [perm ...]
 last_action  ::= op [perm ...]
@@ -141,13 +147,35 @@
 perm         ::= r | s | t | w | x | X | u | g | o
 .Ed
 .Pp
+If an
+.Ar ls_mode
+is used, it is simply a symbolic mode such as that printed by
+.Xr ls 1
+with the first character (which indicates the file type) stripped,
+and possibly with some characters replaced by dots, indicating that
+.Nm chmod
+should not change the bit(s) corresponding to that character.  (When using
+this style of symbolic mode, there is no way to, for example, specify the
+group-execute bit's state without specifying the setgid bit's state as well.
+Affecting one of a pair of bits that use the same character without
+affecting the other is simply not possible with an
+.Ar ls_mode . )
+.Pp
 The
 .Ar who
-symbols ``u'', ``g'', and ``o'' specify the user, group, and other parts
+symbols
+.Dq u ,
+.Dq g ,
+and
+.Dq o
+specify the user, group, and other parts
 of the mode bits, respectively.
 The
 .Ar who
-symbol ``a'' is equivalent to ``ugo''.
+symbol
+.Dq a
+is equivalent to
+.Dq ugo .
 .Pp
 .ne 1i
 The
@@ -170,9 +198,13 @@
 execute/search bits are set in the original (unmodified) mode.
 Operations with the
 .Ar perm
-symbol ``X'' are only meaningful in conjunction with the
+symbol
+.Dq X
+are only meaningful in conjunction with the
 .Ar op
-symbol ``+'', and are ignored in all other cases.
+symbol
+.Dq + ,
+and are ignored in all other cases.
 .It u
 The user permission bits in the mode of the original file.
 .It g
@@ -188,7 +220,9 @@
 .It +
 If no value is supplied for
 .Ar perm ,
-the ``+'' operation has no effect.
+the
+.Dq +
+operation has no effect.
 If no value is supplied for
 .Ar who ,
 each permission bit specified in
@@ -203,7 +237,9 @@
 .It \&\-
 If no value is supplied for
 .Ar perm ,
-the ``\-'' operation has no effect.
+the
+.Dq \-
+operation has no effect.
 If no value is supplied for
 .Ar who ,
 each permission bit specified in
@@ -240,15 +276,20 @@
 order specified.
 .Pp
 Operations upon the other permissions only (specified by the symbol
-``o'' by itself), in combination with the
+.Dq o
+by itself), in combination with the
 .Ar perm
-symbols ``s'' or ``t'', are ignored.
+symbols
+.Dq s
+or
+.Dq t ,
+are ignored.
 .Sh EXAMPLES
 .Bl -tag -width "u=rwx,go=u-w" -compact
 .It Li 644
 make a file readable by anyone and writable by the owner only.
 .Pp
-.It Li go-w
+.It Li go\-w
 deny write permission to group and others.
 .Pp
 .It Li =rw,+X
@@ -261,13 +302,18 @@
 .Pp
 .It Li 755
 .It Li u=rwx,go=rx
-.It Li u=rwx,go=u-w
+.It Li u=rwx,go=u\-w
 make a file readable/executable by everyone and writable by the owner only.
 .Pp
+.It Li rw.r\-.\-\-.
+make a file readable by owner and group, writeable by owner only, and do
+not touch the execute, set-ID, or sticky bits.
+.Pp
 .It Li go=
+.It Li ...\-\-\-\-\-\-
 clear all mode bits for group and others.
 .Pp
-.It Li g=u-w
+.It Li g=u\-w
 set the group bits equal to the user bits, but clear the group write bit.
 .El
 .Sh BUGS
@@ -293,5 +339,7 @@
 symbols
 .Dq t
 and
-.Dq X
-which are not included in that standard.
+.Dq X ,
+and the
+.Ar ls_mode
+specifications, which are not included in that standard.
--- OLD/bin/chmod/chmod.c	Thu Jan  1 00:00:00 1970
+++ NEW/bin/chmod/chmod.c	Thu Jan  1 00:00:00 1970
@@ -125,6 +125,14 @@
 done:	argv += optind;
 	argc -= optind;
 
+	/* If we have a mode beginning with --, like --x--x--x,
+	   getopt will mistake it for a -- end-of-flags indicator. */
+	if ( (argv[-1][0] == '-') &&
+	     (argv[-1][1] == '-') &&
+	     (strlen(argv[-1]) == 9) ) {
+		argc ++;
+		argv --;
+	}
 	if (argc < 2)
 		usage();
 
--- OLD/lib/libc/gen/setmode.c	Thu Jan  1 00:00:00 1970
+++ NEW/lib/libc/gen/setmode.c	Thu Jan  1 00:00:00 1970
@@ -168,6 +168,74 @@
 
 #define	STANDARD_BITS	(S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
 
+static int ls_mode_p(const char *s, int *setp, int *clrp)
+{
+ /* N, ch1, set1, clr1, ch2, set2, clr2, ... chN, setN, clrN,
+    repeated once per character in the mode.  N==0 signals end. */
+ static int prog[] = { 3, 'r', S_IRUSR, 0,
+			  '-', 0, S_IRUSR,
+			  '.', 0, 0,
+		       3, 'w', S_IWUSR, 0,
+			  '-', 0, S_IWUSR,
+			  '.', 0, 0,
+		       5, 'x', S_IXUSR, S_ISUID,
+			  's', S_IXUSR|S_ISUID, 0,
+			  'S', S_ISUID, S_IXUSR,
+			  '-', 0, S_IXUSR|S_ISUID,
+			  '.', 0, 0,
+		       3, 'r', S_IRGRP, 0,
+			  '-', 0, S_IRGRP,
+			  '.', 0, 0,
+		       3, 'w', S_IWGRP, 0,
+			  '-', 0, S_IWGRP,
+			  '.', 0, 0,
+		       5, 'x', S_IXGRP, S_ISGID,
+			  's', S_IXGRP|S_ISGID, 0,
+			  'S', S_ISGID, S_IXGRP,
+			  '-', 0, S_IXGRP|S_ISGID,
+			  '.', 0, 0,
+		       3, 'r', S_IROTH, 0,
+			  '-', 0, S_IROTH,
+			  '.', 0, 0,
+		       3, 'w', S_IWOTH, 0,
+			  '-', 0, S_IWOTH,
+			  '.', 0, 0,
+		       5, 'x', S_IXOTH, S_ISTXT,
+			  't', S_IXOTH|S_ISTXT, 0,
+			  'T', S_ISTXT, S_IXOTH,
+			  '-', 0, S_IXOTH|S_ISTXT,
+			  '.', 0, 0,
+		       0 };
+ int *pp;
+ int n;
+ int mset;
+ int mclr;
+ int bad;
+
+ pp = &prog[0];
+ mset = 0;
+ mclr = 0;
+ while (1)
+  { n = *pp++;
+    if (n == 0)
+     { if (*s) return(0);
+       *setp = mset;
+       *clrp = mclr;
+       return(1);
+     }
+    bad = 1;
+    for (;n>0;n--,pp+=3)
+     { if (*s == pp[0])
+	{ mset |= pp[1];
+	  mclr |= pp[2];
+	  bad = 0;
+	}
+     }
+    if (bad) return(0);
+    s ++;
+  }
+}
+
 void *
 setmode(p)
 	register char *p;
@@ -178,6 +246,7 @@
 	sigset_t sigset, sigoset;
 	mode_t mask;
 	int equalopdone, permXbits, setlen;
+	int permset, permclr;
 
 	if (!*p)
 		return (NULL);
@@ -217,6 +286,15 @@
 				return (NULL);
 			}
 		ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
+		return (saveset);
+	}
+
+	/*
+	 * Check for ls-style symbolic modes.
+	 */
+	if (ls_mode_p(p,&permset,&permclr)) {
+		ADDCMD('+', STANDARD_BITS|S_ISTXT, permset, 0);
+		ADDCMD('-', STANDARD_BITS|S_ISTXT, permclr, 0);
 		return (saveset);
 	}
 

					der Mouse

			    mouse@collatz.mcrcim.mcgill.edu
		    01 EE 31 F6 BB 0C 34 36  00 F3 7C 5A C1 A0 67 1D
>Audit-Trail:
>Unformatted:
		$NetBSD: chmod.c,v 1.12 1995/03/21 09:02:09 cgd Exp $
		$NetBSD: chmod.1,v 1.8 1995/03/21 09:02:07 cgd Exp $
		$NetBSD: setmode.c,v 1.13 1996/04/03 19:49:01 jtc Exp $