#include <sys/resource.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <string.h>
#include "sh.h"
#define SOFT 0x1
#define HARD 0x2
struct limits {
const char *name;
int resource;
int factor;
char option;
};
static void print_ulimit(const struct limits *, int);
static int set_ulimit(const struct limits *, const char *, int);
int
c_ulimit(char **wp)
{
static const struct limits limits[] = {
{ "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
{ "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
{ "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
{ "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
{ "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
{ "processes", RLIMIT_NPROC, 1, 'p' },
{ NULL }
};
const char *options = "HSat#f#c#d#s#l#m#n#p#";
int how = SOFT | HARD;
const struct limits *l;
int optc, all = 0;
while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
switch (optc) {
case 'H':
how = HARD;
break;
case 'S':
how = SOFT;
break;
case 'a':
all = 1;
break;
case '?':
return 1;
default:
break;
}
if (wp[builtin_opt.optind] != NULL) {
bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]");
return 1;
}
ksh_getopt_reset(&builtin_opt, GF_ERROR);
while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
switch (optc) {
case 'a':
case 'H':
case 'S':
break;
case '?':
return 1;
default:
for (l = limits; l->name && l->option != optc; l++)
;
if (!l->name) {
internal_warningf("%s: %c", __func__, optc);
return 1;
}
if (builtin_opt.optarg) {
if (set_ulimit(l, builtin_opt.optarg, how))
return 1;
} else
print_ulimit(l, how);
break;
}
wp += builtin_opt.optind;
if (all) {
for (l = limits; l->name; l++) {
shprintf("%-20s ", l->name);
print_ulimit(l, how);
}
} else if (builtin_opt.optind == 1) {
l = &limits[1];
if (wp[0] != NULL) {
if (set_ulimit(l, wp[0], how))
return 1;
wp++;
} else {
print_ulimit(l, how);
}
}
return 0;
}
static int
set_ulimit(const struct limits *l, const char *v, int how)
{
rlim_t val = 0;
struct rlimit limit;
if (strcmp(v, "unlimited") == 0)
val = RLIM_INFINITY;
else {
int64_t rval;
if (!evaluate(v, &rval, KSH_RETURN_ERROR, false))
return 1;
if (!rval && !digit(v[0])) {
bi_errorf("invalid limit: %s", v);
return 1;
}
val = (rlim_t)rval * l->factor;
}
getrlimit(l->resource, &limit);
if (how & SOFT)
limit.rlim_cur = val;
if (how & HARD)
limit.rlim_max = val;
if (setrlimit(l->resource, &limit) == -1) {
if (errno == EPERM)
bi_errorf("-%c exceeds allowable limit", l->option);
else
bi_errorf("bad -%c limit: %s", l->option,
strerror(errno));
return 1;
}
return 0;
}
static void
print_ulimit(const struct limits *l, int how)
{
rlim_t val = 0;
struct rlimit limit;
getrlimit(l->resource, &limit);
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
if (val == RLIM_INFINITY)
shprintf("unlimited\n");
else {
val /= l->factor;
shprintf("%" PRIi64 "\n", (int64_t) val);
}
}