1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * A copy of the CDDL is also available via the Internet at
11  * http://www.opensource.org/licenses/cddl1.txt
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 
24 /*
25  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
30 /*	  All Rights Reserved  	*/
31 
32 #if defined(sun)
33 #pragma ident	"@(#)ulimit.c	1.14	06/06/16 SMI"
34 #endif
35 
36 /*
37  * Copyright 2008-2017 J. Schilling
38  *
39  * @(#)ulimit.c	1.27 17/12/20 2008-2017 J. Schilling
40  */
41 #ifdef	SCHILY_INCLUDES
42 #include <schily/mconfig.h>
43 #endif
44 #ifndef lint
45 static	UConst char sccsid[] =
46 	"@(#)ulimit.c	1.27 17/12/20 2008-2017 J. Schilling";
47 #endif
48 
49 /*
50  * ulimit builtin
51  */
52 
53 #ifdef	SCHILY_INCLUDES
54 #include <schily/time.h>
55 #include <schily/resource.h>
56 #else
57 #include <sys/resource.h>
58 #include <stdlib.h>
59 #endif
60 
61 #include "defs.h"
62 
63 static char	unlimited[] = "unlimited";
64 
65 static struct rlimtab {
66 	int		value;
67 	char		*name;
68 	char		*aname;
69 	char		*scale;
70 	unsigned char	option;
71 	rlim_t		divisor;
72 } rlimtab[] = {
73 #ifdef	RLIMIT_CPU
74 {	RLIMIT_CPU,	"time",		"cputime",	"seconds", 't', 1, },
75 #endif
76 #ifdef	RLIMIT_FSIZE
77 {	RLIMIT_FSIZE,	"file",		"filesize",	"blocks",  'f', 512, },
78 #endif
79 #ifdef	RLIMIT_DATA
80 {	RLIMIT_DATA,	"data",		"datasize",	"kbytes",  'd', 1024, },
81 #endif
82 #ifdef	RLIMIT_STACK
83 {	RLIMIT_STACK,	"stack",	"stacksize",	"kbytes",  's', 1024, },
84 #endif
85 #ifdef	RLIMIT_CORE
86 {	RLIMIT_CORE,	"coredump",	"coredumpsize",	"blocks",  'c', 512, },
87 #endif
88 #ifdef	RLIMIT_MEMLOCK
89 {	RLIMIT_MEMLOCK,	"memlock",	"memorylocked",	"kbytes",  'l', 1024 },
90 #endif
91 #ifdef	RLIMIT_RSS
92 {	RLIMIT_RSS,	"memoryuse",	NULL,		"kbytes",  'm', 1024, },
93 #endif
94 #if	defined(RLIMIT_UMEM) && !!defined(RLIMIT_RSS)
95 {	RLIMIT_UMEM,	"memoryuse",	NULL,		"kbytes",  'm', 1024, },
96 #endif
97 #ifdef	RLIMIT_NOFILE
98 {	RLIMIT_NOFILE,	"nofiles",	"descriptors",	"descriptors",
99 								    'n', 1, },
100 #endif
101 #if	defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
102 {	RLIMIT_OFILE,	"nofiles",	"descriptors",	"descriptors",
103 								    'n', 1, },
104 #endif
105 #ifdef	RLIMIT_NPROC
106 {	RLIMIT_NPROC,	"processes",	"nproc",	"count",   'u', 1 },
107 #endif
108 #ifdef	RLIMIT_VMEM
109 {	RLIMIT_VMEM,	"memory",	"vmemsize",	"kbytes",  'v', 1024, },
110 #endif
111 #ifdef	RLIMIT_AS
112 {	RLIMIT_AS,	"addressspace",	NULL,		"kbytes",  'M', 1024, },
113 #endif
114 #ifdef	RLIMIT_HEAP	/* BS2000/OSD */
115 {	RLIMIT_HEAP,	"heapsize",	NULL,		"kBytes", '\0', 1024, },
116 #endif
117 #ifdef	RLIMIT_CONCUR	/* CONVEX max. # of processors per process */
118 {	RLIMIT_CONCUR,	"concurrency",	NULL,		"thread(s)", '\0', 1 },
119 #endif
120 #ifdef	RLIMIT_NICE
121 {	RLIMIT_NICE,	"schedpriority", "maxnice",	"nice",	   'e', 1, },
122 #endif
123 #ifdef	RLIMIT_SIGPENDING
124 {	RLIMIT_SIGPENDING, "sigpending", NULL,		"count",   'i', 1, },
125 #endif
126 #ifdef	RLIMIT_NPTS	/* FreeBSD maximum # of pty's */
127 {	RLIMIT_NPTS,	"npty",		 NULL,		"count",   'P', 1, },
128 #endif
129 #ifdef	RLIMIT_MSGQUEUE
130 {	RLIMIT_MSGQUEUE, "messagequeues", "msgqueues",	"count",   'q', 1, },
131 #endif
132 #ifdef	RLIMIT_RTPRIO
133 {	RLIMIT_RTPRIO,	"rtpriority",	"maxrtprio",	"nice",	   'r', 1, },
134 #endif
135 #ifdef	RLIMIT_SWAP
136 {	RLIMIT_SWAP,	"swap",		"swapsize",	"kbytes",  'w', 1024, },
137 #endif
138 #ifdef	RLIMIT_RTTIME
139 {	RLIMIT_RTTIME,	"rttime",	"maxrttime",	"usec",	   'R', 1, },
140 #endif
141 #ifdef	RLIMIT_LOCKS
142 {	RLIMIT_LOCKS,	"locks",	"filelocks",	"count",   'L', 1, },
143 /* bash compat: -x */
144 {	RLIMIT_LOCKS,	"locks",	NULL,		"count",   'x', 1, },
145 #endif
146 #ifdef	RLIMIT_SBSIZE	/* FreeBSD maximum size of all socket buffers */
147 {	RLIMIT_SBSIZE,	"sbsize",	NULL,		"bytes",   'b', 1, },
148 #endif
149 #ifdef	RLIMIT_KQUEUES	/* FreeBSD kqueues allocated */
150 {	RLIMIT_KQUEUES,	"kqueues",	NULL,		"count",   'k', 1, },
151 #endif
152 #ifdef	RLIMIT_UMTXP	/* FreeBSD process-shared umtx */
153 {	RLIMIT_UMTXP,	"umtx shared locks",	NULL,	"count",   'o', 1, },
154 #endif
155 
156 {	0,		NULL,		NULL,	NULL,		0, 0,	},
157 };
158 
159 	void	sysulimit	__PR((int argc, unsigned char **argv));
160 
161 void
sysulimit(argc,argv)162 sysulimit(argc, argv)
163 	int		argc;
164 	unsigned char	**argv;
165 {
166 	struct optv optv;
167 	unsigned char *args;
168 	char errargs[PATH_MAX];
169 	int hard, soft, cnt, c, res;
170 	rlim_t limit, new_limit;
171 	struct rlimit rlimit;
172 	char resources[RLIM_NLIMITS];
173 	struct rlimtab *rlp;
174 #ifdef	DO_SYSLIMIT
175 	int	bsdmode = argv[0][0] == 'l';
176 #else
177 #define	bsdmode	0
178 #endif
179 
180 	for (res = 0;  res < RLIM_NLIMITS; res++) {
181 		resources[res] = 0;
182 	}
183 
184 	optinit(&optv);
185 	hard = 0;
186 	soft = 0;
187 	cnt = 0;
188 
189 	while ((c = optget(argc, argv, &optv,
190 			    "HSacdefilmnqrstuvxLMPR")) != -1) {
191 		switch (c) {
192 		case 'S':
193 			soft++;
194 			continue;
195 		case 'H':
196 			hard++;
197 			continue;
198 		case 'a':
199 			for (res = 0;  res < RLIM_NLIMITS; res++) {
200 				resources[res]++;
201 			}
202 #ifdef	RLIM_NLIMITS
203 			cnt = RLIM_NLIMITS;
204 #endif
205 			continue;
206 
207 		default:
208 			for (rlp = rlimtab; rlp->name; rlp++) {
209 				if (rlp->option == c) {
210 					res = rlp->value;
211 					break;
212 				}
213 			}
214 			break;
215 
216 		case '?':
217 #ifdef	DO_SYSLIMIT
218 			gfailure(UC usage, bsdmode ? limuse : ulimuse);
219 #else
220 			gfailure(UC usage, ulimuse);
221 #endif
222 			return;
223 		}
224 		resources[res]++;
225 		cnt++;
226 	}
227 #ifdef	DO_SYSLIMIT
228 	if (cnt == 0 && optv.optind < argc) {
229 		args = argv[optv.optind];
230 		res = -1;
231 
232 		for (rlp = rlimtab; rlp->name; rlp++) {
233 			if (strstr(rlp->name, C args) == rlp->name ||
234 			    (rlp->aname &&
235 			    strstr(rlp->aname, C args) == rlp->aname)) {
236 				if (res >= 0) {
237 					failure(args, ambiguous);
238 					return;
239 				}
240 				res = rlp->value;
241 			}
242 		}
243 		if (res < 0) {
244 			failure(args, enoent);
245 			return;
246 		}
247 		resources[res]++;
248 		cnt++;
249 		optv.optind++;
250 		bsdmode++;
251 	}
252 #endif
253 
254 #ifdef	RLIMIT_FSIZE
255 	if (cnt == 0) {
256 #ifdef	DO_SYSLIMIT
257 		if (bsdmode) {
258 			for (res = 0;  res < RLIM_NLIMITS; res++) {
259 				resources[res] = 1;
260 			}
261 			cnt++;
262 		}
263 #endif
264 		resources[res = RLIMIT_FSIZE]++;
265 		cnt++;
266 	}
267 #endif
268 
269 	/*
270 	 * if out of arguments, then print the specified resources
271 	 */
272 	if (optv.optind == argc) {
273 #ifdef	DO_SYSLIMIT
274 		if (bsdmode && !hard && !soft) {
275 			hard++;
276 			soft++;
277 		}
278 #endif
279 		/*
280 		 * No extra args, so we are in list mode.
281 		 */
282 		if (!hard && !soft) {
283 			soft++;
284 		}
285 		for (res = 0; res < RLIM_NLIMITS; res++) {
286 			if (resources[res] == 0) {
287 				continue;
288 			}
289 			for (rlp = rlimtab; rlp->name; rlp++) {
290 				if (rlp->value == res)
291 					break;
292 			}
293 			if (rlp->name == NULL)
294 				continue;
295 			if (getrlimit(res, &rlimit) < 0) {
296 				continue;
297 			}
298 			if (cnt > 1 || bsdmode) {
299 #ifdef	DO_ULIMIT_OPTS
300 				if (!bsdmode) {
301 					prc_buff('-');
302 					prc_buff(rlp->option);
303 					prc_buff(':');
304 					prc_buff(' ');
305 				}
306 #endif
307 #ifdef	DO_SYSLIMIT
308 				if (bsdmode && rlp->aname)
309 					prs_buff(_gettext(rlp->aname));
310 				else
311 #endif
312 					prs_buff(_gettext(rlp->name));
313 				prc_buff('(');
314 				prs_buff(_gettext(rlp->scale));
315 				prc_buff(')');
316 				prc_buff(' ');
317 			}
318 			if (soft) {
319 				if (rlimit.rlim_cur == RLIM_INFINITY) {
320 					prs_buff(_gettext(unlimited));
321 				} else  {
322 					prull_buff((UIntmax_t)rlimit.rlim_cur /
323 					    rlp->divisor);
324 				}
325 			}
326 			if (hard && soft) {
327 #ifdef	DO_SYSLIMIT
328 				if (bsdmode)
329 					prc_buff('\t');
330 				else
331 #endif
332 					prc_buff(':');
333 			}
334 			if (hard) {
335 				if (rlimit.rlim_max == RLIM_INFINITY) {
336 					prs_buff(_gettext(unlimited));
337 				} else  {
338 					prull_buff((UIntmax_t)rlimit.rlim_max /
339 					    rlp->divisor);
340 				}
341 			}
342 			prc_buff('\n');
343 		}
344 		return;
345 	}
346 
347 	if (cnt > 1 || optv.optind + 1 != argc) {
348 #ifdef	DO_SYSLIMIT
349 		gfailure(UC usage, bsdmode ? limuse : ulimuse);
350 #else
351 		gfailure(UC usage, ulimuse);
352 #endif
353 		return;
354 	}
355 
356 #ifdef	DO_SYSLIMIT
357 	if (strstr(unlimited, C argv[optv.optind]) == unlimited) {
358 #else
359 	if (eq(argv[optv.optind], unlimited)) {
360 #endif
361 		limit = RLIM_INFINITY;
362 	} else {
363 		args = argv[optv.optind];
364 
365 		new_limit = limit = 0;
366 		do {
367 			if (*args < '0' || *args > '9') {
368 				snprintf(errargs, PATH_MAX-1,
369 				"%s: %s", argv[0], args);
370 				failure((unsigned char *)errargs, badnum);
371 				return;
372 			}
373 			/* Check for overflow! */
374 			new_limit = (limit * 10) + (*args - '0');
375 			if (new_limit >= limit) {
376 				limit = new_limit;
377 			} else {
378 				snprintf(errargs, PATH_MAX-1,
379 				"%s: %s", argv[0], args);
380 				failure((unsigned char *)errargs, badnum);
381 				return;
382 			}
383 		} while (*++args);
384 
385 		for (rlp = rlimtab; rlp->name; rlp++) {
386 			if (rlp->value == res)
387 				break;
388 		}
389 		if (rlp->name == NULL)
390 			goto fail;
391 
392 		/* Check for overflow! */
393 		new_limit = limit * rlp->divisor;
394 		if (new_limit >= limit) {
395 			limit = new_limit;
396 		} else {
397 			snprintf(errargs, PATH_MAX-1,
398 			"%s: %s", argv[0], args);
399 			failure((unsigned char *)errargs, badnum);
400 			return;
401 		}
402 	}
403 
404 	if (getrlimit(res, &rlimit) < 0) {
405 		failure((unsigned char *)argv[0], badnum);
406 		return;
407 	}
408 
409 #ifdef	DO_SYSLIMIT
410 	if (bsdmode && !hard && !soft) {
411 		soft++;
412 	}
413 #endif
414 	if (!hard && !soft) {
415 		hard++;
416 		soft++;
417 	}
418 	if (hard) {
419 		rlimit.rlim_max = limit;
420 	}
421 	if (soft) {
422 		rlimit.rlim_cur = limit;
423 	}
424 
425 	if (setrlimit(res, &rlimit) < 0) {
426 	fail:
427 		snprintf(errargs, PATH_MAX-1,
428 		"%s: %s", argv[0], argv[optv.optind]);
429 		failure((unsigned char *)errargs, badulimit);
430 	}
431 }
432