GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/ksh/c_ulimit.c Lines: 37 75 49.3 %
Date: 2017-11-07 Branches: 28 64 43.8 %

Line Branch Exec Source
1
/*	$OpenBSD: c_ulimit.c,v 1.24 2015/12/14 13:59:42 tb 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 <string.h>
26
27
#include "sh.h"
28
29
#define SOFT	0x1
30
#define HARD	0x2
31
32
struct limits {
33
	const char *name;
34
	int	resource;	/* resource to get/set */
35
	int	factor;		/* multiply by to get rlim_{cur,max} values */
36
	char	option;		/* option character (-d, -f, ...) */
37
};
38
39
static void print_ulimit(const struct limits *, int);
40
static int set_ulimit(const struct limits *, const char *, int);
41
42
int
43
c_ulimit(char **wp)
44
{
45
	static const struct limits limits[] = {
46
		/* Do not use options -H, -S or -a or change the order. */
47
		{ "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
48
		{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
49
		{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
50
		{ "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
51
		{ "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
52
		{ "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
53
		{ "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
54
		{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
55
		{ "processes", RLIMIT_NPROC, 1, 'p' },
56
#ifdef RLIMIT_VMEM
57
		{ "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
58
#endif /* RLIMIT_VMEM */
59
		{ NULL }
60
	};
61
	static char	options[4 + NELEM(limits) * 2];
62
	int		how = SOFT | HARD;
63
	const struct limits	*l;
64
	int		optc, all = 0;
65
66
3342
	if (!options[0]) {
67
		/* build options string on first call - yuck */
68
		char *p = options;
69
70
1671
		*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
71
33420
		for (l = limits; l->name; l++) {
72
15039
			*p++ = l->option;
73
15039
			*p++ = '#';
74
		}
75
1671
		*p = '\0';
76
1671
	}
77
	/* First check for -a, -H and -S. */
78
3342
	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
79

1671
		switch (optc) {
80
		case 'H':
81
			how = HARD;
82
			break;
83
		case 'S':
84
			how = SOFT;
85
			break;
86
		case 'a':
87
			all = 1;
88
			break;
89
		case '?':
90
			return 1;
91
		default:
92
			break;
93
		}
94
95
1671
	if (wp[builtin_opt.optind] != NULL) {
96
		bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]");
97
		return 1;
98
	}
99
100
	/* Then parse and act on the actual limits, one at a time */
101
1671
	ksh_getopt_reset(&builtin_opt, GF_ERROR);
102
5013
	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
103

3342
		switch (optc) {
104
		case 'a':
105
		case 'H':
106
		case 'S':
107
			break;
108
		case '?':
109
			return 1;
110
		default:
111

32040
			for (l = limits; l->name && l->option != optc; l++)
112
				;
113
1671
			if (!l->name) {
114
				internal_errorf(0, "ulimit: %c", optc);
115
				return 1;
116
			}
117
1671
			if (builtin_opt.optarg) {
118
1671
				if (set_ulimit(l, builtin_opt.optarg, how))
119
					return 1;
120
			} else
121
				print_ulimit(l, how);
122
			break;
123
		}
124
125
1671
	wp += builtin_opt.optind;
126
127
1671
	if (all) {
128
		for (l = limits; l->name; l++) {
129
			shprintf("%-20s ", l->name);
130
			print_ulimit(l, how);
131
		}
132
1671
	} else if (builtin_opt.optind == 1) {
133
		/* No limit specified, use file size */
134
		l = &limits[1];
135
		if (wp[0] != NULL) {
136
			if (set_ulimit(l, wp[0], how))
137
				return 1;
138
			wp++;
139
		} else {
140
			print_ulimit(l, how);
141
		}
142
	}
143
144
1671
	return 0;
145
1671
}
146
147
static int
148
set_ulimit(const struct limits *l, const char *v, int how)
149
{
150
	rlim_t		val = 0;
151
3342
	struct rlimit	limit;
152
153
1671
	if (strcmp(v, "unlimited") == 0)
154
		val = RLIM_INFINITY;
155
	else {
156
1671
		long rval;
157
158
1671
		if (!evaluate(v, &rval, KSH_RETURN_ERROR, false))
159
			return 1;
160
		/*
161
		 * Avoid problems caused by typos that evaluate misses due
162
		 * to evaluating unset parameters to 0...
163
		 * If this causes problems, will have to add parameter to
164
		 * evaluate() to control if unset params are 0 or an error.
165
		 */
166

1706
		if (!rval && !digit(v[0])) {
167
			bi_errorf("invalid limit: %s", v);
168
			return 1;
169
		}
170
1671
		val = (rlim_t)rval * l->factor;
171
3342
	}
172
173
1671
	getrlimit(l->resource, &limit);
174
1671
	if (how & SOFT)
175
1671
		limit.rlim_cur = val;
176
1671
	if (how & HARD)
177
1671
		limit.rlim_max = val;
178
1671
	if (setrlimit(l->resource, &limit) < 0) {
179
		if (errno == EPERM)
180
			bi_errorf("-%c exceeds allowable limit", l->option);
181
		else
182
			bi_errorf("bad -%c limit: %s", l->option,
183
			    strerror(errno));
184
		return 1;
185
	}
186
1671
	return 0;
187
1671
}
188
189
static void
190
print_ulimit(const struct limits *l, int how)
191
{
192
	rlim_t		val = 0;
193
	struct rlimit	limit;
194
195
	getrlimit(l->resource, &limit);
196
	if (how & SOFT)
197
		val = limit.rlim_cur;
198
	else if (how & HARD)
199
		val = limit.rlim_max;
200
	if (val == RLIM_INFINITY)
201
		shprintf("unlimited\n");
202
	else {
203
		val /= l->factor;
204
		shprintf("%ld\n", (long) val);
205
	}
206
}