On 03/05/2012 02:27 PM, Bruno Haible wrote: > Then how about using "==" or ":=" to designate the assignment?
That's too fancy. Plain '=' would be better. We can also support notations like '+700' and '-77' to OR-in or AND-out arbitrary masks. This would be a clear and straightforward extension to the existing symbolic modes. Something like the attached patches for gnulib and coreutils, perhaps? If this looks OK I'll add test cases.
modechange: add notations +40, 00440, etc. * lib/modechange.c (mode_compile): Support new notations +40, -40, =440, 00440. See <http://debbugs.gnu.org/8391>. diff --git a/lib/modechange.c b/lib/modechange.c index 4ae90ca..ea46b6c 100644 --- a/lib/modechange.c +++ b/lib/modechange.c @@ -136,6 +136,7 @@ mode_compile (char const *mode_string) /* The array of mode-change directives to be returned. */ struct mode_change *mc; size_t used = 0; + char const *p; if ('0' <= *mode_string && *mode_string < '8') { @@ -143,40 +144,43 @@ mode_compile (char const *mode_string) mode_t mode; mode_t mentioned; + p = mode_string; do { - octal_mode = 8 * octal_mode + *mode_string++ - '0'; + octal_mode = 8 * octal_mode + *p++ - '0'; if (ALLM < octal_mode) return NULL; } - while ('0' <= *mode_string && *mode_string < '8'); + while ('0' <= *p && *p < '8'); - if (*mode_string) + if (*p) return NULL; mode = octal_to_mode (octal_mode); - mentioned = (mode & (S_ISUID | S_ISGID)) | S_ISVTX | S_IRWXUGO; + mentioned = (p - mode_string < 5 + ? (mode & (S_ISUID | S_ISGID)) | S_ISVTX | S_IRWXUGO + : CHMOD_MODE_BITS); return make_node_op_equals (mode, mentioned); } /* Allocate enough space to hold the result. */ { size_t needed = 1; - char const *p; for (p = mode_string; *p; p++) needed += (*p == '=' || *p == '+' || *p == '-'); mc = xnmalloc (needed, sizeof *mc); } - /* One loop iteration for each '[ugoa]*([-+=]([rwxXst]*|[ugo]))+'. */ - for (;; mode_string++) + /* One loop iteration for each + '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=][0-7]+'. */ + for (p = mode_string; ; p++) { /* Which bits in the mode are operated on. */ mode_t affected = 0; /* Turn on all the bits in 'affected' for each group given. */ - for (;; mode_string++) - switch (*mode_string) + for (;; p++) + switch (*p) { default: goto invalid; @@ -199,35 +203,59 @@ mode_compile (char const *mode_string) do { - char op = *mode_string++; + char op = *p++; mode_t value; char flag = MODE_COPY_EXISTING; struct mode_change *change; - switch (*mode_string++) + switch (*p) { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + { + unsigned int octal_mode = 0; + + do + { + octal_mode = 8 * octal_mode + *p++ - '0'; + if (ALLM < octal_mode) + return NULL; + } + while ('0' <= *p && *p < '8'); + + if (affected || (*p && *p != ',')) + return NULL; + affected = CHMOD_MODE_BITS; + value = octal_to_mode (octal_mode); + flag = MODE_ORDINARY_CHANGE; + break; + } + case 'u': /* Set the affected bits to the value of the "u" bits on the same file. */ value = S_IRWXU; + p++; break; case 'g': /* Set the affected bits to the value of the "g" bits on the same file. */ value = S_IRWXG; + p++; break; case 'o': /* Set the affected bits to the value of the "o" bits on the same file. */ value = S_IRWXO; + p++; break; default: value = 0; flag = MODE_ORDINARY_CHANGE; - for (mode_string--;; mode_string++) - switch (*mode_string) + for (;; p++) + switch (*p) { case 'r': value |= S_IRUSR | S_IRGRP | S_IROTH; @@ -262,14 +290,13 @@ mode_compile (char const *mode_string) change->value = value; change->mentioned = (affected ? affected & value : value); } - while (*mode_string == '=' || *mode_string == '+' - || *mode_string == '-'); + while (*p == '=' || *p == '+' || *p == '-'); - if (*mode_string != ',') + if (*p != ',') break; } - if (*mode_string == 0) + if (*p == 0) { mc[used].flag = MODE_DONE; return mc;
chmod: add notations +40, 00440, etc. * NEWS: Document this. * doc/perm.texi (Operator Numeric Modes): New section. (Numeric Modes, Directory Setuid and Setgid): Document new behavior. * src/chmod.c (usage): Document new behavior. (main): Support new options -0, -1, etc. diff --git a/NEWS b/NEWS index 8006669..4f12a62 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,21 @@ GNU coreutils NEWS -*- outline -*- ** New features + As a GNU extension, 'chmod', 'mkdir', and 'install' now accept operators + '-', '+', '=' followed by octal modes; for example, 'chmod +40 FOO' enables + and 'chmod -40 FOO' disables FOO's group-read permissions. Operator + numeric modes can be combined with symbolic modes by separating them with + commas; for example, =0,u+r clears all permissions except for enabling + user-read permissions. Unlike ordinary numeric modes, operator numeric + modes do not preserve directory setuid and setgid bits; for example, + 'chmod =0 FOO' clears all of FOO's permissions, including setuid and setgid. + + Also, ordinary numeric modes with five or more digits no longer preserve + setuid and setgid bits, so that 'chmod 00755 FOO' now clears FOO's setuid + and setgid bits. This allows scripts to be portable to other systems which + lack the GNU extension mentioned previously, and where ordinary numeric + modes do not preserve directory setuid and setgid bits. + dd now accepts the count_bytes, skip_bytes iflags and the seek_bytes oflag, to more easily allow processing portions of a file. diff --git a/doc/perm.texi b/doc/perm.texi index 84f8500..c36f8ac 100644 --- a/doc/perm.texi +++ b/doc/perm.texi @@ -17,6 +17,7 @@ symbolic form or as an octal number. * Mode Structure:: Structure of file mode bits. * Symbolic Modes:: Mnemonic representation of file mode bits. * Numeric Modes:: File mode bits as octal numbers. +* Operator Numeric Modes:: ANDing, ORing, and setting modes octally. * Directory Setuid and Setgid:: Set-user-ID and set-group-ID on directories. @end menu @@ -495,13 +496,16 @@ alternative to giving a symbolic mode, you can give an octal (base 8) number that represents the mode. This number is always interpreted in octal; you do not have to add a leading @samp{0}, as you do in C. Mode @samp{0055} is the same as -mode @samp{55}. +mode @samp{55}. (However, modes of five digits or more, such as +@samp{00055}, are treated specially. @xref{Directory Setuid and Setgid}.) A numeric mode is usually shorter than the corresponding symbolic mode, but it is limited in that normally it cannot take into account the previous file mode bits; it can only set them absolutely. -(As discussed in the next section, the set-user-ID and set-group-ID -bits of directories are an exception to this general limitation.) +The set-user-ID and set-group-ID bits of directories are an exception +to this general limitation; @xref{Directory Setuid and Setgid}. +Also, operator numeric modes can take previous file mode bits into +account; @xref{Operator Numeric Modes}. The permissions granted to the user, to other users in the file's group, @@ -541,6 +545,26 @@ For example, numeric mode @samp{4755} corresponds to symbolic mode @samp{ug=rw,o=r}. Numeric mode @samp{0} corresponds to symbolic mode @samp{a=}. +@node Operator Numeric Modes +@section Operator Numeric Modes + +An operator numeric mode is a numeric mode that is prefixed by a +@samp{-}, @samp{+}, or @samp{=} operator, which has the same +interpretation as in symbolic modes. For example, @samp{+440} enables +read permission for the file's owner and group, @samp{-1} disables +execute permission for other users, and @samp{=600} clears all +permissions that it enables read-write permissions for the file's +owner. Operator numeric modes can be combined with symbolic modes by +separating them with a comma; for example, @samp{=0,u+r} clears all +permissions except for enabling read permission for the file's owner. + +The commands @samp{chmod =755 @var{dir}} and @samp{chmod 755 +@var{dir}} differ in that the former clears the directory @var{dir}'s +setuid and setgid bits, whereas the latter preserves them. +@xref{Directory Setuid and Setgid}. + +Operator numeric modes are a @acronym{GNU} extension. + @node Directory Setuid and Setgid @section Directories and the Set-User-ID and Set-Group-ID Bits @@ -559,8 +583,10 @@ bits of directories. If commands like @command{chmod} and mechanisms would be less convenient and it would be harder to share files. Therefore, a command like @command{chmod} does not affect the set-user-ID or set-group-ID bits of a directory unless the user -specifically mentions them in a symbolic mode, or sets them in -a numeric mode. For example, on systems that support +specifically mentions them in a symbolic mode, or uses an operator +numeric mode such as @samp{=755}, or sets them in a numeric mode, or +clears them in a numeric mode that has five or more octal digits. +For example, on systems that support set-group-ID inheritance: @example @@ -582,20 +608,27 @@ explicitly in the symbolic or numeric modes, e.g.: @example # These commands try to set the set-user-ID # and set-group-ID bits of the subdirectories. -mkdir G H +mkdir G chmod 6755 G -chmod u=rwx,go=rx,a+s H -mkdir -m 6755 I +chmod +6000 G +chmod u=rwx,go=rx,a+s G +mkdir -m 6755 H +mkdir -m +6000 I mkdir -m u=rwx,go=rx,a+s J @end example If you want to try to clear these bits, you must mention them -explicitly in a symbolic mode, e.g.: +explicitly in a symbolic mode, or use a symbolic mode containing +=@var{octal-digits}, or specify a numeric mode with five or more octal +digits, e.g.: @example -# This command tries to clear the set-user-ID +# These commands try to clear the set-user-ID # and set-group-ID bits of the directory D. chmod a-s D +chmod -6000 D +chmod =755 D +chmod 00755 D @end example This behavior is a @acronym{GNU} extension. Portable scripts should diff --git a/src/chmod.c b/src/chmod.c index a134e3f..aa4ac77 100644 --- a/src/chmod.c +++ b/src/chmod.c @@ -398,7 +398,7 @@ With --reference, change the mode of each FILE to that of RFILE.\n\ fputs (VERSION_OPTION_DESCRIPTION, stdout); fputs (_("\ \n\ -Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+'.\n\ +Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=][0-7]+'.\n\ "), stdout); emit_ancillary_info (); } @@ -430,7 +430,8 @@ main (int argc, char **argv) recurse = force_silent = diagnose_surprises = false; while ((c = getopt_long (argc, argv, - "Rcfvr::w::x::X::s::t::u::g::o::a::,::+::=::", + ("Rcfvr::w::x::X::s::t::u::g::o::a::,::+::=::" + "0::1::2::3::4::5::6::7::"), long_options, NULL)) != -1) { @@ -449,6 +450,8 @@ main (int argc, char **argv) case ',': case '+': case '=': + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': /* Support nonportable uses like "chmod -w", but diagnose surprises due to umask confusion. Even though "--", "--r", etc., are valid modes, there is no "case '-'" here since