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