c_ulimit.c revision 1.11 1 /* $NetBSD: c_ulimit.c,v 1.11 2015/05/09 13:22:37 christos 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.11 2015/05/09 13:22:37 christos 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 # ifdef UL_GETMAXBRK /* hpux */
117 { "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' },
118 # endif /* UL_GETMAXBRK */
119 # endif /* UL_GETBREAK */
120 # endif /* UL_GMEMLIM */
121 #endif /* RLIMIT_VMEM */
122 #ifdef RLIMIT_SWAP
123 { "swap(kbytes)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
124 #endif
125 #ifdef RLIMIT_SBSIZE
126 { "sbsize(bytes)", RLIMIT, RLIMIT_SBSIZE, RLIMIT_SBSIZE, 1, 'b' },
127 #endif
128 { .name = NULL }
129 };
130 static char options[3 + NELEM(limits)];
131 rlim_t UNINITIALIZED(val);
132 int how = SOFT | HARD;
133 const struct limits *l;
134 int set, all = 0;
135 int optc, what;
136 #ifdef HAVE_SETRLIMIT
137 struct rlimit limit;
138 #endif /* HAVE_SETRLIMIT */
139
140 if (!options[0]) {
141 /* build options string on first call - yuck */
142 char *p = options;
143
144 *p++ = 'H'; *p++ = 'S'; *p++ = 'a';
145 for (l = limits; l->name; l++)
146 *p++ = l->option;
147 *p = '\0';
148 }
149 what = 'f';
150 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
151 switch (optc) {
152 case 'H':
153 how = HARD;
154 break;
155 case 'S':
156 how = SOFT;
157 break;
158 case 'a':
159 all = 1;
160 break;
161 case '?':
162 return 1;
163 default:
164 what = optc;
165 }
166
167 for (l = limits; l->name && l->option != what; l++)
168 ;
169 if (!l->name) {
170 internal_errorf(0, "ulimit: %c", what);
171 return 1;
172 }
173
174 wp += builtin_opt.optind;
175 set = *wp ? 1 : 0;
176 if (set) {
177 if (all || wp[1]) {
178 bi_errorf("too many arguments");
179 return 1;
180 }
181 if (strcmp(wp[0], "unlimited") == 0)
182 val = KSH_RLIM_INFINITY;
183 else {
184 long rval;
185
186 if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
187 return 1;
188 /* Avoid problems caused by typos that
189 * evaluate misses due to evaluating unset
190 * parameters to 0...
191 * If this causes problems, will have to
192 * add parameter to evaluate() to control
193 * if unset params are 0 or an error.
194 */
195 if (!rval && !digit(wp[0][0])) {
196 bi_errorf("invalid limit: %s", wp[0]);
197 return 1;
198 }
199 val = (u_long)rval * l->factor;
200 }
201 }
202 if (all) {
203 for (l = limits; l->name; l++) {
204 #ifdef HAVE_SETRLIMIT
205 if (l->which == RLIMIT) {
206 if (getrlimit(l->gcmd, &limit) == -1)
207 val = RLIM_INFINITY;
208 else 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 getrlimit(l->gcmd, &limit);
237 if (set) {
238 if (how & SOFT)
239 limit.rlim_cur = val;
240 if (how & HARD)
241 limit.rlim_max = val;
242 if (setrlimit(l->scmd, &limit) < 0) {
243 if (errno == EPERM)
244 bi_errorf("exceeds allowable limit");
245 else
246 bi_errorf("bad limit: %s",
247 strerror(errno));
248 return 1;
249 }
250 } else {
251 if (how & SOFT)
252 val = limit.rlim_cur;
253 else if (how & HARD)
254 val = limit.rlim_max;
255 }
256 } else
257 #endif /* HAVE_SETRLIMIT */
258 #ifdef HAVE_ULIMIT
259 {
260 if (set) {
261 if (l->scmd == -1) {
262 bi_errorf("can't change limit");
263 return 1;
264 } else if (ulimit(l->scmd, val) < 0) {
265 bi_errorf("bad limit: %s", strerror(errno));
266 return 1;
267 }
268 } else
269 val = ulimit(l->gcmd, (rlim_t) 0);
270 }
271 #else /* HAVE_ULIMIT */
272 ;
273 #endif /* HAVE_ULIMIT */
274 if (!set) {
275 #ifdef RLIM_INFINITY
276 if (val == RLIM_INFINITY)
277 shprintf("unlimited\n");
278 else
279 #endif /* RLIM_INFINITY */
280 {
281 val /= l->factor;
282 shprintf("%ld\n", (long) val);
283 }
284 }
285 return 0;
286 }
287