miscbltin.c revision 11601
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
41static 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
70extern 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
80readcmd(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
160umaskcmd(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
185struct 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
205static 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 */
218static struct restab *
219find_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
232static void
233print_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
253ulimitcmd(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