xref: /plan9/sys/src/ape/cmd/pdksh/c_ulimit.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 /*
2 	ulimit -- handle "ulimit" builtin
3 
4 	Reworked to use getrusage() and ulimit() at once (as needed on
5 	some schizophenic systems, eg, HP-UX 9.01), made argument parsing
6 	conform to at&t ksh, added autoconf support.  Michael Rendell, May, '94
7 
8 	Eric Gisin, September 1988
9 	Adapted to PD KornShell. Removed AT&T code.
10 
11 	last edit:	06-Jun-1987	D A Gwyn
12 
13 	This started out as the BRL UNIX System V system call emulation
14 	for 4.nBSD, and was later extended by Doug Kingston to handle
15 	the extended 4.nBSD resource limits.  It now includes the code
16 	that was originally under case SYSULIMIT in source file "xec.c".
17 */
18 
19 #include "sh.h"
20 #include "ksh_time.h"
21 #ifdef HAVE_SYS_RESOURCE_H
22 # include <sys/resource.h>
23 #endif /* HAVE_SYS_RESOURCE_H */
24 #ifdef HAVE_ULIMIT_H
25 # include <ulimit.h>
26 #else /* HAVE_ULIMIT_H */
27 # ifdef HAVE_ULIMIT
28 extern	long ulimit();
29 # endif /* HAVE_ULIMIT */
30 #endif /* HAVE_ULIMIT_H */
31 
32 #define SOFT	0x1
33 #define HARD	0x2
34 
35 #ifdef RLIM_INFINITY
36 # define KSH_RLIM_INFINITY RLIM_INFINITY
37 #else
38 # define KSH_RLIM_INFINITY ((rlim_t) 1 << (sizeof(rlim_t) * 8 - 1) - 1)
39 #endif /* RLIM_INFINITY */
40 
41 int
c_ulimit(wp)42 c_ulimit(wp)
43 	char **wp;
44 {
45 	static const struct limits {
46 		const char	*name;
47 		enum { RLIMIT, ULIMIT } which;
48 		int	gcmd;	/* get command */
49 		int	scmd;	/* set command (or -1, if no set command) */
50 		int	factor;	/* multiply by to get rlim_{cur,max} values */
51 		char	option;
52 	} limits[] = {
53 		/* Do not use options -H, -S or -a */
54 #ifdef RLIMIT_CPU
55 		{ "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' },
56 #endif
57 #ifdef RLIMIT_FSIZE
58 		{ "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' },
59 #else /* RLIMIT_FSIZE */
60 # ifdef UL_GETFSIZE /* x/open */
61 		{ "file(blocks)", ULIMIT, UL_GETFSIZE, UL_SETFSIZE, 1, 'f' },
62 # else /* UL_GETFSIZE */
63 #  ifdef UL_GFILLIM /* svr4/xenix */
64 		{ "file(blocks)", ULIMIT, UL_GFILLIM, UL_SFILLIM, 1, 'f' },
65 #  else /* UL_GFILLIM */
66 		{ "file(blocks)", ULIMIT, 1, 2, 1, 'f' },
67 #  endif /* UL_GFILLIM */
68 # endif /* UL_GETFSIZE */
69 #endif /* RLIMIT_FSIZE */
70 #ifdef RLIMIT_CORE
71 		{ "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' },
72 #endif
73 #ifdef RLIMIT_DATA
74 		{ "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' },
75 #endif
76 #ifdef RLIMIT_STACK
77 		{ "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' },
78 #endif
79 #ifdef RLIMIT_MEMLOCK
80 		{ "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, 1024, 'l' },
81 #endif
82 #ifdef RLIMIT_RSS
83 		{ "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' },
84 #endif
85 #ifdef RLIMIT_NOFILE
86 		{ "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE, 1, 'n' },
87 #else /* RLIMIT_NOFILE */
88 # ifdef UL_GDESLIM /* svr4/xenix */
89 		{ "nofiles(descriptors)", ULIMIT, UL_GDESLIM, -1, 1, 'n' },
90 # endif /* UL_GDESLIM */
91 #endif /* RLIMIT_NOFILE */
92 #ifdef RLIMIT_NPROC
93 		{ "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' },
94 #endif
95 #ifdef RLIMIT_VMEM
96 		{ "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
97 #else /* RLIMIT_VMEM */
98   /* These are not quite right - really should subtract etext or something */
99 # ifdef UL_GMEMLIM /* svr4/xenix */
100 		{ "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' },
101 # else /* UL_GMEMLIM */
102 #  ifdef UL_GETBREAK /* osf/1 */
103 		{ "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' },
104 #  else /* UL_GETBREAK */
105 #   ifdef UL_GETMAXBRK /* hpux */
106 		{ "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' },
107 #   endif /* UL_GETMAXBRK */
108 #  endif /* UL_GETBREAK */
109 # endif /* UL_GMEMLIM */
110 #endif /* RLIMIT_VMEM */
111 #ifdef RLIMIT_SWAP
112 		{ "swap(kbytes)", RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
113 #endif
114 		{ (char *) 0 }
115 	    };
116 	static char	options[3 + NELEM(limits)];
117 	rlim_t		UNINITIALIZED(val);
118 	int		how = SOFT | HARD;
119 	const struct limits	*l;
120 	int		set, all = 0;
121 	int		optc, what;
122 #ifdef HAVE_SETRLIMIT
123 	struct rlimit	limit;
124 #endif /* HAVE_SETRLIMIT */
125 
126 	if (!options[0]) {
127 		/* build options string on first call - yuck */
128 		char *p = options;
129 
130 		*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
131 		for (l = limits; l->name; l++)
132 			*p++ = l->option;
133 		*p = '\0';
134 	}
135 	what = 'f';
136 	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
137 		switch (optc) {
138 		  case 'H':
139 			how = HARD;
140 			break;
141 		  case 'S':
142 			how = SOFT;
143 			break;
144 		  case 'a':
145 			all = 1;
146 			break;
147 		  case '?':
148 			return 1;
149 		  default:
150 			what = optc;
151 		}
152 
153 	for (l = limits; l->name && l->option != what; l++)
154 		;
155 	if (!l->name) {
156 		internal_errorf(0, "ulimit: %c", what);
157 		return 1;
158 	}
159 
160 	wp += builtin_opt.optind;
161 	set = *wp ? 1 : 0;
162 	if (set) {
163 		if (all || wp[1]) {
164 			bi_errorf("too many arguments");
165 			return 1;
166 		}
167 		if (strcmp(wp[0], "unlimited") == 0)
168 			val = KSH_RLIM_INFINITY;
169 		else {
170 			long rval;
171 
172 			if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
173 				return 1;
174 			/* Avoid problems caused by typos that
175 			 * evaluate misses due to evaluating unset
176 			 * parameters to 0...
177 			 * If this causes problems, will have to
178 			 * add parameter to evaluate() to control
179 			 * if unset params are 0 or an error.
180 			 */
181 			if (!rval && !digit(wp[0][0])) {
182 			    bi_errorf("invalid limit: %s", wp[0]);
183 			    return 1;
184 			}
185 			val = rval * l->factor;
186 		}
187 	}
188 	if (all) {
189 		for (l = limits; l->name; l++) {
190 #ifdef HAVE_SETRLIMIT
191 			if (l->which == RLIMIT) {
192 				getrlimit(l->gcmd, &limit);
193 				if (how & SOFT)
194 					val = limit.rlim_cur;
195 				else if (how & HARD)
196 					val = limit.rlim_max;
197 			} else
198 #endif /* HAVE_SETRLIMIT */
199 #ifdef HAVE_ULIMIT
200 			{
201 				val = ulimit(l->gcmd, (rlim_t) 0);
202 			}
203 #else /* HAVE_ULIMIT */
204 				;
205 #endif /* HAVE_ULIMIT */
206 			shprintf("%-20s ", l->name);
207 #ifdef RLIM_INFINITY
208 			if (val == RLIM_INFINITY)
209 				shprintf("unlimited\n");
210 			else
211 #endif /* RLIM_INFINITY */
212 			{
213 				val /= l->factor;
214 				shprintf("%ld\n", (long) val);
215 			}
216 		}
217 		return 0;
218 	}
219 #ifdef HAVE_SETRLIMIT
220 	if (l->which == RLIMIT) {
221 		getrlimit(l->gcmd, &limit);
222 		if (set) {
223 			if (how & SOFT)
224 				limit.rlim_cur = val;
225 			if (how & HARD)
226 				limit.rlim_max = val;
227 			if (setrlimit(l->scmd, &limit) < 0) {
228 				if (errno == EPERM)
229 					bi_errorf("exceeds allowable limit");
230 				else
231 					bi_errorf("bad limit: %s",
232 						strerror(errno));
233 				return 1;
234 			}
235 		} else {
236 			if (how & SOFT)
237 				val = limit.rlim_cur;
238 			else if (how & HARD)
239 				val = limit.rlim_max;
240 		}
241 	} else
242 #endif /* HAVE_SETRLIMIT */
243 #ifdef HAVE_ULIMIT
244 	{
245 		if (set) {
246 			if (l->scmd == -1) {
247 				bi_errorf("can't change limit");
248 				return 1;
249 			} else if (ulimit(l->scmd, val) < 0) {
250 				bi_errorf("bad limit: %s", strerror(errno));
251 				return 1;
252 			}
253 		} else
254 			val = ulimit(l->gcmd, (rlim_t) 0);
255 	}
256 #else /* HAVE_ULIMIT */
257 		;
258 #endif /* HAVE_ULIMIT */
259 	if (!set) {
260 #ifdef RLIM_INFINITY
261 		if (val == RLIM_INFINITY)
262 			shprintf("unlimited\n");
263 		else
264 #endif /* RLIM_INFINITY */
265 		{
266 			val /= l->factor;
267 			shprintf("%ld\n", (long) val);
268 		}
269 	}
270 	return 0;
271 }
272