1 /* $NetBSD: c_ulimit.c,v 1.16 2017/06/30 03:43:57 kamil 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 #include <sys/cdefs.h>
21
22 #ifndef lint
23 __RCSID("$NetBSD: c_ulimit.c,v 1.16 2017/06/30 03:43:57 kamil Exp $");
24 #endif
25
26 #include <sys/time.h>
27 #include <time.h>
28
29 #include "sh.h"
30 #ifdef HAVE_SYS_RESOURCE_H
31 # include <sys/resource.h>
32 #endif /* HAVE_SYS_RESOURCE_H */
33 #ifdef HAVE_ULIMIT_H
34 # include <ulimit.h>
35 #else /* HAVE_ULIMIT_H */
36 # ifdef HAVE_ULIMIT
37 extern long ulimit();
38 # endif /* HAVE_ULIMIT */
39 #endif /* HAVE_ULIMIT_H */
40
41 #define SOFT 0x1
42 #define HARD 0x2
43
44 #ifdef RLIM_INFINITY
45 # define KSH_RLIM_INFINITY RLIM_INFINITY
46 #else
47 # define KSH_RLIM_INFINITY ((rlim_t) 1 << (sizeof(rlim_t) * 8 - 1) - 1)
48 #endif /* RLIM_INFINITY */
49
50 int
c_ulimit(wp)51 c_ulimit(wp)
52 char **wp;
53 {
54 static const struct limits {
55 const char *name;
56 enum { RLIMIT, ULIMIT } which;
57 int gcmd; /* get command */
58 int scmd; /* set command (or -1, if no set command) */
59 int factor; /* multiply by to get rlim_{cur,max} values */
60 char option;
61 } limits[] = {
62 /* Do not use options -H, -S or -a */
63 #ifdef RLIMIT_CPU
64 { "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' },
65 #endif
66 #ifdef RLIMIT_FSIZE
67 { "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' },
68 #else /* RLIMIT_FSIZE */
69 # ifdef UL_GETFSIZE /* x/open */
70 { "file(blocks)", ULIMIT, UL_GETFSIZE, UL_SETFSIZE, 1, 'f' },
71 # else /* UL_GETFSIZE */
72 # ifdef UL_GFILLIM /* svr4/xenix */
73 { "file(blocks)", ULIMIT, UL_GFILLIM, UL_SFILLIM, 1, 'f' },
74 # else /* UL_GFILLIM */
75 { "file(blocks)", ULIMIT, 1, 2, 1, 'f' },
76 # endif /* UL_GFILLIM */
77 # endif /* UL_GETFSIZE */
78 #endif /* RLIMIT_FSIZE */
79 #ifdef RLIMIT_CORE
80 { "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' },
81 #endif
82 #ifdef RLIMIT_DATA
83 { "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' },
84 #endif
85 #ifdef RLIMIT_STACK
86 { "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' },
87 #endif
88 #ifdef RLIMIT_MEMLOCK
89 { "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, 1024, 'l' },
90 #endif
91 #ifdef RLIMIT_RSS
92 { "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' },
93 #endif
94 #ifdef RLIMIT_NOFILE
95 { "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE, 1, 'n' },
96 #else /* RLIMIT_NOFILE */
97 # ifdef UL_GDESLIM /* svr4/xenix */
98 { "nofiles(descriptors)", ULIMIT, UL_GDESLIM, -1, 1, 'n' },
99 # endif /* UL_GDESLIM */
100 #endif /* RLIMIT_NOFILE */
101 #ifdef RLIMIT_NPROC
102 { "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' },
103 #endif
104 #ifdef RLIMIT_NTHR
105 { "threads", RLIMIT, RLIMIT_NTHR, RLIMIT_NTHR, 1, 'r' },
106 #endif
107 #ifdef RLIMIT_VMEM
108 { "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
109 #else /* RLIMIT_VMEM */
110 /* These are not quite right - really should subtract etext or something */
111 # ifdef UL_GMEMLIM /* svr4/xenix */
112 { "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' },
113 # else /* UL_GMEMLIM */
114 # ifdef UL_GETBREAK /* osf/1 */
115 { "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' },
116 # else /* UL_GETBREAK */
117 # endif /* UL_GETBREAK */
118 # endif /* UL_GMEMLIM */
119 #endif /* RLIMIT_VMEM */
120 #ifdef RLIMIT_SWAP
121 { "swap(kbytes)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
122 #endif
123 #ifdef RLIMIT_SBSIZE
124 { "sbsize(bytes)", RLIMIT, RLIMIT_SBSIZE, RLIMIT_SBSIZE, 1, 'b' },
125 #endif
126 { .name = NULL }
127 };
128 static char options[3 + NELEM(limits)];
129 rlim_t UNINITIALIZED(val);
130 int how = SOFT | HARD;
131 const struct limits *l;
132 int set, all = 0;
133 int optc, what;
134 #ifdef HAVE_SETRLIMIT
135 struct rlimit limit;
136 #endif /* HAVE_SETRLIMIT */
137
138 if (!options[0]) {
139 /* build options string on first call - yuck */
140 char *p = options;
141
142 *p++ = 'H'; *p++ = 'S'; *p++ = 'a';
143 for (l = limits; l->name; l++)
144 *p++ = l->option;
145 *p = '\0';
146 }
147 what = 'f';
148 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
149 switch (optc) {
150 case 'H':
151 how = HARD;
152 break;
153 case 'S':
154 how = SOFT;
155 break;
156 case 'a':
157 all = 1;
158 break;
159 case '?':
160 return 1;
161 default:
162 what = optc;
163 }
164
165 for (l = limits; l->name && l->option != what; l++)
166 ;
167 if (!l->name) {
168 internal_errorf(0, "ulimit: %c", what);
169 return 1;
170 }
171
172 wp += builtin_opt.optind;
173 set = *wp ? 1 : 0;
174 if (set) {
175 if (all || wp[1]) {
176 bi_errorf("too many arguments");
177 return 1;
178 }
179 if (strcmp(wp[0], "unlimited") == 0)
180 val = KSH_RLIM_INFINITY;
181 else {
182 long rval;
183
184 if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
185 return 1;
186 /* Avoid problems caused by typos that
187 * evaluate misses due to evaluating unset
188 * parameters to 0...
189 * If this causes problems, will have to
190 * add parameter to evaluate() to control
191 * if unset params are 0 or an error.
192 */
193 if (!rval && !digit(wp[0][0])) {
194 bi_errorf("invalid limit: %s", wp[0]);
195 return 1;
196 }
197 val = (u_long)rval * l->factor;
198 }
199 }
200 if (all) {
201 for (l = limits; l->name; l++) {
202 #ifdef HAVE_SETRLIMIT
203 if (l->which == RLIMIT) {
204 if (getrlimit(l->gcmd, &limit) == -1) {
205 bi_errorf("can't get limit: %s",
206 strerror(errno));
207 return 1;
208 }
209 if (how & SOFT)
210 val = limit.rlim_cur;
211 else if (how & HARD)
212 val = limit.rlim_max;
213 } else
214 #endif /* HAVE_SETRLIMIT */
215 #ifdef HAVE_ULIMIT
216 {
217 val = ulimit(l->gcmd, (rlim_t) 0);
218 }
219 #else /* HAVE_ULIMIT */
220 ;
221 #endif /* HAVE_ULIMIT */
222 shprintf("%-20s ", l->name);
223 #ifdef RLIM_INFINITY
224 if (val == RLIM_INFINITY)
225 shprintf("unlimited\n");
226 else
227 #endif /* RLIM_INFINITY */
228 {
229 val /= l->factor;
230 shprintf("%ld\n", (long) val);
231 }
232 }
233 return 0;
234 }
235 #ifdef HAVE_SETRLIMIT
236 if (l->which == RLIMIT) {
237 if (getrlimit(l->gcmd, &limit) == -1) {
238 bi_errorf("can't get limit: %s", strerror(errno));
239 return 1;
240 }
241 if (set) {
242 if (how & SOFT)
243 limit.rlim_cur = val;
244 if (how & HARD)
245 limit.rlim_max = val;
246 if (setrlimit(l->scmd, &limit) < 0) {
247 if (errno == EPERM)
248 bi_errorf("exceeds allowable limit");
249 else
250 bi_errorf("bad limit: %s",
251 strerror(errno));
252 return 1;
253 }
254 } else {
255 if (how & SOFT)
256 val = limit.rlim_cur;
257 else if (how & HARD)
258 val = limit.rlim_max;
259 }
260 } else
261 #endif /* HAVE_SETRLIMIT */
262 #ifdef HAVE_ULIMIT
263 {
264 if (set) {
265 if (l->scmd == -1) {
266 bi_errorf("can't change limit");
267 return 1;
268 } else if (ulimit(l->scmd, val) < 0) {
269 bi_errorf("bad limit: %s", strerror(errno));
270 return 1;
271 }
272 } else
273 val = ulimit(l->gcmd, (rlim_t) 0);
274 }
275 #else /* HAVE_ULIMIT */
276 ;
277 #endif /* HAVE_ULIMIT */
278 if (!set) {
279 #ifdef RLIM_INFINITY
280 if (val == RLIM_INFINITY)
281 shprintf("unlimited\n");
282 else
283 #endif /* RLIM_INFINITY */
284 {
285 val /= l->factor;
286 shprintf("%ld\n", (long) val);
287 }
288 }
289 return 0;
290 }
291