c_ulimit.c revision 1.5 1 /* $NetBSD: c_ulimit.c,v 1.5 2003/06/23 11:38:54 agc 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.5 2003/06/23 11:38:54 agc 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_SWAP, RLIMIT_SWAP, 1024, 'w' },
121 #endif
122 { (char *) 0 }
123 };
124 static char options[3 + NELEM(limits)];
125 rlim_t UNINITIALIZED(val);
126 int how = SOFT | HARD;
127 const struct limits *l;
128 int set, all = 0;
129 int optc, what;
130 #ifdef HAVE_SETRLIMIT
131 struct rlimit limit;
132 #endif /* HAVE_SETRLIMIT */
133
134 #ifdef __GNUC__
135 /* This outrageous construct just to shut up a GCC warning. */
136 (void) &val;
137 #endif
138
139 if (!options[0]) {
140 /* build options string on first call - yuck */
141 char *p = options;
142
143 *p++ = 'H'; *p++ = 'S'; *p++ = 'a';
144 for (l = limits; l->name; l++)
145 *p++ = l->option;
146 *p = '\0';
147 }
148 what = 'f';
149 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
150 switch (optc) {
151 case 'H':
152 how = HARD;
153 break;
154 case 'S':
155 how = SOFT;
156 break;
157 case 'a':
158 all = 1;
159 break;
160 case '?':
161 return 1;
162 default:
163 what = optc;
164 }
165
166 for (l = limits; l->name && l->option != what; l++)
167 ;
168 if (!l->name) {
169 internal_errorf(0, "ulimit: %c", what);
170 return 1;
171 }
172
173 wp += builtin_opt.optind;
174 set = *wp ? 1 : 0;
175 if (set) {
176 if (all || wp[1]) {
177 bi_errorf("too many arguments");
178 return 1;
179 }
180 if (strcmp(wp[0], "unlimited") == 0)
181 val = KSH_RLIM_INFINITY;
182 else {
183 long rval;
184
185 if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
186 return 1;
187 /* Avoid problems caused by typos that
188 * evaluate misses due to evaluating unset
189 * parameters to 0...
190 * If this causes problems, will have to
191 * add parameter to evaluate() to control
192 * if unset params are 0 or an error.
193 */
194 if (!rval && !digit(wp[0][0])) {
195 bi_errorf("invalid limit: %s", wp[0]);
196 return 1;
197 }
198 val = rval * l->factor;
199 }
200 }
201 if (all) {
202 for (l = limits; l->name; l++) {
203 #ifdef HAVE_SETRLIMIT
204 if (l->which == RLIMIT) {
205 getrlimit(l->gcmd, &limit);
206 if (how & SOFT)
207 val = limit.rlim_cur;
208 else if (how & HARD)
209 val = limit.rlim_max;
210 } else
211 #endif /* HAVE_SETRLIMIT */
212 #ifdef HAVE_ULIMIT
213 {
214 val = ulimit(l->gcmd, (rlim_t) 0);
215 }
216 #else /* HAVE_ULIMIT */
217 ;
218 #endif /* HAVE_ULIMIT */
219 shprintf("%-20s ", l->name);
220 #ifdef RLIM_INFINITY
221 if (val == RLIM_INFINITY)
222 shprintf("unlimited\n");
223 else
224 #endif /* RLIM_INFINITY */
225 {
226 val /= l->factor;
227 shprintf("%ld\n", (long) val);
228 }
229 }
230 return 0;
231 }
232 #ifdef HAVE_SETRLIMIT
233 if (l->which == RLIMIT) {
234 getrlimit(l->gcmd, &limit);
235 if (set) {
236 if (how & SOFT)
237 limit.rlim_cur = val;
238 if (how & HARD)
239 limit.rlim_max = val;
240 if (setrlimit(l->scmd, &limit) < 0) {
241 if (errno == EPERM)
242 bi_errorf("exceeds allowable limit");
243 else
244 bi_errorf("bad limit: %s",
245 strerror(errno));
246 return 1;
247 }
248 } else {
249 if (how & SOFT)
250 val = limit.rlim_cur;
251 else if (how & HARD)
252 val = limit.rlim_max;
253 }
254 } else
255 #endif /* HAVE_SETRLIMIT */
256 #ifdef HAVE_ULIMIT
257 {
258 if (set) {
259 if (l->scmd == -1) {
260 bi_errorf("can't change limit");
261 return 1;
262 } else if (ulimit(l->scmd, val) < 0) {
263 bi_errorf("bad limit: %s", strerror(errno));
264 return 1;
265 }
266 } else
267 val = ulimit(l->gcmd, (rlim_t) 0);
268 }
269 #else /* HAVE_ULIMIT */
270 ;
271 #endif /* HAVE_ULIMIT */
272 if (!set) {
273 #ifdef RLIM_INFINITY
274 if (val == RLIM_INFINITY)
275 shprintf("unlimited\n");
276 else
277 #endif /* RLIM_INFINITY */
278 {
279 val /= l->factor;
280 shprintf("%ld\n", (long) val);
281 }
282 }
283 return 0;
284 }
285