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