GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/ksh/c_ulimit.c Lines: 37 75 49.3 %
Date: 2017-11-13 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
1880
	if (!options[0]) {
67
		/* build options string on first call - yuck */
68
		char *p = options;
69
70
940
		*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
71
18800
		for (l = limits; l->name; l++) {
72
8460
			*p++ = l->option;
73
8460
			*p++ = '#';
74
		}
75
940
		*p = '\0';
76
940
	}
77
	/* First check for -a, -H and -S. */
78
3760
	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
79

940
		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
940
	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
940
	ksh_getopt_reset(&builtin_opt, GF_ERROR);
102
3760
	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
103

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

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

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