[PATCH] shell: Provide ulimit builtin for ash/hush

Tobias Klauser tklauser at distanz.ch
Fri Mar 5 16:31:27 UTC 2010


Moved from the ulimit builtin from shell/ash.c and slightly adapted.

Signed-off-by: Tobias Klauser <tklauser at distanz.ch>
---
 shell/Kbuild           |    4 +-
 shell/ash.c            |  214 +-----------------------------------------------
 shell/builtin_ulimit.c |  202 +++++++++++++++++++++++++++++++++++++++++++++
 shell/builtin_ulimit.h |   19 ++++
 shell/hush.c           |    4 +-
 5 files changed, 228 insertions(+), 215 deletions(-)
 create mode 100644 shell/builtin_ulimit.c
 create mode 100644 shell/builtin_ulimit.h

diff --git a/shell/Kbuild b/shell/Kbuild
index d8306dc..8b52865 100644
--- a/shell/Kbuild
+++ b/shell/Kbuild
@@ -5,8 +5,8 @@
 # Licensed under the GPL v2, see the file LICENSE in this tarball.
 
 lib-y:=
-lib-$(CONFIG_ASH)      += ash.o ash_ptr_hack.o shell_common.o builtin_read.o
-lib-$(CONFIG_HUSH)     += hush.o match.o shell_common.o builtin_read.o
+lib-$(CONFIG_ASH)      += ash.o ash_ptr_hack.o shell_common.o builtin_read.o builtin_ulimit.o
+lib-$(CONFIG_HUSH)     += hush.o match.o shell_common.o builtin_read.o builtin_ulimit.o
 lib-$(CONFIG_CTTYHACK) += cttyhack.o
 
 lib-$(CONFIG_SH_MATH_SUPPORT) += math.o
diff --git a/shell/ash.c b/shell/ash.c
index 03904bb..e938fa5 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -51,6 +51,7 @@
 
 #include "shell_common.h"
 #include "builtin_read.h"
+#include "builtin_ulimit.h"
 #include "math.h"
 #if ENABLE_ASH_RANDOM_SUPPORT
 # include "random.h"
@@ -12614,219 +12615,10 @@ umaskcmd(int argc UNUSED_PARAM, char **argv)
 	return 0;
 }
 
-/*
- * ulimit builtin
- *
- * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
- * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
- * ash by J.T. Conklin.
- *
- * Public domain.
- */
-struct limits {
-	uint8_t cmd;          /* RLIMIT_xxx fit into it */
-	uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
-	char    option;
-};
-
-static const struct limits limits_tbl[] = {
-#ifdef RLIMIT_CPU
-	{ RLIMIT_CPU,        0, 't' },
-#endif
-#ifdef RLIMIT_FSIZE
-	{ RLIMIT_FSIZE,      9, 'f' },
-#endif
-#ifdef RLIMIT_DATA
-	{ RLIMIT_DATA,      10, 'd' },
-#endif
-#ifdef RLIMIT_STACK
-	{ RLIMIT_STACK,     10, 's' },
-#endif
-#ifdef RLIMIT_CORE
-	{ RLIMIT_CORE,       9, 'c' },
-#endif
-#ifdef RLIMIT_RSS
-	{ RLIMIT_RSS,       10, 'm' },
-#endif
-#ifdef RLIMIT_MEMLOCK
-	{ RLIMIT_MEMLOCK,   10, 'l' },
-#endif
-#ifdef RLIMIT_NPROC
-	{ RLIMIT_NPROC,      0, 'p' },
-#endif
-#ifdef RLIMIT_NOFILE
-	{ RLIMIT_NOFILE,     0, 'n' },
-#endif
-#ifdef RLIMIT_AS
-	{ RLIMIT_AS,        10, 'v' },
-#endif
-#ifdef RLIMIT_LOCKS
-	{ RLIMIT_LOCKS,      0, 'w' },
-#endif
-};
-static const char limits_name[] =
-#ifdef RLIMIT_CPU
-	"time(seconds)" "\0"
-#endif
-#ifdef RLIMIT_FSIZE
-	"file(blocks)" "\0"
-#endif
-#ifdef RLIMIT_DATA
-	"data(kb)" "\0"
-#endif
-#ifdef RLIMIT_STACK
-	"stack(kb)" "\0"
-#endif
-#ifdef RLIMIT_CORE
-	"coredump(blocks)" "\0"
-#endif
-#ifdef RLIMIT_RSS
-	"memory(kb)" "\0"
-#endif
-#ifdef RLIMIT_MEMLOCK
-	"locked memory(kb)" "\0"
-#endif
-#ifdef RLIMIT_NPROC
-	"process" "\0"
-#endif
-#ifdef RLIMIT_NOFILE
-	"nofiles" "\0"
-#endif
-#ifdef RLIMIT_AS
-	"vmemory(kb)" "\0"
-#endif
-#ifdef RLIMIT_LOCKS
-	"locks" "\0"
-#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)
-		out1fmt("unlimited\n");
-	else {
-		val >>= l->factor_shift;
-		out1fmt("%lld\n", (long long) val);
-	}
-}
-
 static int FAST_FUNC
-ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
+ulimitcmd(int argc UNUSED_PARAM, char **argv)
 {
-	rlim_t val;
-	enum limtype how = SOFT | HARD;
-	const struct limits *l;
-	int set, all = 0;
-	int optc, what;
-	struct rlimit limit;
-
-	what = 'f';
-	while ((optc = nextopt("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
-					)) != '\0')
-		switch (optc) {
-		case 'H':
-			how = HARD;
-			break;
-		case 'S':
-			how = SOFT;
-			break;
-		case 'a':
-			all = 1;
-			break;
-		default:
-			what = optc;
-		}
-
-	for (l = limits_tbl; l->option != what; l++)
-		continue;
-
-	set = *argptr ? 1 : 0;
-	val = 0;
-	if (set) {
-		char *p = *argptr;
-
-		if (all || argptr[1])
-			ash_msg_and_raise_error("too many arguments");
-		if (strncmp(p, "unlimited\n", 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)
-				ash_msg_and_raise_error("bad number");
-			val <<= l->factor_shift;
-		}
-	}
-	if (all) {
-		const char *lname = limits_name;
-		for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
-			getrlimit(l->cmd, &limit);
-			out1fmt("%-20s ", lname);
-			lname += strlen(lname) + 1;
-			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)
-			ash_msg_and_raise_error("error setting limit (%m)");
-	} else {
-		printlim(how, &limit, l);
-	}
-	return 0;
+	return shell_builtin_ulimit(argv);
 }
 
 /* ============ main() and helpers */
diff --git a/shell/builtin_ulimit.c b/shell/builtin_ulimit.c
new file mode 100644
index 0000000..2ed7b49
--- /dev/null
+++ b/shell/builtin_ulimit.c
@@ -0,0 +1,202 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ulimit builtin
+ *
+ * Adapted from ash applet code
+ *
+ * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
+ * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
+ * ash by J.T. Conklin.
+ *
+ * Public domain.
+
+ * Copyright (c) 2010 Tobias Klauser
+ * Split from ash.c and slightly adapted.
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+#include "libbb.h"
+#include "builtin_ulimit.h"
+
+#include <string.h>
+#include <errno.h>
+
+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
+			;
+
+int FAST_FUNC shell_builtin_ulimit(char **argv)
+{
+	uint32_t flags;
+	int set, all = 0;
+	int 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: %s", strerror(errno));
+			return EXIT_FAILURE;
+		}
+	} else {
+		printlim(how, &limit, l);
+	}
+
+	return 0;
+}
diff --git a/shell/builtin_ulimit.h b/shell/builtin_ulimit.h
new file mode 100644
index 0000000..ec1af78
--- /dev/null
+++ b/shell/builtin_ulimit.h
@@ -0,0 +1,19 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Adapted from ash applet code
+ *
+ * Copyright (c) 2010 Tobias Klauser
+ * Split from ash.c and slightly adapted.
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+#ifndef SHELL_BUILTIN_ULIMIT_H
+#define SHELL_BUILTIN_ULIMIT_H 1
+
+PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
+
+int FAST_FUNC shell_builtin_ulimit(char **argv);
+
+POP_SAVED_FUNCTION_VISIBILITY
+
+#endif
diff --git a/shell/hush.c b/shell/hush.c
index 0310b02..6f391b8 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
@@ -87,6 +86,7 @@
 
 #include "shell_common.h"
 #include "builtin_read.h"
+#include "builtin_ulimit.h"
 #include "math.h"
 #include "match.h"
 #if ENABLE_HUSH_RANDOM_SUPPORT
@@ -671,7 +671,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"   , shell_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"),
-- 
1.6.3.3



More information about the busybox mailing list