xref: /minix/bin/ksh/c_ulimit.c (revision ebfedea0)
1 /*	$NetBSD: c_ulimit.c,v 1.10 2012/06/09 02:51:50 christos Exp $	*/
2 
3 /*
4 	ulimit -- handle "ulimit" builtin
5 
6 	Reworked to use getrusage() and ulimit() at once (as needed on
7 	some schizophrenic 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.10 2012/06/09 02:51:50 christos 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_NTHR
104 		{ "threads", RLIMIT, RLIMIT_NTHR, RLIMIT_NTHR, 1, 'r' },
105 #endif
106 #ifdef RLIMIT_VMEM
107 		{ "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
108 #else /* RLIMIT_VMEM */
109   /* These are not quite right - really should subtract etext or something */
110 # ifdef UL_GMEMLIM /* svr4/xenix */
111 		{ "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' },
112 # else /* UL_GMEMLIM */
113 #  ifdef UL_GETBREAK /* osf/1 */
114 		{ "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' },
115 #  else /* UL_GETBREAK */
116 #   ifdef UL_GETMAXBRK /* hpux */
117 		{ "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' },
118 #   endif /* UL_GETMAXBRK */
119 #  endif /* UL_GETBREAK */
120 # endif /* UL_GMEMLIM */
121 #endif /* RLIMIT_VMEM */
122 #ifdef RLIMIT_SWAP
123 		{ "swap(kbytes)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
124 #endif
125 #ifdef RLIMIT_SBSIZE
126 		{ "sbsize(bytes)", RLIMIT, RLIMIT_SBSIZE, RLIMIT_SBSIZE, 1, 'b' },
127 #endif
128 		{ .name = NULL }
129 	    };
130 	static char	options[3 + NELEM(limits)];
131 	rlim_t		UNINITIALIZED(val);
132 	int		how = SOFT | HARD;
133 	const struct limits	*l;
134 	int		set, all = 0;
135 	int		optc, what;
136 #ifdef HAVE_SETRLIMIT
137 	struct rlimit	limit;
138 #endif /* HAVE_SETRLIMIT */
139 
140 	if (!options[0]) {
141 		/* build options string on first call - yuck */
142 		char *p = options;
143 
144 		*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
145 		for (l = limits; l->name; l++)
146 			*p++ = l->option;
147 		*p = '\0';
148 	}
149 	what = 'f';
150 	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
151 		switch (optc) {
152 		  case 'H':
153 			how = HARD;
154 			break;
155 		  case 'S':
156 			how = SOFT;
157 			break;
158 		  case 'a':
159 			all = 1;
160 			break;
161 		  case '?':
162 			return 1;
163 		  default:
164 			what = optc;
165 		}
166 
167 	for (l = limits; l->name && l->option != what; l++)
168 		;
169 	if (!l->name) {
170 		internal_errorf(0, "ulimit: %c", what);
171 		return 1;
172 	}
173 
174 	wp += builtin_opt.optind;
175 	set = *wp ? 1 : 0;
176 	if (set) {
177 		if (all || wp[1]) {
178 			bi_errorf("too many arguments");
179 			return 1;
180 		}
181 		if (strcmp(wp[0], "unlimited") == 0)
182 			val = KSH_RLIM_INFINITY;
183 		else {
184 			long rval;
185 
186 			if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
187 				return 1;
188 			/* Avoid problems caused by typos that
189 			 * evaluate misses due to evaluating unset
190 			 * parameters to 0...
191 			 * If this causes problems, will have to
192 			 * add parameter to evaluate() to control
193 			 * if unset params are 0 or an error.
194 			 */
195 			if (!rval && !digit(wp[0][0])) {
196 			    bi_errorf("invalid limit: %s", wp[0]);
197 			    return 1;
198 			}
199 			val = (u_long)rval * l->factor;
200 		}
201 	}
202 	if (all) {
203 		for (l = limits; l->name; l++) {
204 #ifdef HAVE_SETRLIMIT
205 			if (l->which == RLIMIT) {
206 				getrlimit(l->gcmd, &limit);
207 				if (how & SOFT)
208 					val = limit.rlim_cur;
209 				else if (how & HARD)
210 					val = limit.rlim_max;
211 			} else
212 #endif /* HAVE_SETRLIMIT */
213 #ifdef HAVE_ULIMIT
214 			{
215 				val = ulimit(l->gcmd, (rlim_t) 0);
216 			}
217 #else /* HAVE_ULIMIT */
218 				;
219 #endif /* HAVE_ULIMIT */
220 			shprintf("%-20s ", l->name);
221 #ifdef RLIM_INFINITY
222 			if (val == RLIM_INFINITY)
223 				shprintf("unlimited\n");
224 			else
225 #endif /* RLIM_INFINITY */
226 			{
227 				val /= l->factor;
228 				shprintf("%ld\n", (long) val);
229 			}
230 		}
231 		return 0;
232 	}
233 #ifdef HAVE_SETRLIMIT
234 	if (l->which == RLIMIT) {
235 		getrlimit(l->gcmd, &limit);
236 		if (set) {
237 			if (how & SOFT)
238 				limit.rlim_cur = val;
239 			if (how & HARD)
240 				limit.rlim_max = val;
241 			if (setrlimit(l->scmd, &limit) < 0) {
242 				if (errno == EPERM)
243 					bi_errorf("exceeds allowable limit");
244 				else
245 					bi_errorf("bad limit: %s",
246 						strerror(errno));
247 				return 1;
248 			}
249 		} else {
250 			if (how & SOFT)
251 				val = limit.rlim_cur;
252 			else if (how & HARD)
253 				val = limit.rlim_max;
254 		}
255 	} else
256 #endif /* HAVE_SETRLIMIT */
257 #ifdef HAVE_ULIMIT
258 	{
259 		if (set) {
260 			if (l->scmd == -1) {
261 				bi_errorf("can't change limit");
262 				return 1;
263 			} else if (ulimit(l->scmd, val) < 0) {
264 				bi_errorf("bad limit: %s", strerror(errno));
265 				return 1;
266 			}
267 		} else
268 			val = ulimit(l->gcmd, (rlim_t) 0);
269 	}
270 #else /* HAVE_ULIMIT */
271 		;
272 #endif /* HAVE_ULIMIT */
273 	if (!set) {
274 #ifdef RLIM_INFINITY
275 		if (val == RLIM_INFINITY)
276 			shprintf("unlimited\n");
277 		else
278 #endif /* RLIM_INFINITY */
279 		{
280 			val /= l->factor;
281 			shprintf("%ld\n", (long) val);
282 		}
283 	}
284 	return 0;
285 }
286