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