1 |
|
|
/* $OpenBSD: c_ulimit.c,v 1.24 2015/12/14 13:59:42 tb Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
ulimit -- handle "ulimit" builtin |
5 |
|
|
|
6 |
|
|
Reworked to use getrusage() and ulimit() at once (as needed on |
7 |
|
|
some schizophrenic systems, eg, HP-UX 9.01), made argument parsing |
8 |
|
|
conform to at&t ksh, added autoconf support. Michael Rendell, May, '94 |
9 |
|
|
|
10 |
|
|
Eric Gisin, September 1988 |
11 |
|
|
Adapted to PD KornShell. Removed AT&T code. |
12 |
|
|
|
13 |
|
|
last edit: 06-Jun-1987 D A Gwyn |
14 |
|
|
|
15 |
|
|
This started out as the BRL UNIX System V system call emulation |
16 |
|
|
for 4.nBSD, and was later extended by Doug Kingston to handle |
17 |
|
|
the extended 4.nBSD resource limits. It now includes the code |
18 |
|
|
that was originally under case SYSULIMIT in source file "xec.c". |
19 |
|
|
*/ |
20 |
|
|
|
21 |
|
|
#include <sys/resource.h> |
22 |
|
|
|
23 |
|
|
#include <ctype.h> |
24 |
|
|
#include <errno.h> |
25 |
|
|
#include <string.h> |
26 |
|
|
|
27 |
|
|
#include "sh.h" |
28 |
|
|
|
29 |
|
|
#define SOFT 0x1 |
30 |
|
|
#define HARD 0x2 |
31 |
|
|
|
32 |
|
|
struct limits { |
33 |
|
|
const char *name; |
34 |
|
|
int resource; /* resource to get/set */ |
35 |
|
|
int factor; /* multiply by to get rlim_{cur,max} values */ |
36 |
|
|
char option; /* option character (-d, -f, ...) */ |
37 |
|
|
}; |
38 |
|
|
|
39 |
|
|
static void print_ulimit(const struct limits *, int); |
40 |
|
|
static int set_ulimit(const struct limits *, const char *, int); |
41 |
|
|
|
42 |
|
|
int |
43 |
|
|
c_ulimit(char **wp) |
44 |
|
2 |
{ |
45 |
|
|
static const struct limits limits[] = { |
46 |
|
|
/* Do not use options -H, -S or -a or change the order. */ |
47 |
|
|
{ "time(cpu-seconds)", RLIMIT_CPU, 1, 't' }, |
48 |
|
|
{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, |
49 |
|
|
{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, |
50 |
|
|
{ "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, |
51 |
|
|
{ "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, |
52 |
|
|
{ "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, |
53 |
|
|
{ "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, |
54 |
|
|
{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, |
55 |
|
|
{ "processes", RLIMIT_NPROC, 1, 'p' }, |
56 |
|
|
#ifdef RLIMIT_VMEM |
57 |
|
|
{ "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, |
58 |
|
|
#endif /* RLIMIT_VMEM */ |
59 |
|
|
{ NULL } |
60 |
|
|
}; |
61 |
|
|
static char options[4 + NELEM(limits) * 2]; |
62 |
|
2 |
int how = SOFT | HARD; |
63 |
|
|
const struct limits *l; |
64 |
|
2 |
int optc, all = 0; |
65 |
|
|
|
66 |
✓✗ |
2 |
if (!options[0]) { |
67 |
|
|
/* build options string on first call - yuck */ |
68 |
|
2 |
char *p = options; |
69 |
|
|
|
70 |
|
2 |
*p++ = 'H'; *p++ = 'S'; *p++ = 'a'; |
71 |
✓✓ |
20 |
for (l = limits; l->name; l++) { |
72 |
|
18 |
*p++ = l->option; |
73 |
|
18 |
*p++ = '#'; |
74 |
|
|
} |
75 |
|
2 |
*p = '\0'; |
76 |
|
|
} |
77 |
|
|
/* First check for -a, -H and -S. */ |
78 |
✓✓ |
4 |
while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) |
79 |
✗✗✗✗ ✓ |
2 |
switch (optc) { |
80 |
|
|
case 'H': |
81 |
|
|
how = HARD; |
82 |
|
|
break; |
83 |
|
|
case 'S': |
84 |
|
|
how = SOFT; |
85 |
|
|
break; |
86 |
|
|
case 'a': |
87 |
|
|
all = 1; |
88 |
|
|
break; |
89 |
|
|
case '?': |
90 |
|
|
return 1; |
91 |
|
|
default: |
92 |
|
|
break; |
93 |
|
|
} |
94 |
|
|
|
95 |
✗✓ |
2 |
if (wp[builtin_opt.optind] != NULL) { |
96 |
|
|
bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]"); |
97 |
|
|
return 1; |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
/* Then parse and act on the actual limits, one at a time */ |
101 |
|
2 |
ksh_getopt_reset(&builtin_opt, GF_ERROR); |
102 |
✓✓ |
6 |
while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) |
103 |
✗✓✗ |
2 |
switch (optc) { |
104 |
|
|
case 'a': |
105 |
|
|
case 'H': |
106 |
|
|
case 'S': |
107 |
|
|
break; |
108 |
|
|
case '?': |
109 |
|
|
return 1; |
110 |
|
|
default: |
111 |
✓✗✓✓
|
2 |
for (l = limits; l->name && l->option != optc; l++) |
112 |
|
|
; |
113 |
✗✓ |
2 |
if (!l->name) { |
114 |
|
|
internal_errorf(0, "ulimit: %c", optc); |
115 |
|
|
return 1; |
116 |
|
|
} |
117 |
✓✗ |
2 |
if (builtin_opt.optarg) { |
118 |
✗✓ |
2 |
if (set_ulimit(l, builtin_opt.optarg, how)) |
119 |
|
|
return 1; |
120 |
|
|
} else |
121 |
|
|
print_ulimit(l, how); |
122 |
|
|
break; |
123 |
|
|
} |
124 |
|
|
|
125 |
|
2 |
wp += builtin_opt.optind; |
126 |
|
|
|
127 |
✗✓ |
2 |
if (all) { |
128 |
|
|
for (l = limits; l->name; l++) { |
129 |
|
|
shprintf("%-20s ", l->name); |
130 |
|
|
print_ulimit(l, how); |
131 |
|
|
} |
132 |
✗✓ |
2 |
} else if (builtin_opt.optind == 1) { |
133 |
|
|
/* No limit specified, use file size */ |
134 |
|
|
l = &limits[1]; |
135 |
|
|
if (wp[0] != NULL) { |
136 |
|
|
if (set_ulimit(l, wp[0], how)) |
137 |
|
|
return 1; |
138 |
|
|
wp++; |
139 |
|
|
} else { |
140 |
|
|
print_ulimit(l, how); |
141 |
|
|
} |
142 |
|
|
} |
143 |
|
|
|
144 |
|
2 |
return 0; |
145 |
|
|
} |
146 |
|
|
|
147 |
|
|
static int |
148 |
|
|
set_ulimit(const struct limits *l, const char *v, int how) |
149 |
|
2 |
{ |
150 |
|
2 |
rlim_t val = 0; |
151 |
|
|
struct rlimit limit; |
152 |
|
|
|
153 |
✗✓ |
2 |
if (strcmp(v, "unlimited") == 0) |
154 |
|
|
val = RLIM_INFINITY; |
155 |
|
|
else { |
156 |
|
|
long rval; |
157 |
|
|
|
158 |
✗✓ |
2 |
if (!evaluate(v, &rval, KSH_RETURN_ERROR, false)) |
159 |
|
|
return 1; |
160 |
|
|
/* |
161 |
|
|
* Avoid problems caused by typos that evaluate misses due |
162 |
|
|
* to evaluating unset parameters to 0... |
163 |
|
|
* If this causes problems, will have to add parameter to |
164 |
|
|
* evaluate() to control if unset params are 0 or an error. |
165 |
|
|
*/ |
166 |
✓✗✗✓
|
2 |
if (!rval && !digit(v[0])) { |
167 |
|
|
bi_errorf("invalid limit: %s", v); |
168 |
|
|
return 1; |
169 |
|
|
} |
170 |
|
2 |
val = (rlim_t)rval * l->factor; |
171 |
|
|
} |
172 |
|
|
|
173 |
|
2 |
getrlimit(l->resource, &limit); |
174 |
✓✗ |
2 |
if (how & SOFT) |
175 |
|
2 |
limit.rlim_cur = val; |
176 |
✓✗ |
2 |
if (how & HARD) |
177 |
|
2 |
limit.rlim_max = val; |
178 |
✗✓ |
2 |
if (setrlimit(l->resource, &limit) < 0) { |
179 |
|
|
if (errno == EPERM) |
180 |
|
|
bi_errorf("-%c exceeds allowable limit", l->option); |
181 |
|
|
else |
182 |
|
|
bi_errorf("bad -%c limit: %s", l->option, |
183 |
|
|
strerror(errno)); |
184 |
|
|
return 1; |
185 |
|
|
} |
186 |
|
2 |
return 0; |
187 |
|
|
} |
188 |
|
|
|
189 |
|
|
static void |
190 |
|
|
print_ulimit(const struct limits *l, int how) |
191 |
|
|
{ |
192 |
|
|
rlim_t val = 0; |
193 |
|
|
struct rlimit limit; |
194 |
|
|
|
195 |
|
|
getrlimit(l->resource, &limit); |
196 |
|
|
if (how & SOFT) |
197 |
|
|
val = limit.rlim_cur; |
198 |
|
|
else if (how & HARD) |
199 |
|
|
val = limit.rlim_max; |
200 |
|
|
if (val == RLIM_INFINITY) |
201 |
|
|
shprintf("unlimited\n"); |
202 |
|
|
else { |
203 |
|
|
val /= l->factor; |
204 |
|
|
shprintf("%ld\n", (long) val); |
205 |
|
|
} |
206 |
|
|
} |