summaryrefslogtreecommitdiff
path: root/src/ulimit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ulimit.c')
-rw-r--r--src/ulimit.c360
1 files changed, 360 insertions, 0 deletions
diff --git a/src/ulimit.c b/src/ulimit.c
new file mode 100644
index 0000000..5bdfdd1
--- /dev/null
+++ b/src/ulimit.c
@@ -0,0 +1,360 @@
+/* $OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $ */
+
+/*-
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
+ * 2019, 2020
+ * mirabilos <m@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
+#include "sh.h"
+
+__RCSID("$MirOS: src/bin/mksh/ulimit.c,v 1.3 2020/07/24 21:08:26 tg Exp $");
+
+#define SOFT 0x1
+#define HARD 0x2
+
+#if HAVE_RLIMIT
+
+#if !HAVE_RLIM_T
+typedef unsigned long rlim_t;
+#endif
+
+/* Magic to divine the 'm' and 'v' limits */
+
+#ifdef RLIMIT_AS
+#if !defined(RLIMIT_VMEM) || (RLIMIT_VMEM == RLIMIT_AS) || \
+ !defined(RLIMIT_RSS) || (RLIMIT_VMEM == RLIMIT_RSS)
+#define ULIMIT_V_IS_AS
+#elif defined(RLIMIT_VMEM)
+#if !defined(RLIMIT_RSS) || (RLIMIT_RSS == RLIMIT_AS)
+#define ULIMIT_V_IS_AS
+#else
+#define ULIMIT_V_IS_VMEM
+#endif
+#endif
+#endif
+
+#ifdef RLIMIT_RSS
+#ifdef ULIMIT_V_IS_VMEM
+#define ULIMIT_M_IS_RSS
+#elif defined(RLIMIT_VMEM) && (RLIMIT_VMEM == RLIMIT_RSS)
+#define ULIMIT_M_IS_VMEM
+#else
+#define ULIMIT_M_IS_RSS
+#endif
+#if defined(ULIMIT_M_IS_RSS) && defined(RLIMIT_AS) && \
+ !defined(__APPLE__) && (RLIMIT_RSS == RLIMIT_AS)
+/* On Mac OSX keep -m as -v alias for pkgsrc and other software expecting it */
+#undef ULIMIT_M_IS_RSS
+#endif
+#endif
+
+#if !defined(RLIMIT_AS) && !defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_VMEM)
+#define ULIMIT_V_IS_VMEM
+#endif
+
+#if !defined(ULIMIT_V_IS_VMEM) && defined(RLIMIT_VMEM) && \
+ (!defined(RLIMIT_RSS) || (defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS)))
+#define ULIMIT_M_IS_VMEM
+#endif
+
+#if defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_AS) && \
+ (RLIMIT_VMEM == RLIMIT_AS)
+#undef ULIMIT_M_IS_VMEM
+#endif
+
+#if defined(ULIMIT_M_IS_RSS) && defined(ULIMIT_M_IS_VMEM)
+# error nonsensical m ulimit
+#endif
+
+#if defined(ULIMIT_V_IS_VMEM) && defined(ULIMIT_V_IS_AS)
+# error nonsensical v ulimit
+#endif
+
+#define LIMITS_GEN "rlimits.gen"
+
+#else /* !HAVE_RLIMIT */
+
+#undef RLIMIT_CORE /* just in case */
+
+#if defined(UL_GETFSIZE)
+#define KSH_UL_GFIL UL_GETFSIZE
+#elif defined(UL_GFILLIM)
+#define KSH_UL_GFIL UL_GFILLIM
+#elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST)
+#define KSH_UL_GFIL 1
+#endif
+
+#if defined(UL_SETFSIZE)
+#define KSH_UL_SFIL UL_SETFSIZE
+#elif defined(UL_SFILLIM)
+#define KSH_UL_SFIL UL_SFILLIM
+#elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST)
+#define KSH_UL_SFIL 2
+#endif
+
+#if defined(KSH_UL_SFIL)
+#define KSH_UL_WFIL true
+#else
+#define KSH_UL_WFIL false
+#define KSH_UL_SFIL 0
+#endif
+
+#if defined(UL_GETMAXBRK)
+#define KSH_UL_GBRK UL_GETMAXBRK
+#elif defined(UL_GMEMLIM)
+#define KSH_UL_GBRK UL_GMEMLIM
+#elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST)
+#define KSH_UL_GBRK 3
+#endif
+
+#if defined(UL_GDESLIM)
+#define KSH_UL_GDES UL_GDESLIM
+#elif defined(__GLIBC__) || defined(KSH_ULIMIT2_TEST)
+#define KSH_UL_GDES 4
+#endif
+
+extern char etext;
+extern long ulimit(int, long);
+
+#define LIMITS_GEN "ulimits.gen"
+
+#endif /* !HAVE_RLIMIT */
+
+struct limits {
+ /* limit resource / read command */
+ int resource;
+#if HAVE_RLIMIT
+ /* multiply by to get rlim_{cur,max} values */
+ unsigned int factor;
+#else
+ /* write command */
+ int wesource;
+ /* writable? */
+ bool writable;
+#endif
+ /* getopts char */
+ char optchar;
+ /* limit name */
+ char name[1];
+};
+
+#define RLIMITS_DEFNS
+#if HAVE_RLIMIT
+#define FN(lname,lid,lfac,lopt) \
+ static const struct { \
+ int resource; \
+ unsigned int factor; \
+ char optchar; \
+ char name[sizeof(lname)]; \
+ } rlimits_ ## lid = { \
+ lid, lfac, lopt, lname \
+ };
+#else
+#define FN(lname,lg,ls,lw,lopt) \
+ static const struct { \
+ int rcmd; \
+ int wcmd; \
+ bool writable; \
+ char optchar; \
+ char name[sizeof(lname)]; \
+ } rlimits_ ## lg = { \
+ lg, ls, lw, lopt, lname \
+ };
+#endif
+#include LIMITS_GEN
+
+static void print_ulimit(const struct limits *, int);
+static int set_ulimit(const struct limits *, const char *, int);
+
+static const struct limits * const rlimits[] = {
+#define RLIMITS_ITEMS
+#include LIMITS_GEN
+};
+
+static const char rlimits_opts[] =
+#define RLIMITS_OPTCS
+#include LIMITS_GEN
+#ifndef RLIMIT_CORE
+ "c"
+#endif
+ ;
+
+int
+c_ulimit(const char **wp)
+{
+ size_t i = 0;
+ int how = SOFT | HARD, optc;
+ char what = 'f';
+ bool all = false;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1)
+ switch (optc) {
+ case ORD('H'):
+ how = HARD;
+ break;
+ case ORD('S'):
+ how = SOFT;
+ break;
+ case ORD('a'):
+ all = true;
+ break;
+ case ORD('?'):
+ bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts);
+ return (1);
+ default:
+ what = optc;
+ }
+
+ while (i < NELEM(rlimits)) {
+ if (rlimits[i]->optchar == what)
+ goto found;
+ ++i;
+ }
+#ifndef RLIMIT_CORE
+ if (what == ORD('c'))
+ /* silently accept */
+ return 0;
+#endif
+ internal_warningf("ulimit: %c", what);
+ return (1);
+ found:
+ if (wp[builtin_opt.optind]) {
+ if (all || wp[builtin_opt.optind + 1]) {
+ bi_errorf(Ttoo_many_args);
+ return (1);
+ }
+ return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how));
+ }
+ if (!all)
+ print_ulimit(rlimits[i], how);
+ else for (i = 0; i < NELEM(rlimits); ++i) {
+ shprintf("-%c: %-20s ", rlimits[i]->optchar, rlimits[i]->name);
+ print_ulimit(rlimits[i], how);
+ }
+ return (0);
+}
+
+#if HAVE_RLIMIT
+#define RL_T rlim_t
+#define RL_U (rlim_t)RLIM_INFINITY
+#else
+#define RL_T long
+#define RL_U LONG_MAX
+#endif
+
+static int
+set_ulimit(const struct limits *l, const char *v, int how MKSH_A_UNUSED)
+{
+ RL_T val = (RL_T)0;
+#if HAVE_RLIMIT
+ struct rlimit limit;
+#endif
+
+ if (strcmp(v, "unlimited") == 0)
+ val = RL_U;
+ else {
+ mksh_uari_t rval;
+
+ if (!evaluate(v, (mksh_ari_t *)&rval, KSH_RETURN_ERROR, false))
+ return (1);
+ /*
+ * Avoid problems caused by typos that evaluate misses due
+ * to evaluating unset parameters to 0...
+ * If this causes problems, will have to add parameter to
+ * evaluate() to control if unset params are 0 or an error.
+ */
+ if (!rval && !ctype(v[0], C_DIGIT)) {
+ bi_errorf("invalid %s limit: %s", l->name, v);
+ return (1);
+ }
+#if HAVE_RLIMIT
+ val = (rlim_t)((rlim_t)rval * l->factor);
+#else
+ val = (RL_T)rval;
+#endif
+ }
+
+#if HAVE_RLIMIT
+ if (getrlimit(l->resource, &limit) < 0) {
+#ifndef MKSH_SMALL
+ bi_errorf("limit %s could not be read, contact the mksh developers: %s",
+ l->name, cstrerror(errno));
+#endif
+ /* some can't be read */
+ limit.rlim_cur = RLIM_INFINITY;
+ limit.rlim_max = RLIM_INFINITY;
+ }
+ if (how & SOFT)
+ limit.rlim_cur = val;
+ if (how & HARD)
+ limit.rlim_max = val;
+ if (!setrlimit(l->resource, &limit))
+ return (0);
+#else
+ if (l->writable == false) {
+ /* check.t:ulimit-2 fails if we return 1 and/or do:
+ bi_errorf(Tf_ro, l->name);
+ */
+ return (0);
+ }
+ if (ulimit(l->wesource, val) != -1L)
+ return (0);
+#endif
+ if (errno == EPERM)
+ bi_errorf("%s exceeds allowable %s limit", v, l->name);
+ else
+ bi_errorf("bad %s limit: %s", l->name, cstrerror(errno));
+ return (1);
+}
+
+static void
+print_ulimit(const struct limits *l, int how MKSH_A_UNUSED)
+{
+ RL_T val = (RL_T)0;
+#if HAVE_RLIMIT
+ struct rlimit limit;
+
+ if (getrlimit(l->resource, &limit))
+#else
+ if ((val = ulimit(l->resource, 0)) < 0)
+#endif
+ {
+ shf_puts("unknown\n", shl_stdout);
+ return;
+ }
+#if HAVE_RLIMIT
+ if (how & SOFT)
+ val = limit.rlim_cur;
+ else if (how & HARD)
+ val = limit.rlim_max;
+#endif
+ if (val == RL_U)
+ shf_puts("unlimited\n", shl_stdout);
+ else {
+#if HAVE_RLIMIT
+ val /= l->factor;
+#elif defined(KSH_UL_GBRK)
+ if (l->resource == KSH_UL_GBRK)
+ val = (RL_T)(((size_t)val - (size_t)&etext) /
+ (size_t)1024);
+#endif
+ shprintf("%lu\n", (unsigned long)val);
+ }
+}