Based on the ulimit bultin from shell/ash.c
Signed-off-by: Tobias Klauser <[email protected]>
---
shell/Config.in | 7 ++
shell/hush.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 193 insertions(+), 2 deletions(-)
diff --git a/shell/Config.in b/shell/Config.in
index 3b16506..4bd1cdd 100644
--- a/shell/Config.in
+++ b/shell/Config.in
@@ -243,6 +243,13 @@ config HUSH_RANDOM_SUPPORT
Enable pseudorandom generator and dynamic variable "$RANDOM".
Each read of "$RANDOM" will generate a new pseudorandom value.
+config HUSH_ULIMIT
+ bool "ulimit builtin"
+ default n
+ depends on HUSH
+ help
+ Enable ulimit builtin in hush.
+
config LASH
bool "lash (deprecated: aliased to hush)"
default n
diff --git a/shell/hush.c b/shell/hush.c
index 0310b02..9a06502 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -57,7 +57,6 @@
*
* TODOs:
* grep for "TODO" and fix (some of them are easy)
- * builtins: ulimit
* special variables (done: PWD)
* follow IFS rules more precisely, including update semantics
* export builtin should be special, its arguments are assignments
@@ -613,6 +612,9 @@ static int builtin_continue(char **argv) FAST_FUNC;
#if ENABLE_HUSH_FUNCTIONS
static int builtin_return(char **argv) FAST_FUNC;
#endif
+#ifdef ENABLE_HUSH_ULIMIT
+static int builtin_ulimit(char **argv) FAST_FUNC;
+#endif
/* Table of built-in functions. They can be forked or not, depending on
* context: within pipes, they fork. As simple commands, they do not.
@@ -671,7 +673,7 @@ static const struct built_in_command bltins1[] = {
BLTIN("shift" , builtin_shift , "Shift positional parameters"),
BLTIN("trap" , builtin_trap , "Trap signals"),
BLTIN("type" , builtin_type , "Write a description of command
type"),
-// BLTIN("ulimit" , builtin_ulimit , "Control resource limits"),
+ BLTIN("ulimit" , builtin_ulimit , "Control resource limits"),
BLTIN("umask" , builtin_umask , "Set file creation mask"),
BLTIN("unset" , builtin_unset , "Unset variables"),
BLTIN("wait" , builtin_wait , "Wait for process"),
@@ -8095,3 +8097,185 @@ static int FAST_FUNC builtin_return(char **argv)
return rc;
}
#endif
+
+#if ENABLE_HUSH_ULIMIT
+struct limits {
+ uint8_t cmd; /* RLIMIT_xxx fit into it */
+ uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
+ char option;
+ const char *name;
+};
+
+static const struct limits limits_tbl[] = {
+#ifdef RLIMIT_CPU
+ { RLIMIT_CPU, 0, 't', "cpu time (seconds)" },
+#endif
+#ifdef RLIMIT_FSIZE
+ { RLIMIT_FSIZE, 9, 'f', "file size (blocks)" },
+#endif
+#ifdef RLIMIT_DATA
+ { RLIMIT_DATA, 10, 'd', "data seg size (kb)" },
+#endif
+#ifdef RLIMIT_STACK
+ { RLIMIT_STACK, 10, 's', "stack size (kb)" },
+#endif
+#ifdef RLIMIT_CORE
+ { RLIMIT_CORE, 9, 'c', "core file size (blocks)" },
+#endif
+#ifdef RLIMIT_RSS
+ { RLIMIT_RSS, 10, 'm', "resident set size (kb)" },
+#endif
+#ifdef RLIMIT_MEMLOCK
+ { RLIMIT_MEMLOCK, 10, 'l', "locked memory (kb)" },
+#endif
+#ifdef RLIMIT_NPROC
+ { RLIMIT_NPROC, 0, 'p', "processes" },
+#endif
+#ifdef RLIMIT_NOFILE
+ { RLIMIT_NOFILE, 0, 'n', "file descriptors" },
+#endif
+#ifdef RLIMIT_AS
+ { RLIMIT_AS, 10, 'v', "address space (kb)" },
+#endif
+#ifdef RLIMIT_LOCKS
+ { RLIMIT_LOCKS, 0, 'w', "locks" },
+#endif
+};
+
+enum limtype { SOFT = 0x1, HARD = 0x2 };
+
+static void printlim(enum limtype how, const struct rlimit *limit,
+ const struct limits *l)
+{
+ rlim_t val;
+
+ val = limit->rlim_max;
+ if (how & SOFT)
+ val = limit->rlim_cur;
+
+ if (val == RLIM_INFINITY)
+ printf("unlimited\n");
+ else {
+ val >>= l->factor_shift;
+ printf("%lld\n", (long long) val);
+ }
+}
+
+static const char ulimit_opt_string[] = "!HSa"
+#ifdef RLIMIT_CPU
+ "t"
+#endif
+#ifdef RLIMIT_FSIZE
+ "f"
+#endif
+#ifdef RLIMIT_DATA
+ "d"
+#endif
+#ifdef RLIMIT_STACK
+ "s"
+#endif
+#ifdef RLIMIT_CORE
+ "c"
+#endif
+#ifdef RLIMIT_RSS
+ "m"
+#endif
+#ifdef RLIMIT_MEMLOCK
+ "l"
+#endif
+#ifdef RLIMIT_NPROC
+ "p"
+#endif
+#ifdef RLIMIT_NOFILE
+ "n"
+#endif
+#ifdef RLIMIT_AS
+ "v"
+#endif
+#ifdef RLIMIT_LOCKS
+ "w"
+#endif
+ ;
+
+static int FAST_FUNC builtin_ulimit(char **argv)
+{
+ uint32_t flags;
+ int set, all = 0;
+ enum limtype how = SOFT | HARD;
+ const struct limits *l;
+ rlim_t val;
+ struct rlimit limit;
+
+ l = &limits_tbl[1]; /* default to '-f' */
+ flags = getopt32(argv, ulimit_opt_string);
+ if (flags == (uint32_t)-1)
+ return EXIT_FAILURE;
+ if (flags & 1)
+ how = HARD;
+ if (flags & 2)
+ how = SOFT;
+ if (flags & 4)
+ all = 1;
+
+ if (all && (flags & ~0x7)) {
+ bb_error_msg("ulimit: no limits allowed with -a");
+ return EXIT_FAILURE;
+ }
+
+ flags >>= 3;
+ l = limits_tbl;
+ for ( ; flags; flags >>= 1, l++) {
+ /* Only consider the first matching option */
+ if (flags & 1)
+ break;
+ }
+
+ argv += optind;
+ set = *argv ? 1 : 0;
+ val = 0;
+ if (set) {
+ char *p = *argv;
+
+ if (strncmp(p, "unlimited", 9) == 0)
+ val = RLIM_INFINITY;
+ else {
+ if (sizeof(val) == sizeof(int))
+ val = bb_strtou(p, NULL, 10);
+ else if (sizeof(val) == sizeof(long))
+ val = bb_strtoul(p, NULL, 10);
+ else
+ val = bb_strtoull(p, NULL, 10);
+ if (errno) {
+ bb_error_msg("ulimit: bad number");
+ return EXIT_FAILURE;
+ }
+ val <<= l->factor_shift;
+ }
+ }
+
+ if (all) {
+ for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)];
l++) {
+ getrlimit(l->cmd, &limit);
+ printf("-%c: %-30s ", l->option, l->name);
+ printlim(how, &limit, l);
+ }
+ return 0;
+ }
+
+ getrlimit(l->cmd, &limit);
+ if (set) {
+ if (how & HARD)
+ limit.rlim_max = val;
+ if (how & SOFT)
+ limit.rlim_cur = val;
+ if (setrlimit(l->cmd, &limit) < 0) {
+ bb_error_msg("ulimit: error setting limit");
+ return EXIT_FAILURE;
+ }
+ } else {
+ printlim(how, &limit, l);
+ }
+
+ return 0;
+}
+#endif
--
1.6.3.3
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox