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