Change 5109da9b3e6a898c8e0ad647303a1b375e3d97d3 caused test.test to call
chmod with mode `u+s+s` which passes on the host (where you have a
toybox test but a GNU chmod) but fails on Android where chmod is toybox
too.

Add the missing loop to string_to_mode(), which means this will also
affect other toys, but that seems like a feature (and, for example, GNU
mkdir also accepts a mode like `a=r+w+x`).
---
 lib/lib.c        | 76 +++++++++++++++++++++++++-----------------------
 tests/chmod.test |  1 +
 2 files changed, 41 insertions(+), 36 deletions(-)
From da730f8d8e0555dd4dc5645b2b4f4b15e5542937 Mon Sep 17 00:00:00 2001
From: Elliott Hughes <e...@google.com>
Date: Thu, 3 Dec 2020 14:48:16 -0800
Subject: [PATCH] chmod: support complex modes.

Change 5109da9b3e6a898c8e0ad647303a1b375e3d97d3 caused test.test to call
chmod with mode `u+s+s` which passes on the host (where you have a
toybox test but a GNU chmod) but fails on Android where chmod is toybox
too.

Add the missing loop to string_to_mode(), which means this will also
affect other toys, but that seems like a feature (and, for example, GNU
mkdir also accepts a mode like `a=r+w+x`).
---
 lib/lib.c        | 76 +++++++++++++++++++++++++-----------------------
 tests/chmod.test |  1 +
 2 files changed, 41 insertions(+), 36 deletions(-)

diff --git a/lib/lib.c b/lib/lib.c
index c4e70dfe..ebf85ce0 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -970,48 +970,52 @@ mode_t string_to_mode(char *modestr, mode_t mode)
       umask(amask = umask(0));
     }
 
-    if (!*str || !(s = strchr(hows, *str))) goto barf;
-    if (!(dohow = *(str++))) goto barf;
+    // Repeated "hows" are allowed; something like "a=r+w+s" is valid.
+    if (!*str) goto barf;
+    while (*str) {
+      if (!strchr(hows, *str)) goto barf;
+      if (!(dohow = *(str++))) goto barf;
+
+      while (*str && (s = strchr(whats, *str))) {
+        dowhat |= 1<<(s-whats);
+        str++;
+      }
 
-    while (*str && (s = strchr(whats, *str))) {
-      dowhat |= 1<<(s-whats);
-      str++;
-    }
+      // Convert X to x for directory or if already executable somewhere
+      if ((dowhat&32) &&  (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
 
-    // Convert X to x for directory or if already executable somewhere
-    if ((dowhat&32) &&  (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
+      // Copy mode from another category?
+      if (!dowhat && *str && (s = strchr(whys, *str))) {
+        dowhat = (mode>>(3*(s-whys)))&7;
+        str++;
+      }
 
-    // Copy mode from another category?
-    if (!dowhat && *str && (s = strchr(whys, *str))) {
-      dowhat = (mode>>(3*(s-whys)))&7;
-      str++;
-    }
+      // Are we ready to do a thing yet?
+      if (*str && (str[1] != ',' && !strchr(hows, *str))) goto barf;
 
-    // Are we ready to do a thing yet?
-    if (*str && *(str++) != ',') goto barf;
-
-    // Loop through what=xwrs and who=ogu to apply bits to the mode.
-    for (i=0; i<4; i++) {
-      for (j=0; j<3; j++) {
-        mode_t bit = 0;
-        int where = 1<<((3*i)+j);
-
-        if (amask & where) continue;
-
-        // Figure out new value at this location
-        if (i == 3) {
-          // suid and sticky
-          if (!j) bit = dowhat&16; // o+s = t
-          else if ((dowhat&8) && (dowho&(8|(1<<j)))) bit++;
-        } else {
-          if (!(dowho&(8|(1<<i)))) continue;
-          else if (dowhat&(1<<j)) bit++;
-        }
+      // Loop through what=xwrs and who=ogu to apply bits to the mode.
+      for (i=0; i<4; i++) {
+        for (j=0; j<3; j++) {
+          mode_t bit = 0;
+          int where = 1<<((3*i)+j);
+
+          if (amask & where) continue;
 
-        // When selection active, modify bit
+          // Figure out new value at this location
+          if (i == 3) {
+            // suid and sticky
+            if (!j) bit = dowhat&16; // o+s = t
+            else if ((dowhat&8) && (dowho&(8|(1<<j)))) bit++;
+          } else {
+            if (!(dowho&(8|(1<<i)))) continue;
+            else if (dowhat&(1<<j)) bit++;
+          }
 
-        if (dohow == '=' || (bit && dohow == '-')) mode &= ~where;
-        if (bit && dohow != '-') mode |= where;
+          // When selection active, modify bit
+
+          if (dohow == '=' || (bit && dohow == '-')) mode &= ~where;
+          if (bit && dohow != '-') mode |= where;
+        }
       }
     }
 
diff --git a/tests/chmod.test b/tests/chmod.test
index 9dcf796e..2c8c6b91 100755
--- a/tests/chmod.test
+++ b/tests/chmod.test
@@ -112,6 +112,7 @@ chtest u+s "drwsr-xr-x\n-rwSr--r--\n"
 chtest +s "drwsr-sr-x\n-rwSr-Sr--\n"
 chtest o+s "drwxr-xr-x\n-rw-r--r--\n"
 chtest +t  "drwxr-xr-t\n-rw-r--r-T\n"
+chtest a=r+w+x "drwxrwxrwx\n-rwxrwxrwx\n"
 
 mkdir foo
 ln -s bar foo/baz
-- 
2.29.2.576.ga3fc446d84-goog

_______________________________________________
Toybox mailing list
Toybox@lists.landley.net
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to