miscbltin.c revision 18018
1160814Ssimon/*-
2296341Sdelphij * Copyright (c) 1991, 1993
3296341Sdelphij *	The Regents of the University of California.  All rights reserved.
4296341Sdelphij *
5160814Ssimon * This code is derived from software contributed to Berkeley by
6160814Ssimon * Kenneth Almquist.
7160814Ssimon *
8160814Ssimon * Redistribution and use in source and binary forms, with or without
9160814Ssimon * modification, are permitted provided that the following conditions
10160814Ssimon * are met:
11160814Ssimon * 1. Redistributions of source code must retain the above copyright
12160814Ssimon *    notice, this list of conditions and the following disclaimer.
13160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
14296341Sdelphij *    notice, this list of conditions and the following disclaimer in the
15160814Ssimon *    documentation and/or other materials provided with the distribution.
16160814Ssimon * 3. All advertising materials mentioning features or use of this software
17160814Ssimon *    must display the following acknowledgement:
18160814Ssimon *	This product includes software developed by the University of
19160814Ssimon *	California, Berkeley and its contributors.
20160814Ssimon * 4. Neither the name of the University nor the names of its contributors
21160814Ssimon *    may be used to endorse or promote products derived from this software
22160814Ssimon *    without specific prior written permission.
23160814Ssimon *
24160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25160814Ssimon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27160814Ssimon * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28160814Ssimon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29160814Ssimon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30160814Ssimon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32160814Ssimon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33160814Ssimon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34160814Ssimon * SUCH DAMAGE.
35160814Ssimon *
36160814Ssimon *	$Id: miscbltin.c,v 1.6 1996/09/03 13:35:10 peter Exp $
37160814Ssimon */
38160814Ssimon
39160814Ssimon#ifndef lint
40160814Ssimonstatic char sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
41160814Ssimon#endif /* not lint */
42160814Ssimon
43160814Ssimon/*
44160814Ssimon * Miscelaneous builtins.
45160814Ssimon */
46160814Ssimon
47160814Ssimon#include <sys/types.h>
48160814Ssimon#include <sys/stat.h>
49160814Ssimon#include <sys/time.h>
50160814Ssimon#include <sys/resource.h>
51160814Ssimon#include <unistd.h>
52160814Ssimon#include <ctype.h>
53160814Ssimon#include <errno.h>
54160814Ssimon#include <stdio.h>
55160814Ssimon
56160814Ssimon#include "shell.h"
57160814Ssimon#include "options.h"
58160814Ssimon#include "var.h"
59160814Ssimon#include "output.h"
60160814Ssimon#include "memalloc.h"
61160814Ssimon#include "error.h"
62160814Ssimon#include "mystring.h"
63160814Ssimon
64160814Ssimon#undef eflag
65160814Ssimon
66160814Ssimonextern char **argptr;		/* argument list for builtin command */
67296341Sdelphij
68160814Ssimon
69160814Ssimon/*
70296341Sdelphij * The read builtin.  The -e option causes backslashes to escape the
71160814Ssimon * following character.
72160814Ssimon *
73296341Sdelphij * This uses unbuffered input, which may be avoidable in some cases.
74160814Ssimon */
75160814Ssimon
76160814Ssimonint
77160814Ssimonreadcmd(argc, argv)
78296341Sdelphij	int argc;
79160814Ssimon	char **argv;
80296341Sdelphij{
81296341Sdelphij	char **ap;
82296341Sdelphij	int backslash;
83296341Sdelphij	char c;
84296341Sdelphij	int eflag;
85160814Ssimon	char *prompt;
86296341Sdelphij	char *ifs;
87296341Sdelphij	char *p;
88160814Ssimon	int startword;
89160814Ssimon	int status;
90160814Ssimon	int i;
91160814Ssimon
92296341Sdelphij	eflag = 0;
93160814Ssimon	prompt = NULL;
94160814Ssimon	while ((i = nextopt("ep:")) != '\0') {
95160814Ssimon		if (i == 'p')
96296341Sdelphij			prompt = optarg;
97160814Ssimon		else
98296341Sdelphij			eflag = 1;
99160814Ssimon	}
100296341Sdelphij	if (prompt && isatty(0)) {
101296341Sdelphij		out2str(prompt);
102160814Ssimon		flushall();
103160814Ssimon	}
104296341Sdelphij	if (*(ap = argptr) == NULL)
105296341Sdelphij		error("arg count");
106296341Sdelphij	if ((ifs = bltinlookup("IFS", 1)) == NULL)
107160814Ssimon		ifs = nullstr;
108296341Sdelphij	status = 0;
109160814Ssimon	startword = 1;
110160814Ssimon	backslash = 0;
111296341Sdelphij	STARTSTACKSTR(p);
112296341Sdelphij	for (;;) {
113160814Ssimon		if (read(0, &c, 1) != 1) {
114296341Sdelphij			status = 1;
115296341Sdelphij			break;
116296341Sdelphij		}
117160814Ssimon		if (c == '\0')
118296341Sdelphij			continue;
119160814Ssimon		if (backslash) {
120160814Ssimon			backslash = 0;
121160814Ssimon			if (c != '\n')
122296341Sdelphij				STPUTC(c, p);
123296341Sdelphij			continue;
124296341Sdelphij		}
125296341Sdelphij		if (eflag && c == '\\') {
126160814Ssimon			backslash++;
127160814Ssimon			continue;
128296341Sdelphij		}
129160814Ssimon		if (c == '\n')
130296341Sdelphij			break;
131296341Sdelphij		if (startword && *ifs == ' ' && strchr(ifs, c)) {
132296341Sdelphij			continue;
133296341Sdelphij		}
134296341Sdelphij		startword = 0;
135296341Sdelphij		if (backslash && c == '\\') {
136160814Ssimon			if (read(0, &c, 1) != 1) {
137296341Sdelphij				status = 1;
138160814Ssimon				break;
139296341Sdelphij			}
140296341Sdelphij			STPUTC(c, p);
141296341Sdelphij		} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
142296341Sdelphij			STACKSTRNUL(p);
143296341Sdelphij			setvar(*ap, stackblock(), 0);
144296341Sdelphij			ap++;
145296341Sdelphij			startword = 1;
146296341Sdelphij			STARTSTACKSTR(p);
147296341Sdelphij		} else {
148296341Sdelphij			STPUTC(c, p);
149296341Sdelphij		}
150296341Sdelphij	}
151296341Sdelphij	STACKSTRNUL(p);
152296341Sdelphij	setvar(*ap, stackblock(), 0);
153296341Sdelphij	while (*++ap != NULL)
154296341Sdelphij		setvar(*ap, nullstr, 0);
155296341Sdelphij	return status;
156160814Ssimon}
157296341Sdelphij
158160814Ssimon
159296341Sdelphij
160296341Sdelphijint
161296341Sdelphijumaskcmd(argc, argv)
162296341Sdelphij	int argc;
163296341Sdelphij	char **argv;
164296341Sdelphij{
165296341Sdelphij	char *ap;
166296341Sdelphij	int mask;
167296341Sdelphij	int i;
168296341Sdelphij	int symbolic_mode = 0;
169296341Sdelphij
170296341Sdelphij	while ((i = nextopt("S")) != '\0') {
171296341Sdelphij		symbolic_mode = 1;
172296341Sdelphij	}
173296341Sdelphij
174160814Ssimon	INTOFF;
175296341Sdelphij	mask = umask(0);
176160814Ssimon	umask(mask);
177296341Sdelphij	INTON;
178296341Sdelphij
179296341Sdelphij	if ((ap = *argptr) == NULL) {
180296341Sdelphij		if (symbolic_mode) {
181296341Sdelphij			char u[4], g[4], o[4];
182296341Sdelphij
183296341Sdelphij			i = 0;
184296341Sdelphij			if ((mask & S_IRUSR) == 0)
185296341Sdelphij				u[i++] = 'r';
186296341Sdelphij			if ((mask & S_IWUSR) == 0)
187296341Sdelphij				u[i++] = 'w';
188296341Sdelphij			if ((mask & S_IXUSR) == 0)
189160814Ssimon				u[i++] = 'x';
190160814Ssimon			u[i] = '\0';
191160814Ssimon
192160814Ssimon			i = 0;
193160814Ssimon			if ((mask & S_IRGRP) == 0)
194296341Sdelphij				g[i++] = 'r';
195296341Sdelphij			if ((mask & S_IWGRP) == 0)
196296341Sdelphij				g[i++] = 'w';
197296341Sdelphij			if ((mask & S_IXGRP) == 0)
198160814Ssimon				g[i++] = 'x';
199296341Sdelphij			g[i] = '\0';
200296341Sdelphij
201296341Sdelphij			i = 0;
202296341Sdelphij			if ((mask & S_IROTH) == 0)
203296341Sdelphij				o[i++] = 'r';
204296341Sdelphij			if ((mask & S_IWOTH) == 0)
205296341Sdelphij				o[i++] = 'w';
206296341Sdelphij			if ((mask & S_IXOTH) == 0)
207296341Sdelphij				o[i++] = 'x';
208296341Sdelphij			o[i] = '\0';
209296341Sdelphij
210296341Sdelphij			out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
211296341Sdelphij		} else {
212296341Sdelphij			out1fmt("%.4o\n", mask);
213296341Sdelphij		}
214296341Sdelphij	} else {
215296341Sdelphij		if (isdigit(*ap)) {
216296341Sdelphij			mask = 0;
217296341Sdelphij			do {
218296341Sdelphij				if (*ap >= '8' || *ap < '0')
219296341Sdelphij					error("Illegal number: %s", argv[1]);
220296341Sdelphij				mask = (mask << 3) + (*ap - '0');
221296341Sdelphij			} while (*++ap != '\0');
222296341Sdelphij			umask(mask);
223296341Sdelphij		} else {
224296341Sdelphij			void *set;
225296341Sdelphij			if ((set = setmode (ap)) == 0)
226160814Ssimon					error("Illegal number: %s", ap);
227296341Sdelphij
228296341Sdelphij			mask = getmode (set, ~mask & 0777);
229296341Sdelphij			umask(~mask & 0777);
230296341Sdelphij		}
231296341Sdelphij	}
232296341Sdelphij	return 0;
233296341Sdelphij}
234296341Sdelphij
235296341Sdelphij/*
236296341Sdelphij * ulimit builtin
237296341Sdelphij *
238296341Sdelphij * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
239296341Sdelphij * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
240296341Sdelphij * ash by J.T. Conklin.
241296341Sdelphij *
242160814Ssimon * Public domain.
243296341Sdelphij */
244296341Sdelphij
245296341Sdelphijstruct limits {
246296341Sdelphij	const char *name;
247296341Sdelphij	const char *units;
248296341Sdelphij	int	cmd;
249296341Sdelphij	int	factor;	/* multiply by to get rlim_{cur,max} values */
250296341Sdelphij	char	option;
251296341Sdelphij};
252160814Ssimon
253296341Sdelphijstatic const struct limits limits[] = {
254296341Sdelphij#ifdef RLIMIT_CPU
255296341Sdelphij	{ "cpu time",		"seconds",	RLIMIT_CPU,	   1, 't' },
256296341Sdelphij#endif
257296341Sdelphij#ifdef RLIMIT_FSIZE
258296341Sdelphij	{ "file size",		"512-blocks",	RLIMIT_FSIZE,	 512, 'f' },
259160814Ssimon#endif
260296341Sdelphij#ifdef RLIMIT_DATA
261296341Sdelphij	{ "data seg size",	"kbytes",	RLIMIT_DATA,	1024, 'd' },
262296341Sdelphij#endif
263296341Sdelphij#ifdef RLIMIT_STACK
264160814Ssimon	{ "stack size",		"kbytes",	RLIMIT_STACK,	1024, 's' },
265296341Sdelphij#endif
266160814Ssimon#ifdef  RLIMIT_CORE
267296341Sdelphij	{ "core file size",	"512-blocks",	RLIMIT_CORE,	 512, 'c' },
268296341Sdelphij#endif
269296341Sdelphij#ifdef RLIMIT_RSS
270296341Sdelphij	{ "max memory size",	"kbytes",	RLIMIT_RSS,	1024, 'm' },
271296341Sdelphij#endif
272296341Sdelphij#ifdef RLIMIT_MEMLOCK
273296341Sdelphij	{ "locked memory",	"kbytes",	RLIMIT_MEMLOCK, 1024, 'l' },
274296341Sdelphij#endif
275296341Sdelphij#ifdef RLIMIT_NPROC
276296341Sdelphij	{ "max user processes",	(char *)0,	RLIMIT_NPROC,      1, 'u' },
277160814Ssimon#endif
278160814Ssimon#ifdef RLIMIT_NOFILE
279296341Sdelphij	{ "open files",		(char *)0,	RLIMIT_NOFILE,     1, 'n' },
280296341Sdelphij#endif
281296341Sdelphij#ifdef RLIMIT_VMEM
282296341Sdelphij	{ "virtual mem size",	"kbytes",	RLIMIT_VMEM,	1024, 'v' },
283296341Sdelphij#endif
284296341Sdelphij#ifdef RLIMIT_SWAP
285296341Sdelphij	{ "swap limit",		"kbytes",	RLIMIT_SWAP,	1024, 'w' },
286296341Sdelphij#endif
287296341Sdelphij	{ (char *) 0,		(char *)0,	0,		   0, '\0' }
288296341Sdelphij};
289160814Ssimon
290296341Sdelphijint
291296341Sdelphijulimitcmd(argc, argv)
292296341Sdelphij	int argc;
293296341Sdelphij	char **argv;
294296341Sdelphij{
295296341Sdelphij	register int	c;
296160814Ssimon	quad_t val = 0;
297160814Ssimon	enum { SOFT = 0x1, HARD = 0x2 }
298296341Sdelphij			how = SOFT | HARD;
299296341Sdelphij	const struct limits	*l;
300296341Sdelphij	int		set, all = 0;
301296341Sdelphij	int		optc, what;
302160814Ssimon	struct rlimit	limit;
303160814Ssimon
304296341Sdelphij	what = 'f';
305296341Sdelphij	while ((optc = nextopt("HSatfdsmcnul")) != '\0')
306160814Ssimon		switch (optc) {
307296341Sdelphij		case 'H':
308296341Sdelphij			how = HARD;
309296341Sdelphij			break;
310296341Sdelphij		case 'S':
311296341Sdelphij			how = SOFT;
312296341Sdelphij			break;
313296341Sdelphij		case 'a':
314296341Sdelphij			all = 1;
315296341Sdelphij			break;
316296341Sdelphij		default:
317160814Ssimon			what = optc;
318160814Ssimon		}
319296341Sdelphij
320296341Sdelphij	for (l = limits; l->name && l->option != what; l++)
321296341Sdelphij		;
322296341Sdelphij	if (!l->name)
323296341Sdelphij		error("internal error (%c)", what);
324296341Sdelphij
325160814Ssimon	set = *argptr ? 1 : 0;
326296341Sdelphij	if (set) {
327296341Sdelphij		char *p = *argptr;
328296341Sdelphij
329296341Sdelphij		if (all || argptr[1])
330296341Sdelphij			error("too many arguments");
331296341Sdelphij		if (strcmp(p, "unlimited") == 0)
332160814Ssimon			val = RLIM_INFINITY;
333296341Sdelphij		else {
334296341Sdelphij			val = (quad_t) 0;
335296341Sdelphij
336296341Sdelphij			while ((c = *p++) >= '0' && c <= '9')
337296341Sdelphij			{
338160814Ssimon				val = (val * 10) + (long)(c - '0');
339160814Ssimon				if (val < (quad_t) 0)
340160814Ssimon					break;
341160814Ssimon			}
342160814Ssimon			if (c)
343160814Ssimon				error("bad number");
344296341Sdelphij			val *= l->factor;
345296341Sdelphij		}
346296341Sdelphij	}
347296341Sdelphij	if (all) {
348296341Sdelphij		for (l = limits; l->name; l++) {
349296341Sdelphij			char optbuf[40];
350296341Sdelphij			if (getrlimit(l->cmd, &limit) < 0)
351296341Sdelphij				error("can't get limit: %s", strerror(errno));
352296341Sdelphij			if (how & SOFT)
353296341Sdelphij				val = limit.rlim_cur;
354160814Ssimon			else if (how & HARD)
355160814Ssimon				val = limit.rlim_max;
356160814Ssimon
357296341Sdelphij			if (l->units)
358296341Sdelphij				snprintf(optbuf, sizeof(optbuf),
359296341Sdelphij					"%s (%s, -%c) ", l->name, l->units, l->option);
360296341Sdelphij			else
361296341Sdelphij				snprintf(optbuf, sizeof(optbuf),
362296341Sdelphij					"%s (-%c) ", l->name, l->option);
363296341Sdelphij			out1fmt("%32s ", optbuf);
364296341Sdelphij			if (val == RLIM_INFINITY)
365296341Sdelphij				out1fmt("unlimited\n");
366160814Ssimon			else
367296341Sdelphij			{
368296341Sdelphij				val /= l->factor;
369296341Sdelphij				out1fmt("%qd\n", (quad_t) val);
370296341Sdelphij			}
371296341Sdelphij		}
372296341Sdelphij		return 0;
373296341Sdelphij	}
374296341Sdelphij
375296341Sdelphij	if (getrlimit(l->cmd, &limit) < 0)
376296341Sdelphij		error("can't get limit: %s", strerror(errno));
377296341Sdelphij	if (set) {
378296341Sdelphij		if (how & SOFT)
379296341Sdelphij			limit.rlim_cur = val;
380296341Sdelphij		if (how & HARD)
381296341Sdelphij			limit.rlim_max = val;
382296341Sdelphij		if (setrlimit(l->cmd, &limit) < 0)
383296341Sdelphij			error("bad limit: %s", strerror(errno));
384296341Sdelphij	} else {
385296341Sdelphij		if (how & SOFT)
386296341Sdelphij			val = limit.rlim_cur;
387296341Sdelphij		else if (how & HARD)
388296341Sdelphij			val = limit.rlim_max;
389296341Sdelphij	}
390296341Sdelphij
391296341Sdelphij	if (!set) {
392296341Sdelphij		if (val == RLIM_INFINITY)
393296341Sdelphij			out1fmt("unlimited\n");
394296341Sdelphij		else
395296341Sdelphij		{
396296341Sdelphij			val /= l->factor;
397296341Sdelphij			out1fmt("%qd\n", (quad_t) val);
398296341Sdelphij		}
399296341Sdelphij	}
400296341Sdelphij	return 0;
401296341Sdelphij}
402296341Sdelphij