diff --git a/coreutils/chmod.c b/coreutils/chmod.c index 5ee45b942..a21c6d501 100644 --- a/coreutils/chmod.c +++ b/coreutils/chmod.c @@ -69,9 +69,9 @@ static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, void if (S_ISLNK(statbuf->st_mode)) return TRUE; } - newmode = statbuf->st_mode; - if (!bb_parse_mode((char *)param, &newmode)) + newmode = bb_parse_mode((char *)param, statbuf->st_mode); + if (newmode == (mode_t)-1) bb_error_msg_and_die("invalid mode '%s'", (char *)param); if (chmod(fileName, newmode) == 0) { diff --git a/coreutils/install.c b/coreutils/install.c index 73f9c70d5..8aa51cc34 100644 --- a/coreutils/install.c +++ b/coreutils/install.c @@ -159,7 +159,7 @@ int install_main(int argc, char **argv) } mode = 0755; /* GNU coreutils 6.10 compat */ if (opts & OPT_MODE) - bb_parse_mode(mode_str, &mode); + mode = bb_parse_mode(mode_str, mode); uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid(); gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid(); diff --git a/coreutils/libcoreutils/getopt_mk_fifo_nod.c b/coreutils/libcoreutils/getopt_mk_fifo_nod.c index 222717149..47375ff91 100644 --- a/coreutils/libcoreutils/getopt_mk_fifo_nod.c +++ b/coreutils/libcoreutils/getopt_mk_fifo_nod.c @@ -33,7 +33,9 @@ mode_t FAST_FUNC getopt_mk_fifo_nod(char **argv) int opt; opt = getopt32(argv, "m:" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); if (opt & 1) { - if (bb_parse_mode(smode, &mode)) + mode = bb_parse_mode(smode, mode); + if (mode != (mode_t)-1) /* if mode is valid */ + /* make future mknod/mkfifo set mode bits exactly */ umask(0); } diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c index 864edfb0a..6f7b004dd 100644 --- a/coreutils/mkdir.c +++ b/coreutils/mkdir.c @@ -71,8 +71,8 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv) #endif opt = getopt32(argv, "m:pv" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); if (opt & 1) { - mode_t mmode = 0777; - if (!bb_parse_mode(smode, &mmode)) { + mode_t mmode = bb_parse_mode(smode, 0777); + if (mmode == (mode_t)-1) { bb_error_msg_and_die("invalid mode '%s'", smode); } mode = mmode; diff --git a/findutils/find.c b/findutils/find.c index ced8922e7..f72cad7d1 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -1261,7 +1261,8 @@ static action*** parse_params(char **argv) ap->perm_char = arg1[0]; arg1 = (arg1[0] == '/' ? arg1+1 : plus_minus_num(arg1)); /*ap->perm_mask = 0; - ALLOC_ACTION did it */ - if (!bb_parse_mode(arg1, &ap->perm_mask)) + ap->perm_mask = bb_parse_mode(arg1, ap->perm_mask); + if (ap->perm_mask == (mode_t)-1) bb_error_msg_and_die("invalid mode '%s'", arg1); } #endif diff --git a/include/libbb.h b/include/libbb.h index 543214ea4..d79843a2d 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1251,7 +1251,8 @@ char *bb_ask_stdin(const char * prompt) FAST_FUNC; char *bb_ask(const int fd, int timeout, const char * prompt) FAST_FUNC; int bb_ask_confirmation(void) FAST_FUNC; -int bb_parse_mode(const char* s, mode_t* theMode) FAST_FUNC; +/* Returns -1 if input is invalid. current_mode is a base for e.g. "u+rw" */ +int bb_parse_mode(const char* s, unsigned cur_mode) FAST_FUNC; /* * Config file parser diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c index 5a4e1c579..bddd39bca 100644 --- a/libbb/parse_mode.c +++ b/libbb/parse_mode.c @@ -15,7 +15,7 @@ #define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) -int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) +int FAST_FUNC bb_parse_mode(const char *s, unsigned current_mode) { static const mode_t who_mask[] = { S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */ @@ -46,13 +46,12 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) tmp = strtoul(s, &e, 8); if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */ - return 0; + return -1; } - *current_mode = tmp; - return 1; + return tmp; } - new_mode = *current_mode; + new_mode = current_mode; /* Note: we allow empty clauses, and hence empty modes. * We treat an empty mode as no change to perms. */ @@ -71,7 +70,7 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) if (*p == *s) { wholist |= who_mask[(int)(p-who_chars)]; if (!*++s) { - return 0; + return -1; } goto WHO_LIST; } @@ -80,7 +79,7 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) do { /* Process action list. */ if ((*s != '+') && (*s != '-')) { if (*s != '=') { - return 0; + return -1; } /* Since op is '=', clear all bits corresponding to the * wholist, or all file bits if wholist is empty. */ @@ -145,6 +144,5 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) } while (*s && (*s != ',')); } - *current_mode = new_mode; - return 1; + return new_mode; } diff --git a/shell/ash.c b/shell/ash.c index 80dfc1d6a..ab8ec006f 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12862,7 +12862,8 @@ umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ if (!isdigit(modestr[0])) mask ^= 0777; - if (!bb_parse_mode(modestr, &mask) || (unsigned)mask > 0777) { + mask = bb_parse_mode(modestr, mask); + if ((unsigned)mask > 0777) { ash_msg_and_raise_error("illegal mode: %s", modestr); } if (!isdigit(modestr[0])) diff --git a/shell/hush.c b/shell/hush.c index 8b8d5fc8b..bccd9c1e9 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -8965,6 +8965,7 @@ static int FAST_FUNC builtin_umask(char **argv) int rc; mode_t mask; + rc = 1; mask = umask(0); argv = skip_dash_dash(argv); if (argv[0]) { @@ -8974,19 +8975,19 @@ static int FAST_FUNC builtin_umask(char **argv) /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ if (!isdigit(argv[0][0])) mask ^= 0777; - rc = bb_parse_mode(argv[0], &mask); + mask = bb_parse_mode(argv[0], mask); if (!isdigit(argv[0][0])) mask ^= 0777; - if (rc == 0 || (unsigned)mask > 0777) { + if ((unsigned)mask > 0777) { mask = old_mask; /* bash messages: * bash: umask: 'q': invalid symbolic mode operator * bash: umask: 999: octal number out of range */ bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]); + rc = 0; } } else { - rc = 1; /* Mimic bash */ printf("%04o\n", (unsigned) mask); /* fall through and restore mask which we set to 0 */ diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 662e8ab38..51781d597 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -406,7 +406,7 @@ static void parse_next_rule(void) } /* 3rd field: mode - device permissions */ - bb_parse_mode(tokens[2], &G.cur_rule.mode); + G.cur_rule.mode = bb_parse_mode(tokens[2], G.cur_rule.mode); /* 4th field (opt): ">|=alias" or "!" to not create the node */ val = tokens[3];