xref: /freebsd/bin/sh/miscbltin.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  * The ulimit() builtin has been contributed by Joerg Wunsch.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by the University of
20  *	California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	$Id: miscbltin.c,v 1.3 1995/10/19 18:42:10 joerg Exp $
38  */
39 
40 #ifndef lint
41 static char sccsid[] = "@(#)miscbltin.c	8.2 (Berkeley) 4/16/94";
42 #endif /* not lint */
43 
44 /*
45  * Miscelaneous builtins.
46  */
47 
48 #include "shell.h"
49 #include "options.h"
50 #include "var.h"
51 #include "output.h"
52 #include "memalloc.h"
53 #include "error.h"
54 #include "mystring.h"
55 
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <errno.h>
60 
61 #if BSD
62 #include <limits.h>
63 #include <sys/types.h>
64 #include <sys/time.h>
65 #include <sys/resource.h>
66 #endif
67 
68 #undef eflag
69 
70 extern char **argptr;		/* argument list for builtin command */
71 
72 
73 /*
74  * The read builtin.  The -e option causes backslashes to escape the
75  * following character.
76  *
77  * This uses unbuffered input, which may be avoidable in some cases.
78  */
79 
80 readcmd(argc, argv)  char **argv; {
81 	char **ap;
82 	int backslash;
83 	char c;
84 	int eflag;
85 	char *prompt;
86 	char *ifs;
87 	char *p;
88 	int startword;
89 	int status;
90 	int i;
91 
92 	eflag = 0;
93 	prompt = NULL;
94 	while ((i = nextopt("ep:")) != '\0') {
95 		if (i == 'p')
96 			prompt = optarg;
97 		else
98 			eflag = 1;
99 	}
100 	if (prompt && isatty(0)) {
101 		out2str(prompt);
102 		flushall();
103 	}
104 	if (*(ap = argptr) == NULL)
105 		error("arg count");
106 	if ((ifs = bltinlookup("IFS", 1)) == NULL)
107 		ifs = nullstr;
108 	status = 0;
109 	startword = 1;
110 	backslash = 0;
111 	STARTSTACKSTR(p);
112 	for (;;) {
113 		if (read(0, &c, 1) != 1) {
114 			status = 1;
115 			break;
116 		}
117 		if (c == '\0')
118 			continue;
119 		if (backslash) {
120 			backslash = 0;
121 			if (c != '\n')
122 				STPUTC(c, p);
123 			continue;
124 		}
125 		if (eflag && c == '\\') {
126 			backslash++;
127 			continue;
128 		}
129 		if (c == '\n')
130 			break;
131 		if (startword && *ifs == ' ' && strchr(ifs, c)) {
132 			continue;
133 		}
134 		startword = 0;
135 		if (backslash && c == '\\') {
136 			if (read(0, &c, 1) != 1) {
137 				status = 1;
138 				break;
139 			}
140 			STPUTC(c, p);
141 		} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
142 			STACKSTRNUL(p);
143 			setvar(*ap, stackblock(), 0);
144 			ap++;
145 			startword = 1;
146 			STARTSTACKSTR(p);
147 		} else {
148 			STPUTC(c, p);
149 		}
150 	}
151 	STACKSTRNUL(p);
152 	setvar(*ap, stackblock(), 0);
153 	while (*++ap != NULL)
154 		setvar(*ap, nullstr, 0);
155 	return status;
156 }
157 
158 
159 
160 umaskcmd(argc, argv)  char **argv; {
161 	int mask;
162 	char *p;
163 	int i;
164 
165 	if ((p = argv[1]) == NULL) {
166 		INTOFF;
167 		mask = umask(0);
168 		umask(mask);
169 		INTON;
170 		out1fmt("%.4o\n", mask);	/* %#o might be better */
171 	} else {
172 		mask = 0;
173 		do {
174 			if ((unsigned)(i = *p - '0') >= 8)
175 				error("Illegal number: %s", argv[1]);
176 			mask = (mask << 3) + i;
177 		} while (*++p != '\0');
178 		umask(mask);
179 	}
180 	return 0;
181 }
182 
183 
184 #if BSD
185 struct restab {
186 	int resource;
187 	int scale;
188 	char *descript;
189 };
190 
191 /* multi-purpose */
192 #define RLIMIT_UNSPEC (-2)
193 
194 /* resource */
195 #define RLIMIT_ALL (-1)
196 
197 /* mode */
198 #define RLIMIT_SHOW 0
199 #define RLIMIT_SET 1
200 
201 /* what */
202 #define RLIMIT_SOFT 1
203 #define RLIMIT_HARD 2
204 
205 static struct restab restab[] = {
206 	{RLIMIT_CORE,     512,  "coredump(512-blocks)    "},
207 	{RLIMIT_CPU,      1,    "time(seconds)           "},
208 	{RLIMIT_DATA,     1024, "datasize(kilobytes)     "},
209 	{RLIMIT_FSIZE,    512,  "filesize(512-blocks)    "},
210 	{RLIMIT_MEMLOCK,  1024, "lockedmem(kilobytes)    "},
211 	{RLIMIT_NOFILE,   1,    "nofiles(descriptors)    "},
212 	{RLIMIT_NPROC,    1,    "userprocs(max)          "},
213 	{RLIMIT_RSS,      1024, "memoryuse(kilobytes)    "},
214 	{RLIMIT_STACK,    1024, "stacksize(kilobytes)    "}
215 };
216 
217 /* get entry into above table */
218 static struct restab *
219 find_resource(resource) {
220 	int i;
221 	struct restab *rp;
222 
223 	for(i = 0, rp = restab;
224 	    i < sizeof restab / sizeof(struct restab);
225 	    i++, rp++)
226 		if(rp->resource == resource)
227 			return rp;
228 	error("internal error: resource not in table");
229 	return 0;
230 }
231 
232 static void
233 print_resource(rp, what, with_descript) struct restab *rp; {
234 	struct rlimit rlim;
235 	quad_t val;
236 
237 	(void)getrlimit(rp->resource, &rlim);
238 	val = (what == RLIMIT_SOFT)?
239 		rlim.rlim_cur: rlim.rlim_max;
240 	if(with_descript)
241 		out1str(rp->descript);
242 	if(val == RLIM_INFINITY)
243 		out1str("unlimited\n");
244 	else {
245 		val /= (quad_t)rp->scale;
246 		if(val > (quad_t)ULONG_MAX)
247 			out1fmt("> %lu\n", (unsigned long)ULONG_MAX);
248 		else
249 			out1fmt("%lu\n", (unsigned long)val);
250 	}
251 }
252 
253 ulimitcmd(argc, argv)  char **argv; {
254 	struct rlimit rlim;
255 	char *p;
256 	int i;
257 	int resource = RLIMIT_UNSPEC;
258 	quad_t val;
259 	int what = RLIMIT_UNSPEC;
260 	int mode = RLIMIT_UNSPEC;
261 	int errs = 0, arg = 1;
262 	struct restab *rp;
263 	extern int optreset;	/* XXX should be declared in <stdlib.h> */
264 
265 	opterr = 0;		/* use own error processing */
266 	optreset = 1;
267 	optind = 1;
268 	while ((i = getopt(argc, argv, "HSacdfnstmlu")) != EOF) {
269 		arg++;
270 		switch(i) {
271 		case 'H':
272 			if(what == RLIMIT_UNSPEC) what = 0;
273 			what |= RLIMIT_HARD;
274 			break;
275 		case 'S':
276 			if(what == RLIMIT_UNSPEC) what = 0;
277 			what |= RLIMIT_SOFT;
278 			break;
279 		case 'a':
280 			if(resource != RLIMIT_UNSPEC) errs++;
281 			resource = RLIMIT_ALL;
282 			mode = RLIMIT_SHOW;
283 			break;
284 		case 'c':
285 			if(resource != RLIMIT_UNSPEC) errs++;
286 			resource = RLIMIT_CORE;
287 			break;
288 		case 'd':
289 			if(resource != RLIMIT_UNSPEC) errs++;
290 			resource = RLIMIT_DATA;
291 			break;
292 		case 'f':
293 			if(resource != RLIMIT_UNSPEC) errs++;
294 			resource = RLIMIT_FSIZE;
295 			break;
296 		case 'n':
297 			if(resource != RLIMIT_UNSPEC) errs++;
298 			resource = RLIMIT_NOFILE;
299 			break;
300 		case 's':
301 			if(resource != RLIMIT_UNSPEC) errs++;
302 			resource = RLIMIT_STACK;
303 			break;
304 		case 't':
305 			if(resource != RLIMIT_UNSPEC) errs++;
306 			resource = RLIMIT_CPU;
307 			break;
308 		case 'm':
309 			if(resource != RLIMIT_UNSPEC) errs++;
310 			resource = RLIMIT_RSS;
311 			break;
312 		case 'l':
313 			if(resource != RLIMIT_UNSPEC) errs++;
314 			resource = RLIMIT_MEMLOCK;
315 			break;
316 		case 'u':
317 			if(resource != RLIMIT_UNSPEC) errs++;
318 			resource = RLIMIT_NPROC;
319 			break;
320 		case '?':
321 			error("illegal option -%c", optopt);
322 		}
323 	}
324 
325 	argc -= optind;
326 	argv += optind;
327 	if(argc > 1)
328 		error("too many arguments");
329 	if(argc == 0)
330 		mode = RLIMIT_SHOW;
331 	else if (resource == RLIMIT_ALL)
332 		errs++;
333 	else
334 		mode = RLIMIT_SET;
335 	if(mode == RLIMIT_UNSPEC)
336 		mode = RLIMIT_SHOW;
337 	if(resource == RLIMIT_UNSPEC)
338 		resource = RLIMIT_FSIZE;
339 	if(what == RLIMIT_UNSPEC)
340 		what = (mode == RLIMIT_SHOW)?
341 			RLIMIT_SOFT: (RLIMIT_SOFT|RLIMIT_HARD);
342 	if(mode == RLIMIT_SHOW && what == (RLIMIT_SOFT|RLIMIT_HARD))
343 		errs++;
344 	if(errs)
345 		error("Wrong option combination");
346 
347 	if(resource == RLIMIT_ALL)
348 		for(i = 0; i < sizeof restab / sizeof(struct restab); i++)
349 			print_resource(restab + i, what, 1);
350 	else if(mode == RLIMIT_SHOW)
351 		print_resource(find_resource(resource), what, 0);
352 	else {
353 		rp = find_resource(resource);
354 		if(strcmp(argv[0], "unlimited") == 0)
355 			val = RLIM_INFINITY;
356 		else {
357 			val = 0;
358 			p = argv[0];
359 			do {
360 				if((i = *p - '0') < 0 || i > 9)
361 					error("Illegal number: %s", argv[0]);
362 				val = (10 * val) + (quad_t)i;
363 			} while (*++p != '\0');
364 			val *= (quad_t)rp->scale;
365 		}
366 		(void)getrlimit(resource, &rlim);
367 		if(what & RLIMIT_HARD)
368 			rlim.rlim_max = val;
369 		if(what & RLIMIT_SOFT)
370 			rlim.rlim_cur = val;
371 		if(setrlimit(resource, &rlim) == -1) {
372 			outfmt(&errout, "ulimit: bad limit: %s\n",
373 			       strerror(errno));
374 			return 1;
375 		}
376 	}
377 	return 0;
378 }
379 #else /* !BSD */
380 #error ulimit() not implemented
381 #endif /* BSD */
382