361 lines
8.2 KiB
C
361 lines
8.2 KiB
C
/* $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);
|
|
}
|
|
}
|