loksh-noxz

[fork] a Linux port of OpenBSD's ksh
git clone https://noxz.tech/git/loksh-noxz.git
Log | Files | README

c_ulimit.c
1/*	$OpenBSD: c_ulimit.c,v 1.29 2019/06/28 13:34:59 deraadt 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
21#include <sys/resource.h>
22
23#include <ctype.h>
24#include <errno.h>
25#include <inttypes.h>
26#include <string.h>
27
28#include "sh.h"
29
30#define SOFT	0x1
31#define HARD	0x2
32
33struct limits {
34	const char *name;
35	int	resource;	/* resource to get/set */
36	int	factor;		/* multiply by to get rlim_{cur,max} values */
37	char	option;		/* option character (-d, -f, ...) */
38};
39
40static void print_ulimit(const struct limits *, int);
41static int set_ulimit(const struct limits *, const char *, int);
42
43int
44c_ulimit(char **wp)
45{
46	static const struct limits limits[] = {
47		/* Do not use options -H, -S or -a or change the order. */
48		{ "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
49		{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
50		{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
51		{ "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
52		{ "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
53		{ "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
54		{ "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
55		{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
56		{ "processes", RLIMIT_NPROC, 1, 'p' },
57		{ NULL }
58	};
59	const char	*options = "HSat#f#c#d#s#l#m#n#p#";
60	int		how = SOFT | HARD;
61	const struct limits	*l;
62	int		optc, all = 0;
63
64	/* First check for -a, -H and -S. */
65	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
66		switch (optc) {
67		case 'H':
68			how = HARD;
69			break;
70		case 'S':
71			how = SOFT;
72			break;
73		case 'a':
74			all = 1;
75			break;
76		case '?':
77			return 1;
78		default:
79			break;
80		}
81
82	if (wp[builtin_opt.optind] != NULL) {
83		bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]");
84		return 1;
85	}
86
87	/* Then parse and act on the actual limits, one at a time */
88	ksh_getopt_reset(&builtin_opt, GF_ERROR);
89	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
90		switch (optc) {
91		case 'a':
92		case 'H':
93		case 'S':
94			break;
95		case '?':
96			return 1;
97		default:
98			for (l = limits; l->name && l->option != optc; l++)
99				;
100			if (!l->name) {
101				internal_warningf("%s: %c", __func__, optc);
102				return 1;
103			}
104			if (builtin_opt.optarg) {
105				if (set_ulimit(l, builtin_opt.optarg, how))
106					return 1;
107			} else
108				print_ulimit(l, how);
109			break;
110		}
111
112	wp += builtin_opt.optind;
113
114	if (all) {
115		for (l = limits; l->name; l++) {
116			shprintf("%-20s ", l->name);
117			print_ulimit(l, how);
118		}
119	} else if (builtin_opt.optind == 1) {
120		/* No limit specified, use file size */
121		l = &limits[1];
122		if (wp[0] != NULL) {
123			if (set_ulimit(l, wp[0], how))
124				return 1;
125			wp++;
126		} else {
127			print_ulimit(l, how);
128		}
129	}
130
131	return 0;
132}
133
134static int
135set_ulimit(const struct limits *l, const char *v, int how)
136{
137	rlim_t		val = 0;
138	struct rlimit	limit;
139
140	if (strcmp(v, "unlimited") == 0)
141		val = RLIM_INFINITY;
142	else {
143		int64_t rval;
144
145		if (!evaluate(v, &rval, KSH_RETURN_ERROR, false))
146			return 1;
147		/*
148		 * Avoid problems caused by typos that evaluate misses due
149		 * to evaluating unset parameters to 0...
150		 * If this causes problems, will have to add parameter to
151		 * evaluate() to control if unset params are 0 or an error.
152		 */
153		if (!rval && !digit(v[0])) {
154			bi_errorf("invalid limit: %s", v);
155			return 1;
156		}
157		val = (rlim_t)rval * l->factor;
158	}
159
160	getrlimit(l->resource, &limit);
161	if (how & SOFT)
162		limit.rlim_cur = val;
163	if (how & HARD)
164		limit.rlim_max = val;
165	if (setrlimit(l->resource, &limit) == -1) {
166		if (errno == EPERM)
167			bi_errorf("-%c exceeds allowable limit", l->option);
168		else
169			bi_errorf("bad -%c limit: %s", l->option,
170			    strerror(errno));
171		return 1;
172	}
173	return 0;
174}
175
176static void
177print_ulimit(const struct limits *l, int how)
178{
179	rlim_t		val = 0;
180	struct rlimit	limit;
181
182	getrlimit(l->resource, &limit);
183	if (how & SOFT)
184		val = limit.rlim_cur;
185	else if (how & HARD)
186		val = limit.rlim_max;
187	if (val == RLIM_INFINITY)
188		shprintf("unlimited\n");
189	else {
190		val /= l->factor;
191		shprintf("%" PRIi64 "\n", (int64_t) val);
192	}
193}