xref: /netbsd-src/bin/ksh/c_ulimit.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
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