bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

possible new feature for chmod


From: Steve Summit
Subject: possible new feature for chmod
Date: Mon, 04 Aug 2003 12:07:09 -0400

I don't know how the GNU project feels about creeping features
these days.  Once upon a time, at least, the GNU versions of
things were celebrated/notorious for their manifold extensions,
and many of those extensions were useful as "prior art" guiding
the deliberations of various standards bodies and have now
officially adopted.  And of course more recently, much work has
been done to make the GNU utilities fully standards-compliant,
by hook or by crook.  I don't know how interested y'all are these
days in brand new nonstandard extensions.

Be that as it may, I just thought of an extension that chmod
really ought to have; in fact, I don't know why I didn't think
of it a long time ago.  You really ought to be able to say,
for example,

        chmod -rw-rw-r-- file

where that mode string is obviously in the style of ls -l.
This would be useful whenever you wanted to make one file's modes
match another's, since there's no good or standard way to fetch
an existing file's modes in a way that's otherwise acceptable to
chmod as input.

(Yes, I do know about chmod --reference.  The mechanism I'm
proposing here is more general, because it lets you do things
with mode strings which aren't simply derived from local files.
Perhaps you're working with an ls-style mode string which came
from a tar tv listing, or from an ftp dir listing, or something
like that.)

It turns out that this isn't at all difficult to implement.
The attached patch embodies my attempt.  Only one source file
is affected, lib/modechange.c.  (Naturally, this means that the
extended feature is also picked up by the mode-setting options
of the install, mkdir, mkfifo, and mknod programs.  And since
the documentation for those other programs says that they all
accept the same kinds of mode strings that chmod does, if chmod's
set is is expanded, it's appropriate for the others to pick it up.)

This is a nice, tidy extension, seems to work fine and
everything, except -- (why does this always happen?) --
there's one squirrelly little complication, in that the
error handling didn't work out quite the way I expected.

As implemented, this code for parsing rwx- strings accepts
them only if they are exactly 9 or 10 characters long.  (In
the 10-character variant, the leading file-type character is
ignored.)  I was assuming that these strings were so completely
different from the existing chmod mode strings that there would
be no ambiguity.  For example, I assumed that the broken string
-rw-rw-r-, which looks mostly "new style" but is rejected by the
new rwx-parsing code, would also be rejected by the existing code,
leading to an error like "chmod: invalid mode string: `-rw-rw-r-'",
which would be perfectly appropriate.

I hadn't counted, though, on the currently-accepted "generality"
of the traditional-style chmod mode strings.  It turns out that
"-rw-rw-r-" is acceptable as such a string, with (I gather) the
interpretation "turn off rw for all, and rw for all, and r for
all, and nothing for all".  This is pretty meaningless, of
course, but it means that someone who attempts to use one of
the new rwx-style modes, but goofs it up, may not get a useful
error message, but rather a pathologically unexpected mode such
as 000 or 010.

Therefore, I added another little scrap of code to emit a warning
message in the case where a mode string (a) isn't accepted by
the new rwx-style parser, (b) is accepted by the existing parser,
(c) begins with a -, (d) contains at least one other -, but
(e) contains no commas.

(Strictly speaking, this new warning shouldn't appear if
chmod's --silent option is used, but the relevant global
variable `force_silent' isn't present in mkdir and the other
three programs, so it's problematical.  There are various ways
of handling this, perhaps the simplest being to remove the
`static' from force_silent's declaration in chmod.c, declare
"int force_silent;" at the top of modechange.c, and let the old
"common allocation" take care of it, but I'm not going to impose
that on your source tree.)

I also made a few changes to two of the .texi files.  (I'm
appending patches for these below also.)  Besides documenting
the new chmod option, I added a section to {File permissions}
describing the "presentation modes" (that is, the ls-style modes),
since those are really quite different from the "symbolic modes"
as traditionally used by chmod.  (It's these presentation modes
that the documentation for ls -l should reference, not the
"symbolic modes".)

Feel free to use these patches in any way you desire (including
ignoring them, although of course I hope you won't.)  If you
need me to make various formal declarations that the new code
I'm enclosing here was written by me, is free of any copyright
encumbrance, and is released by me for GNU's use, I will
certainly do so.

                        *       *       *

diff -u coreutils-5.0/lib/modechange.c coreutils-5.0.scs/lib/modechange.c
--- coreutils-5.0/lib/modechange.c      Sun Dec  9 17:54:19 2001
+++ coreutils-5.0.scs/lib/modechange.c  Sun Aug  3 13:34:39 2003
@@ -28,14 +28,18 @@
 # include <config.h>
 #endif

+#include "gettext.h"
 #include "modechange.h"
 #include <sys/stat.h>
 #include "xstrtol.h"
+#include "error.h"

 #if STDC_HEADERS
 # include <stdlib.h>
+# include <string.h>
 #else
 char *malloc ();
+char *strchr ();
 #endif

 #ifndef NULL
@@ -154,6 +158,106 @@
     }
 }

+/* Parse a rw-rw-r-- style string, i.e. as built by mode_string()
+   in filemode.c, turning it back into an octal mode string.
+   (Note that the octal string is built in terms of the "traditional"
+   bit values RUSR, WUSR, XUSR, etc., not necessarily the official
+   values S_IRUSR, S_IWUSR, S_IXUSR, etc.  But the code in mode_compile()
+   will perform the appropriate translation if necessary.)
+   Return nonzero if successful.
+   */
+
+static int
+rwx_compile (const char *mode_string, unsigned long *octal_value)
+{
+  unsigned long retval = 0;
+  int len = strlen (mode_string);
+  const char *p = mode_string;
+  int i;
+
+  if (len < 9 || len > 10)
+    return 0;
+
+  if (len == 10)
+    {
+    /* could check first char for "validity", but too hard to keep up-to-date 
*/
+    /* (see list in ftypelet() in filemode.c) */
+    p++;
+    }
+
+    for (i = 0; i < 3; i++)
+      {
+      switch (*p)
+       {
+       case 'r':
+         retval |= RUSR >> i * 3;
+         break;
+
+       case '-':
+         break;
+
+       default:
+         return 0;
+       }
+
+      p++;
+
+      switch (*p)
+       {
+       case 'w':
+         retval |= WUSR >> i * 3;
+         break;
+
+       case '-':
+         break;
+
+       default:
+         return 0;
+       }
+
+      p++;
+
+      switch (*p)
+       {
+       case 'x':
+         retval |= XUSR >> i * 3;
+         break;
+
+       case 's':
+         retval |= XUSR >> i * 3;
+         /* fallthrough */
+       case 'S':
+         switch (i)
+           {
+           case 0: retval |= SUID; break;
+           case 1: retval |= SGID; break;
+           case 2: return 0;
+           }
+         break;
+
+       case 't':
+         retval |= XUSR >> i * 3;
+         /* fallthrough */
+       case 'T':
+         if (i != 2)
+           return 0;
+         retval |= SVTX;
+         break;
+
+       case '-':
+         break;
+
+       default:
+         return 0;
+       }
+
+      p++;
+      }
+
+  *octal_value = retval;
+  return 1;
+}
+
 /* Return a linked list of file mode change operations created from
    MODE_STRING, an ASCII string that contains either an octal number
    specifying an absolute mode, or symbolic mode change operations with
@@ -170,6 +274,7 @@
 struct mode_change *
 mode_compile (const char *mode_string, unsigned int masked_ops)
 {
+  const char *orig_mode_string = mode_string;
   struct mode_change *head;    /* First element of the linked list. */
   struct mode_change *tail;    /* An element of the linked list. */
   unsigned long octal_value;   /* The mode value, if octal.  */
@@ -180,7 +285,8 @@
   tail = NULL;
 #endif

-  if (xstrtoul (mode_string, NULL, 8, &octal_value, "") == LONGINT_OK)
+  if (xstrtoul (mode_string, NULL, 8, &octal_value, "") == LONGINT_OK ||
+                               rwx_compile (mode_string, &octal_value))
     {
       struct mode_change *p;
       mode_t mode;
@@ -357,6 +463,18 @@
        no_more_values:;
        }
   } while (*mode_string == ',');
+
+  /* Firewall to check for invalid rwx-style strings which were nonetheless
+     parsed -- though probably not as intended -- as "normal" chmod strings.
+     Example: -rw-rw-r- */
+
+  if (*orig_mode_string == '-' && strchr (orig_mode_string+1, '-') != NULL &&
+                               strchr (orig_mode_string, ',') == NULL)
+    {
+    error (0, 0, gettext("warning: ambiguous/degenerate mode string \"%s\""),
+                                                       orig_mode_string);
+    }
+
   if (*mode_string == 0)
     return head;
 invalid:

diff -u coreutils-5.0/doc/coreutils.texi coreutils-5.0.scs/doc/coreutils.texi
--- coreutils-5.0/doc/coreutils.texi    Wed Apr  2 13:19:11 2003
+++ coreutils-5.0.scs/doc/coreutils.texi        Sun Aug  3 15:10:03 2003
@@ -420,7 +420,8 @@
 File permissions

 * Mode Structure::               Structure of File Permissions
-* Symbolic Modes::               Mnemonic permissions representation
+* Presentation Modes::           Display of permissions by ls and other 
programs
+* Symbolic Modes::               Mnemonic representation for setting 
permissions
 * Numeric Modes::                Permissions as octal numbers

 Date input formats
@@ -5174,8 +5175,8 @@
 this is arguably a deficiency.

 @cindex permissions, output by @command{ls}
-The permissions listed are similar to symbolic mode specifications
-(@pxref{Symbolic Modes}).  But @command{ls} combines multiple bits into the
+The permissions are presented in symbolic form (@pxref{Presentation Modes}).
+But @command{ls} combines multiple bits into the
 third character of each set of permissions as follows:
 @table @samp
 @item s
@@ -7707,7 +7708,9 @@
 In contrast, @command{chmod} ignores symbolic links encountered during
 recursive directory traversals.

-If used, @var{mode} specifies the new permissions.
+If used, @var{mode} specifies the new permissions,
+either as an octal number, a symbolic mode string,
+or an ls-style mode string.
 For details, see the section on @ref{File permissions}.

 The program accepts the following options.  Also see @ref{Common options}.

diff -u coreutils-5.0/doc/perm.texi coreutils-5.0.scs/doc/perm.texi
--- coreutils-5.0/doc/perm.texi Sat Feb  8 15:31:28 2003
+++ coreutils-5.0.scs/doc/perm.texi     Sun Aug  3 14:57:22 2003
@@ -1,11 +1,13 @@
 Each file has a set of @dfn{permissions} that control the kinds of
 access that users have to that file.  The permissions for a file are
-also called its @dfn{access mode}.  They can be represented either in
-symbolic form or as an octal number.
+also called its @dfn{access mode}.  They can be represented
+in several symbolic forms
+or as an octal number.

 @menu
 * Mode Structure::              Structure of file permissions.
-* Symbolic Modes::              Mnemonic permissions representation.
+* Presentation Modes::          Display of permissions by ls and other 
programs.
+* Symbolic Modes::              Mnemonic representation for setting 
permissions.
 * Numeric Modes::               Permissions as octal numbers.
 @end menu

@@ -108,6 +110,65 @@
 For example, if the immutable attribute is set on a file,
 it cannot be modified, regardless of the fact that you
 may have just run @code{chmod a+w FILE}.
+
address@hidden Presentation Modes
address@hidden Presentation Modes
+
address@hidden presentation modes
+The modes of files are traditionally displayed as 9- or
+10-character strings of the form
+
address@hidden
+-rw-rw-r--
address@hidden example
+
+This style was first introduced by the ls program(@pxref{Directory listing}),
+but is also used by many other programs
+that have occasion to describe a file's modes.
+
+The first character (if present) describes the type of the file.
+The next three characters describe the read, write, and
+executability permissions for the file's owner.
+The next three characters describe the permissions for users in the file's 
group,
+and the last three characters describe the permissions for everyone else.
+
+Within each of the following three groups of three characters,
+the first character is `r' if the file is readable and '-' if it is not.
+The second character is `w' if the file is writable and '-' if it is not.
+Finally, the third character is `x' if the file is executable
+and '-' if it is not.
+
+Under some circumstances,
+the third character in a group may also take on a few special values.
+In the first group, if the third character is `s' it means that
+the file's set-user-id bit is set.
+In the second group, if the third character is `s' it means that
+the file's set-group-id bit is set.
+In the third group, if the third character is `t' it means that
+the file's save-text bit is set.
+(Also, a capital `S' or `T' indicates that the special bit is set
+although the corresponding executable bit is @emph{not} set.)
+
+In the 9-character form, the initial file-type character is not shown.
+In the 10-character form, the first character is `-' for a regular file,
+or one of the following characters for a special file:
+
address@hidden @samp
address@hidden d
+directory
address@hidden l
+symbolic link
address@hidden b
+block-special device
address@hidden c
+character-special device
address@hidden s
+socket
address@hidden p
+fifo
address@hidden table
+
+(Some systems may have additional file types besides those listed here.)

 @node Symbolic Modes
 @section Symbolic Modes




reply via email to

[Prev in Thread] Current Thread [Next in Thread]