GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/ksh/c_ulimit.c Lines: 37 78 47.4 %
Date: 2016-12-06 Branches: 25 60 41.7 %

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
2
{
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
2
	int		how = SOFT | HARD;
63
	const struct limits	*l;
64
2
	int		optc, all = 0;
65
66
2
	if (!options[0]) {
67
		/* build options string on first call - yuck */
68
2
		char *p = options;
69
70
2
		*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
71
20
		for (l = limits; l->name; l++) {
72
18
			*p++ = l->option;
73
18
			*p++ = '#';
74
		}
75
2
		*p = '\0';
76
	}
77
	/* First check for -a, -H and -S. */
78
4
	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
79

2
		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
2
	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
2
	ksh_getopt_reset(&builtin_opt, GF_ERROR);
102
6
	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
103
2
		switch (optc) {
104
		case 'a':
105
		case 'H':
106
		case 'S':
107
			break;
108
		case '?':
109
			return 1;
110
		default:
111

2
			for (l = limits; l->name && l->option != optc; l++)
112
				;
113
2
			if (!l->name) {
114
				internal_errorf(0, "ulimit: %c", optc);
115
				return 1;
116
			}
117
2
			if (builtin_opt.optarg) {
118
2
				if (set_ulimit(l, builtin_opt.optarg, how))
119
					return 1;
120
			} else
121
				print_ulimit(l, how);
122
			break;
123
		}
124
125
2
	wp += builtin_opt.optind;
126
127
2
	if (all) {
128
		for (l = limits; l->name; l++) {
129
			shprintf("%-20s ", l->name);
130
			print_ulimit(l, how);
131
		}
132
2
	} 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
2
	return 0;
145
}
146
147
static int
148
set_ulimit(const struct limits *l, const char *v, int how)
149
2
{
150
2
	rlim_t		val = 0;
151
	struct rlimit	limit;
152
153
2
	if (strcmp(v, "unlimited") == 0)
154
		val = RLIM_INFINITY;
155
	else {
156
		long rval;
157
158
2
		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

2
		if (!rval && !digit(v[0])) {
167
			bi_errorf("invalid limit: %s", v);
168
			return 1;
169
		}
170
2
		val = (rlim_t)rval * l->factor;
171
	}
172
173
2
	getrlimit(l->resource, &limit);
174
2
	if (how & SOFT)
175
2
		limit.rlim_cur = val;
176
2
	if (how & HARD)
177
2
		limit.rlim_max = val;
178
2
	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
2
	return 0;
187
}
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
}