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