diff options
author | Joshua M. Clulow <jmc@joyent.com> | 2016-09-27 11:38:30 -0700 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2017-03-23 01:01:14 +0000 |
commit | 401bc9af09d3e2bcb61df16867750651ccb30004 (patch) | |
tree | d637032fdb75429a173b0238fb867f688494749c /usr/src/uts/common/fs/tmpfs/tmp_subr.c | |
parent | 7909625fdb7ecb20e9b7a777cfc0ec7ee63b4642 (diff) | |
download | illumos-gate-401bc9af09d3e2bcb61df16867750651ccb30004.tar.gz |
7752 tmpfs should support gigabyte sizes
7753 tmpfs should support "mode" option
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Approved by: Dan McDonald <danmcd@omniti.com>
Diffstat (limited to 'usr/src/uts/common/fs/tmpfs/tmp_subr.c')
-rw-r--r-- | usr/src/uts/common/fs/tmpfs/tmp_subr.c | 127 |
1 files changed, 86 insertions, 41 deletions
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_subr.c b/usr/src/uts/common/fs/tmpfs/tmp_subr.c index 2e59d28d80..0a3c07b381 100644 --- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2015 Joyent, Inc. */ #include <sys/types.h> @@ -40,9 +41,17 @@ #include <sys/policy.h> #include <sys/fs/tmp.h> #include <sys/fs/tmpnode.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#define KILOBYTE 1024 +#define MEGABYTE (1024 * KILOBYTE) +#define GIGABYTE (1024 * MEGABYTE) #define MODESHIFT 3 +#define VALIDMODEBITS 07777 + int tmp_taccess(void *vtp, int mode, struct cred *cred) { @@ -71,7 +80,6 @@ tmp_taccess(void *vtp, int mode, struct cred *cred) * a plain file and you have write access to that file. * Function returns 0 if remove access is granted. */ - int tmp_sticky_remove_access(struct tmpnode *dir, struct tmpnode *entry, struct cred *cr) @@ -128,70 +136,81 @@ tmp_memfree(void *cp, size_t size) * maximum value encoded in 'str' is PAGESIZE * ULONG_MAX, while the value * returned in 'maxpg' is at most ULONG_MAX. * - * If the number is followed by a "k" or "K", the value is converted from - * kilobytes to bytes. If it is followed by an "m" or "M" it is converted - * from megabytes to bytes. If it is not followed by a character it is - * assumed to be in bytes. Multiple letter options are allowed, so for instance - * '2mk' is interpreted as 2gb. + * The number may be followed by a magnitude suffix: "k" or "K" for kilobytes; + * "m" or "M" for megabytes; "g" or "G" for gigabytes. This interface allows + * for an arguably esoteric interpretation of multiple suffix characters: + * namely, they cascade. For example, the caller may specify "2mk", which is + * interpreted as 2 gigabytes. It would seem, at this late stage, that the + * horse has left not only the barn but indeed the country, and possibly the + * entire planetary system. * * Parse and overflow errors are detected and a non-zero number returned on * error. */ - int tmp_convnum(char *str, pgcnt_t *maxpg) { - uint64_t num = 0, oldnum; + u_longlong_t num = 0; #ifdef _LP64 - uint64_t max_bytes = ULONG_MAX; + u_longlong_t max_bytes = ULONG_MAX; #else - uint64_t max_bytes = PAGESIZE * (uint64_t)ULONG_MAX; + u_longlong_t max_bytes = PAGESIZE * (uint64_t)ULONG_MAX; #endif char *c; - - if (str == NULL) + const struct convchar { + char *cc_char; + uint64_t cc_factor; + } convchars[] = { + { "kK", KILOBYTE }, + { "mM", MEGABYTE }, + { "gG", GIGABYTE }, + { NULL, 0 } + }; + + if (str == NULL) { return (EINVAL); + } c = str; /* - * Convert str to number + * Convert the initial numeric portion of the input string. */ - while ((*c >= '0') && (*c <= '9')) { - oldnum = num; - num = num * 10 + (*c++ - '0'); - if (oldnum > num) /* overflow */ - return (EINVAL); + if (ddi_strtoull(str, &c, 10, &num) != 0) { + return (EINVAL); } /* - * Terminate on null + * Apply the (potentially cascading) magnitude suffixes until an + * invalid character is found, or the string comes to an end. */ - while (*c != '\0') { - switch (*c++) { + for (; *c != '\0'; c++) { + int i; + + for (i = 0; convchars[i].cc_char != NULL; i++) { + /* + * Check if this character matches this multiplier + * class: + */ + if (strchr(convchars[i].cc_char, *c) != NULL) { + /* + * Check for overflow: + */ + if (num > max_bytes / convchars[i].cc_factor) { + return (EINVAL); + } + + num *= convchars[i].cc_factor; + goto valid_char; + } + } /* - * convert from kilobytes + * This was not a valid multiplier suffix character. */ - case 'k': - case 'K': - if (num > max_bytes / 1024) /* will overflow */ - return (EINVAL); - num *= 1024; - break; + return (EINVAL); - /* - * convert from megabytes - */ - case 'm': - case 'M': - if (num > max_bytes / (1024 * 1024)) /* will overflow */ - return (EINVAL); - num *= 1024 * 1024; - break; - - default: - return (EINVAL); - } +valid_char: + continue; } /* @@ -204,3 +223,29 @@ tmp_convnum(char *str, pgcnt_t *maxpg) return (EINVAL); return (0); } + +/* + * Parse an octal mode string for use as the permissions set for the root + * of the tmpfs mount. + */ +int +tmp_convmode(char *str, mode_t *mode) +{ + ulong_t num; + char *c; + + if (str == NULL) { + return (EINVAL); + } + + if (ddi_strtoul(str, &c, 8, &num) != 0) { + return (EINVAL); + } + + if ((num & ~VALIDMODEBITS) != 0) { + return (EINVAL); + } + + *mode = VALIDMODEBITS & num; + return (0); +} |