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