c_ulimit.c revision 1.6 1 /* $NetBSD: c_ulimit.c,v 1.6 2004/04/17 15:40:12 christos Exp $ */
2
3 /*
4 ulimit -- handle "ulimit" builtin
5
6 Reworked to use getrusage() and ulimit() at once (as needed on
7 some schizophenic 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.6 2004/04/17 15:40:12 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_VMEM
104 { "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
105 #else /* RLIMIT_VMEM */
106 /* These are not quite right - really should subtract etext or something */
107 # ifdef UL_GMEMLIM /* svr4/xenix */
108 { "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' },
109 # else /* UL_GMEMLIM */
110 # ifdef UL_GETBREAK /* osf/1 */
111 { "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' },
112 # else /* UL_GETBREAK */
113 # ifdef UL_GETMAXBRK /* hpux */
114 { "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' },
115 # endif /* UL_GETMAXBRK */
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 { (char *) 0 }
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 #ifdef __GNUC__
138 /* This outrageous construct just to shut up a GCC warning. */
139 (void) &val;
140 #endif
141
142 if (!options[0]) {
143 /* build options string on first call - yuck */
144 char *p = options;
145
146 *p++ = 'H'; *p++ = 'S'; *p++ = 'a';
147 for (l = limits; l->name; l++)
148 *p++ = l->option;
149 *p = '\0';
150 }
151 what = 'f';
152 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
153 switch (optc) {
154 case 'H':
155 how = HARD;
156 break;
157 case 'S':
158 how = SOFT;
159 break;
160 case 'a':
161 all = 1;
162 break;
163 case '?':
164 return 1;
165 default:
166 what = optc;
167 }
168
169 for (l = limits; l->name && l->option != what; l++)
170 ;
171 if (!l->name) {
172 internal_errorf(0, "ulimit: %c", what);
173 return 1;
174 }
175
176 wp += builtin_opt.optind;
177 set = *wp ? 1 : 0;
178 if (set) {
179 if (all || wp[1]) {
180 bi_errorf("too many arguments");
181 return 1;
182 }
183 if (strcmp(wp[0], "unlimited") == 0)
184 val = KSH_RLIM_INFINITY;
185 else {
186 long rval;
187
188 if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
189 return 1;
190 /* Avoid problems caused by typos that
191 * evaluate misses due to evaluating unset
192 * parameters to 0...
193 * If this causes problems, will have to
194 * add parameter to evaluate() to control
195 * if unset params are 0 or an error.
196 */
197 if (!rval && !digit(wp[0][0])) {
198 bi_errorf("invalid limit: %s", wp[0]);
199 return 1;
200 }
201 val = rval * l->factor;
202 }
203 }
204 if (all) {
205 for (l = limits; l->name; l++) {
206 #ifdef HAVE_SETRLIMIT
207 if (l->which == RLIMIT) {
208 getrlimit(l->gcmd, &limit);
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 getrlimit(l->gcmd, &limit);
238 if (set) {
239 if (how & SOFT)
240 limit.rlim_cur = val;
241 if (how & HARD)
242 limit.rlim_max = val;
243 if (setrlimit(l->scmd, &limit) < 0) {
244 if (errno == EPERM)
245 bi_errorf("exceeds allowable limit");
246 else
247 bi_errorf("bad limit: %s",
248 strerror(errno));
249 return 1;
250 }
251 } else {
252 if (how & SOFT)
253 val = limit.rlim_cur;
254 else if (how & HARD)
255 val = limit.rlim_max;
256 }
257 } else
258 #endif /* HAVE_SETRLIMIT */
259 #ifdef HAVE_ULIMIT
260 {
261 if (set) {
262 if (l->scmd == -1) {
263 bi_errorf("can't change limit");
264 return 1;
265 } else if (ulimit(l->scmd, val) < 0) {
266 bi_errorf("bad limit: %s", strerror(errno));
267 return 1;
268 }
269 } else
270 val = ulimit(l->gcmd, (rlim_t) 0);
271 }
272 #else /* HAVE_ULIMIT */
273 ;
274 #endif /* HAVE_ULIMIT */
275 if (!set) {
276 #ifdef RLIM_INFINITY
277 if (val == RLIM_INFINITY)
278 shprintf("unlimited\n");
279 else
280 #endif /* RLIM_INFINITY */
281 {
282 val /= l->factor;
283 shprintf("%ld\n", (long) val);
284 }
285 }
286 return 0;
287 }
288