• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*	$OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
5  *		 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
6  *		 2019, 2020
7  *	mirabilos <m@mirbsd.org>
8  *
9  * Provided that these terms and disclaimer and all copyright notices
10  * are retained or reproduced in an accompanying document, permission
11  * is granted to deal in this work without restriction, including un-
12  * limited rights to use, publicly perform, distribute, sell, modify,
13  * merge, give away, or sublicence.
14  *
15  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
16  * the utmost extent permitted by applicable law, neither express nor
17  * implied; without malicious intent or gross negligence. In no event
18  * may a licensor, author or contributor be held liable for indirect,
19  * direct, other damage, loss, or other issues arising in any way out
20  * of dealing in the work, even if advised of the possibility of such
21  * damage or existence of a defect, except proven that it results out
22  * of said person's immediate fault when using the work as intended.
23  */
24 
25 #include "sh.h"
26 
27 __RCSID("$MirOS: src/bin/mksh/ulimit.c,v 1.3 2020/07/24 21:08:26 tg Exp $");
28 
29 #define SOFT	0x1
30 #define HARD	0x2
31 
32 #if HAVE_RLIMIT
33 
34 #if !HAVE_RLIM_T
35 typedef unsigned long rlim_t;
36 #endif
37 
38 /* Magic to divine the 'm' and 'v' limits */
39 
40 #ifdef RLIMIT_AS
41 #if !defined(RLIMIT_VMEM) || (RLIMIT_VMEM == RLIMIT_AS) || \
42     !defined(RLIMIT_RSS) || (RLIMIT_VMEM == RLIMIT_RSS)
43 #define ULIMIT_V_IS_AS
44 #elif defined(RLIMIT_VMEM)
45 #if !defined(RLIMIT_RSS) || (RLIMIT_RSS == RLIMIT_AS)
46 #define ULIMIT_V_IS_AS
47 #else
48 #define ULIMIT_V_IS_VMEM
49 #endif
50 #endif
51 #endif
52 
53 #ifdef RLIMIT_RSS
54 #ifdef ULIMIT_V_IS_VMEM
55 #define ULIMIT_M_IS_RSS
56 #elif defined(RLIMIT_VMEM) && (RLIMIT_VMEM == RLIMIT_RSS)
57 #define ULIMIT_M_IS_VMEM
58 #else
59 #define ULIMIT_M_IS_RSS
60 #endif
61 #if defined(ULIMIT_M_IS_RSS) && defined(RLIMIT_AS) && \
62     !defined(__APPLE__) && (RLIMIT_RSS == RLIMIT_AS)
63 /* On Mac OSX keep -m as -v alias for pkgsrc and other software expecting it */
64 #undef ULIMIT_M_IS_RSS
65 #endif
66 #endif
67 
68 #if !defined(RLIMIT_AS) && !defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_VMEM)
69 #define ULIMIT_V_IS_VMEM
70 #endif
71 
72 #if !defined(ULIMIT_V_IS_VMEM) && defined(RLIMIT_VMEM) && \
73     (!defined(RLIMIT_RSS) || (defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS)))
74 #define ULIMIT_M_IS_VMEM
75 #endif
76 
77 #if defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_AS) && \
78     (RLIMIT_VMEM == RLIMIT_AS)
79 #undef ULIMIT_M_IS_VMEM
80 #endif
81 
82 #if defined(ULIMIT_M_IS_RSS) && defined(ULIMIT_M_IS_VMEM)
83 # error nonsensical m ulimit
84 #endif
85 
86 #if defined(ULIMIT_V_IS_VMEM) && defined(ULIMIT_V_IS_AS)
87 # error nonsensical v ulimit
88 #endif
89 
90 #define LIMITS_GEN	"rlimits.gen"
91 
92 #else /* !HAVE_RLIMIT */
93 
94 #undef RLIMIT_CORE	/* just in case */
95 
96 #if defined(UL_GETFSIZE)
97 #define KSH_UL_GFIL	UL_GETFSIZE
98 #elif defined(UL_GFILLIM)
99 #define KSH_UL_GFIL	UL_GFILLIM
100 #elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST)
101 #define KSH_UL_GFIL	1
102 #endif
103 
104 #if defined(UL_SETFSIZE)
105 #define KSH_UL_SFIL	UL_SETFSIZE
106 #elif defined(UL_SFILLIM)
107 #define KSH_UL_SFIL	UL_SFILLIM
108 #elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST)
109 #define KSH_UL_SFIL	2
110 #endif
111 
112 #if defined(KSH_UL_SFIL)
113 #define KSH_UL_WFIL	true
114 #else
115 #define KSH_UL_WFIL	false
116 #define KSH_UL_SFIL	0
117 #endif
118 
119 #if defined(UL_GETMAXBRK)
120 #define KSH_UL_GBRK	UL_GETMAXBRK
121 #elif defined(UL_GMEMLIM)
122 #define KSH_UL_GBRK	UL_GMEMLIM
123 #elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST)
124 #define KSH_UL_GBRK	3
125 #endif
126 
127 #if defined(UL_GDESLIM)
128 #define KSH_UL_GDES	UL_GDESLIM
129 #elif defined(__GLIBC__) || defined(KSH_ULIMIT2_TEST)
130 #define KSH_UL_GDES	4
131 #endif
132 
133 extern char etext;
134 extern long ulimit(int, long);
135 
136 #define LIMITS_GEN	"ulimits.gen"
137 
138 #endif /* !HAVE_RLIMIT */
139 
140 struct limits {
141 	/* limit resource / read command */
142 	int resource;
143 #if HAVE_RLIMIT
144 	/* multiply by to get rlim_{cur,max} values */
145 	unsigned int factor;
146 #else
147 	/* write command */
148 	int wesource;
149 	/* writable? */
150 	bool writable;
151 #endif
152 	/* getopts char */
153 	char optchar;
154 	/* limit name */
155 	char name[1];
156 };
157 
158 #define RLIMITS_DEFNS
159 #if HAVE_RLIMIT
160 #define FN(lname,lid,lfac,lopt)				\
161 	static const struct {				\
162 		int resource;				\
163 		unsigned int factor;			\
164 		char optchar;				\
165 		char name[sizeof(lname)];		\
166 	} rlimits_ ## lid = {				\
167 		lid, lfac, lopt, lname			\
168 	};
169 #else
170 #define FN(lname,lg,ls,lw,lopt)				\
171 	static const struct {				\
172 		int rcmd;				\
173 		int wcmd;				\
174 		bool writable;				\
175 		char optchar;				\
176 		char name[sizeof(lname)];		\
177 	} rlimits_ ## lg = {				\
178 		lg, ls, lw, lopt, lname			\
179 	};
180 #endif
181 #include LIMITS_GEN
182 
183 static void print_ulimit(const struct limits *, int);
184 static int set_ulimit(const struct limits *, const char *, int);
185 
186 static const struct limits * const rlimits[] = {
187 #define RLIMITS_ITEMS
188 #include LIMITS_GEN
189 };
190 
191 static const char rlimits_opts[] =
192 #define RLIMITS_OPTCS
193 #include LIMITS_GEN
194 #ifndef RLIMIT_CORE
195 	"c"
196 #endif
197     ;
198 
199 int
c_ulimit(const char ** wp)200 c_ulimit(const char **wp)
201 {
202 	size_t i = 0;
203 	int how = SOFT | HARD, optc;
204 	char what = 'f';
205 	bool all = false;
206 
207 	while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1)
208 		switch (optc) {
209 		case ORD('H'):
210 			how = HARD;
211 			break;
212 		case ORD('S'):
213 			how = SOFT;
214 			break;
215 		case ORD('a'):
216 			all = true;
217 			break;
218 		case ORD('?'):
219 			bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts);
220 			return (1);
221 		default:
222 			what = optc;
223 		}
224 
225 	while (i < NELEM(rlimits)) {
226 		if (rlimits[i]->optchar == what)
227 			goto found;
228 		++i;
229 	}
230 #ifndef RLIMIT_CORE
231 	if (what == ORD('c'))
232 		/* silently accept */
233 		return 0;
234 #endif
235 	internal_warningf("ulimit: %c", what);
236 	return (1);
237  found:
238 	if (wp[builtin_opt.optind]) {
239 		if (all || wp[builtin_opt.optind + 1]) {
240 			bi_errorf(Ttoo_many_args);
241 			return (1);
242 		}
243 		return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how));
244 	}
245 	if (!all)
246 		print_ulimit(rlimits[i], how);
247 	else for (i = 0; i < NELEM(rlimits); ++i) {
248 		shprintf("-%c: %-20s  ", rlimits[i]->optchar, rlimits[i]->name);
249 		print_ulimit(rlimits[i], how);
250 	}
251 	return (0);
252 }
253 
254 #if HAVE_RLIMIT
255 #define RL_T rlim_t
256 #define RL_U (rlim_t)RLIM_INFINITY
257 #else
258 #define RL_T long
259 #define RL_U LONG_MAX
260 #endif
261 
262 static int
set_ulimit(const struct limits * l,const char * v,int how MKSH_A_UNUSED)263 set_ulimit(const struct limits *l, const char *v, int how MKSH_A_UNUSED)
264 {
265 	RL_T val = (RL_T)0;
266 #if HAVE_RLIMIT
267 	struct rlimit limit;
268 #endif
269 
270 	if (strcmp(v, "unlimited") == 0)
271 		val = RL_U;
272 	else {
273 		mksh_uari_t rval;
274 
275 		if (!evaluate(v, (mksh_ari_t *)&rval, KSH_RETURN_ERROR, false))
276 			return (1);
277 		/*
278 		 * Avoid problems caused by typos that evaluate misses due
279 		 * to evaluating unset parameters to 0...
280 		 * If this causes problems, will have to add parameter to
281 		 * evaluate() to control if unset params are 0 or an error.
282 		 */
283 		if (!rval && !ctype(v[0], C_DIGIT)) {
284 			bi_errorf("invalid %s limit: %s", l->name, v);
285 			return (1);
286 		}
287 #if HAVE_RLIMIT
288 		val = (rlim_t)((rlim_t)rval * l->factor);
289 #else
290 		val = (RL_T)rval;
291 #endif
292 	}
293 
294 #if HAVE_RLIMIT
295 	if (getrlimit(l->resource, &limit) < 0) {
296 #ifndef MKSH_SMALL
297 		bi_errorf("limit %s could not be read, contact the mksh developers: %s",
298 		    l->name, cstrerror(errno));
299 #endif
300 		/* some can't be read */
301 		limit.rlim_cur = RLIM_INFINITY;
302 		limit.rlim_max = RLIM_INFINITY;
303 	}
304 	if (how & SOFT)
305 		limit.rlim_cur = val;
306 	if (how & HARD)
307 		limit.rlim_max = val;
308 	if (!setrlimit(l->resource, &limit))
309 		return (0);
310 #else
311 	if (l->writable == false) {
312 	    /* check.t:ulimit-2 fails if we return 1 and/or do:
313 		bi_errorf(Tf_ro, l->name);
314 	    */
315 		return (0);
316 	}
317 	if (ulimit(l->wesource, val) != -1L)
318 		return (0);
319 #endif
320 	if (errno == EPERM)
321 		bi_errorf("%s exceeds allowable %s limit", v, l->name);
322 	else
323 		bi_errorf("bad %s limit: %s", l->name, cstrerror(errno));
324 	return (1);
325 }
326 
327 static void
print_ulimit(const struct limits * l,int how MKSH_A_UNUSED)328 print_ulimit(const struct limits *l, int how MKSH_A_UNUSED)
329 {
330 	RL_T val = (RL_T)0;
331 #if HAVE_RLIMIT
332 	struct rlimit limit;
333 
334 	if (getrlimit(l->resource, &limit))
335 #else
336 	if ((val = ulimit(l->resource, 0)) < 0)
337 #endif
338 	    {
339 		shf_puts("unknown\n", shl_stdout);
340 		return;
341 	}
342 #if HAVE_RLIMIT
343 	if (how & SOFT)
344 		val = limit.rlim_cur;
345 	else if (how & HARD)
346 		val = limit.rlim_max;
347 #endif
348 	if (val == RL_U)
349 		shf_puts("unlimited\n", shl_stdout);
350 	else {
351 #if HAVE_RLIMIT
352 		val /= l->factor;
353 #elif defined(KSH_UL_GBRK)
354 		if (l->resource == KSH_UL_GBRK)
355 			val = (RL_T)(((size_t)val - (size_t)&etext) /
356 			    (size_t)1024);
357 #endif
358 		shprintf("%lu\n", (unsigned long)val);
359 	}
360 }
361