miscbltin.c revision 52072
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
351556Srgrimes */
361556Srgrimes
371556Srgrimes#ifndef lint
3836150Scharnier#if 0
3936150Scharnierstatic char sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
4036150Scharnier#endif
4136150Scharnierstatic const char rcsid[] =
4250471Speter  "$FreeBSD: head/bin/sh/miscbltin.c 52072 1999-10-09 20:56:06Z green $";
431556Srgrimes#endif /* not lint */
441556Srgrimes
451556Srgrimes/*
4646684Skris * Miscellaneous builtins.
471556Srgrimes */
481556Srgrimes
4917987Speter#include <sys/types.h>
5017987Speter#include <sys/stat.h>
5117987Speter#include <sys/time.h>
5217987Speter#include <sys/resource.h>
5317987Speter#include <unistd.h>
5417987Speter#include <ctype.h>
5518016Speter#include <errno.h>
5618018Speter#include <stdio.h>
5738536Scracauer#include <stdlib.h>
5829983Smsmith#include <termios.h>
5917987Speter
601556Srgrimes#include "shell.h"
611556Srgrimes#include "options.h"
621556Srgrimes#include "var.h"
631556Srgrimes#include "output.h"
641556Srgrimes#include "memalloc.h"
651556Srgrimes#include "error.h"
661556Srgrimes#include "mystring.h"
671556Srgrimes
681556Srgrimes#undef eflag
691556Srgrimes
701556Srgrimesextern char **argptr;		/* argument list for builtin command */
711556Srgrimes
721556Srgrimes
731556Srgrimes/*
7450394Stg * The read builtin.  The -r option causes backslashes to be treated like
7550394Stg * ordinary characters.
761556Srgrimes *
771556Srgrimes * This uses unbuffered input, which may be avoidable in some cases.
781556Srgrimes */
791556Srgrimes
8017987Speterint
8117987Speterreadcmd(argc, argv)
8225905Ssteve	int argc __unused;
8325905Ssteve	char **argv __unused;
8417987Speter{
851556Srgrimes	char **ap;
861556Srgrimes	int backslash;
871556Srgrimes	char c;
8850394Stg	int rflag;
891556Srgrimes	char *prompt;
901556Srgrimes	char *ifs;
911556Srgrimes	char *p;
921556Srgrimes	int startword;
931556Srgrimes	int status;
941556Srgrimes	int i;
9529983Smsmith	struct timeval tv;
9629983Smsmith	char *tvptr;
9729983Smsmith	fd_set ifds;
9829983Smsmith	struct termios told, tnew;
9929983Smsmith	int tsaved;
1001556Srgrimes
10150394Stg	rflag = 0;
1021556Srgrimes	prompt = NULL;
10329983Smsmith	tv.tv_sec = -1;
10429983Smsmith	tv.tv_usec = 0;
10550394Stg	while ((i = nextopt("erp:t:")) != '\0') {
10629983Smsmith		switch(i) {
10729983Smsmith		case 'p':
1081556Srgrimes			prompt = optarg;
10929983Smsmith			break;
11029983Smsmith		case 'e':
11129983Smsmith			break;
11250394Stg		case 'r':
11350394Stg			rflag = 1;
11450394Stg			break;
11529983Smsmith		case 't':
11629983Smsmith			tv.tv_sec = strtol(optarg, &tvptr, 0);
11729983Smsmith			if (tvptr == optarg)
11829983Smsmith				error("timeout value");
11929983Smsmith			switch(*tvptr) {
12029983Smsmith			case 0:
12129983Smsmith			case 's':
12229983Smsmith				break;
12329983Smsmith			case 'h':
12429983Smsmith				tv.tv_sec *= 60;
12529983Smsmith				/* FALLTHROUGH */
12629983Smsmith			case 'm':
12729983Smsmith				tv.tv_sec *= 60;
12829983Smsmith				break;
12929983Smsmith			default:
13029983Smsmith				error("timeout unit");
13129983Smsmith			}
13229983Smsmith			break;
13329983Smsmith		}
1341556Srgrimes	}
1351556Srgrimes	if (prompt && isatty(0)) {
1361556Srgrimes		out2str(prompt);
1371556Srgrimes		flushall();
1381556Srgrimes	}
1391556Srgrimes	if (*(ap = argptr) == NULL)
1401556Srgrimes		error("arg count");
1411556Srgrimes	if ((ifs = bltinlookup("IFS", 1)) == NULL)
1421556Srgrimes		ifs = nullstr;
14329983Smsmith
14429983Smsmith	if (tv.tv_sec >= 0) {
14529983Smsmith		/*
14629983Smsmith		 * See if we can disable input processing; this will
14729983Smsmith		 * not give the desired result if we are in a pipeline
14829983Smsmith		 * and someone upstream is still in line-by-line mode.
14929983Smsmith		 */
15029983Smsmith		tsaved = 0;
15129983Smsmith		if (tcgetattr(0, &told) == 0) {
15229983Smsmith			memcpy(&tnew, &told, sizeof(told));
15329983Smsmith			cfmakeraw(&tnew);
15429983Smsmith			tcsetattr(0, TCSANOW, &tnew);
15529983Smsmith			tsaved = 1;
15629983Smsmith		}
15729983Smsmith		/*
15829983Smsmith		 * Wait for something to become available.
15929983Smsmith		 */
16029983Smsmith		FD_ZERO(&ifds);
16129983Smsmith		FD_SET(0, &ifds);
16229983Smsmith		status = select(1, &ifds, NULL, NULL, &tv);
16329983Smsmith		if (tsaved)
16429983Smsmith			tcsetattr(0, TCSANOW, &told);
16529983Smsmith		/*
16629983Smsmith		 * If there's nothing ready, return an error.
16729983Smsmith		 */
16829983Smsmith		if (status <= 0)
16929983Smsmith			return(1);
17029983Smsmith	}
17129983Smsmith
1721556Srgrimes	status = 0;
1731556Srgrimes	startword = 1;
1741556Srgrimes	backslash = 0;
1751556Srgrimes	STARTSTACKSTR(p);
1761556Srgrimes	for (;;) {
1771556Srgrimes		if (read(0, &c, 1) != 1) {
1781556Srgrimes			status = 1;
1791556Srgrimes			break;
1801556Srgrimes		}
1811556Srgrimes		if (c == '\0')
1821556Srgrimes			continue;
1831556Srgrimes		if (backslash) {
1841556Srgrimes			backslash = 0;
1851556Srgrimes			if (c != '\n')
1861556Srgrimes				STPUTC(c, p);
1871556Srgrimes			continue;
1881556Srgrimes		}
18950394Stg		if (!rflag && c == '\\') {
1901556Srgrimes			backslash++;
1911556Srgrimes			continue;
1921556Srgrimes		}
1931556Srgrimes		if (c == '\n')
1941556Srgrimes			break;
1951556Srgrimes		if (startword && *ifs == ' ' && strchr(ifs, c)) {
1961556Srgrimes			continue;
1971556Srgrimes		}
1981556Srgrimes		startword = 0;
1991556Srgrimes		if (backslash && c == '\\') {
2001556Srgrimes			if (read(0, &c, 1) != 1) {
2011556Srgrimes				status = 1;
2021556Srgrimes				break;
2031556Srgrimes			}
2041556Srgrimes			STPUTC(c, p);
2051556Srgrimes		} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
2061556Srgrimes			STACKSTRNUL(p);
2071556Srgrimes			setvar(*ap, stackblock(), 0);
2081556Srgrimes			ap++;
2091556Srgrimes			startword = 1;
2101556Srgrimes			STARTSTACKSTR(p);
2111556Srgrimes		} else {
2121556Srgrimes			STPUTC(c, p);
2131556Srgrimes		}
2141556Srgrimes	}
2151556Srgrimes	STACKSTRNUL(p);
2161556Srgrimes	setvar(*ap, stackblock(), 0);
2171556Srgrimes	while (*++ap != NULL)
2181556Srgrimes		setvar(*ap, nullstr, 0);
2191556Srgrimes	return status;
2201556Srgrimes}
2211556Srgrimes
2221556Srgrimes
2231556Srgrimes
22417987Speterint
22517987Speterumaskcmd(argc, argv)
22625905Ssteve	int argc __unused;
22720425Ssteve	char **argv;
22817987Speter{
22917987Speter	char *ap;
2301556Srgrimes	int mask;
2311556Srgrimes	int i;
23217987Speter	int symbolic_mode = 0;
2331556Srgrimes
23417987Speter	while ((i = nextopt("S")) != '\0') {
23517987Speter		symbolic_mode = 1;
2361556Srgrimes	}
23711571Sjoerg
23817987Speter	INTOFF;
23917987Speter	mask = umask(0);
24017987Speter	umask(mask);
24117987Speter	INTON;
24211571Sjoerg
24317987Speter	if ((ap = *argptr) == NULL) {
24417987Speter		if (symbolic_mode) {
24517987Speter			char u[4], g[4], o[4];
24611571Sjoerg
24717987Speter			i = 0;
24817987Speter			if ((mask & S_IRUSR) == 0)
24917987Speter				u[i++] = 'r';
25017987Speter			if ((mask & S_IWUSR) == 0)
25117987Speter				u[i++] = 'w';
25217987Speter			if ((mask & S_IXUSR) == 0)
25317987Speter				u[i++] = 'x';
25417987Speter			u[i] = '\0';
25511571Sjoerg
25617987Speter			i = 0;
25717987Speter			if ((mask & S_IRGRP) == 0)
25817987Speter				g[i++] = 'r';
25917987Speter			if ((mask & S_IWGRP) == 0)
26017987Speter				g[i++] = 'w';
26117987Speter			if ((mask & S_IXGRP) == 0)
26217987Speter				g[i++] = 'x';
26317987Speter			g[i] = '\0';
26411571Sjoerg
26517987Speter			i = 0;
26617987Speter			if ((mask & S_IROTH) == 0)
26717987Speter				o[i++] = 'r';
26817987Speter			if ((mask & S_IWOTH) == 0)
26917987Speter				o[i++] = 'w';
27017987Speter			if ((mask & S_IXOTH) == 0)
27117987Speter				o[i++] = 'x';
27217987Speter			o[i] = '\0';
27311571Sjoerg
27417987Speter			out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
27517987Speter		} else {
27617987Speter			out1fmt("%.4o\n", mask);
27717987Speter		}
27817987Speter	} else {
27917987Speter		if (isdigit(*ap)) {
28017987Speter			mask = 0;
28117987Speter			do {
28217987Speter				if (*ap >= '8' || *ap < '0')
28317987Speter					error("Illegal number: %s", argv[1]);
28417987Speter				mask = (mask << 3) + (*ap - '0');
28517987Speter			} while (*++ap != '\0');
28617987Speter			umask(mask);
28717987Speter		} else {
28820425Ssteve			void *set;
28917987Speter			if ((set = setmode (ap)) == 0)
29041844Simp				error("Illegal number: %s", ap);
29111571Sjoerg
29217987Speter			mask = getmode (set, ~mask & 0777);
29317987Speter			umask(~mask & 0777);
29441844Simp			free(set);
29517987Speter		}
29617987Speter	}
29711571Sjoerg	return 0;
29811571Sjoerg}
29911571Sjoerg
30017987Speter/*
30117987Speter * ulimit builtin
30217987Speter *
30317987Speter * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
30417987Speter * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
30517987Speter * ash by J.T. Conklin.
30617987Speter *
30717987Speter * Public domain.
30817987Speter */
30911571Sjoerg
31017987Speterstruct limits {
31117987Speter	const char *name;
31218016Speter	const char *units;
31317987Speter	int	cmd;
31417987Speter	int	factor;	/* multiply by to get rlim_{cur,max} values */
31517987Speter	char	option;
31617987Speter};
31711571Sjoerg
31817987Speterstatic const struct limits limits[] = {
31917987Speter#ifdef RLIMIT_CPU
32018016Speter	{ "cpu time",		"seconds",	RLIMIT_CPU,	   1, 't' },
32117987Speter#endif
32217987Speter#ifdef RLIMIT_FSIZE
32318016Speter	{ "file size",		"512-blocks",	RLIMIT_FSIZE,	 512, 'f' },
32417987Speter#endif
32517987Speter#ifdef RLIMIT_DATA
32618016Speter	{ "data seg size",	"kbytes",	RLIMIT_DATA,	1024, 'd' },
32717987Speter#endif
32817987Speter#ifdef RLIMIT_STACK
32918016Speter	{ "stack size",		"kbytes",	RLIMIT_STACK,	1024, 's' },
33017987Speter#endif
33117987Speter#ifdef  RLIMIT_CORE
33218016Speter	{ "core file size",	"512-blocks",	RLIMIT_CORE,	 512, 'c' },
33317987Speter#endif
33417987Speter#ifdef RLIMIT_RSS
33518016Speter	{ "max memory size",	"kbytes",	RLIMIT_RSS,	1024, 'm' },
33617987Speter#endif
33717987Speter#ifdef RLIMIT_MEMLOCK
33818016Speter	{ "locked memory",	"kbytes",	RLIMIT_MEMLOCK, 1024, 'l' },
33917987Speter#endif
34017987Speter#ifdef RLIMIT_NPROC
34118016Speter	{ "max user processes",	(char *)0,	RLIMIT_NPROC,      1, 'u' },
34217987Speter#endif
34317987Speter#ifdef RLIMIT_NOFILE
34418016Speter	{ "open files",		(char *)0,	RLIMIT_NOFILE,     1, 'n' },
34517987Speter#endif
34617987Speter#ifdef RLIMIT_VMEM
34718016Speter	{ "virtual mem size",	"kbytes",	RLIMIT_VMEM,	1024, 'v' },
34817987Speter#endif
34917987Speter#ifdef RLIMIT_SWAP
35018016Speter	{ "swap limit",		"kbytes",	RLIMIT_SWAP,	1024, 'w' },
35117987Speter#endif
35252072Sgreen#ifdef RLIMIT_SBSIZE
35352072Sgreen	{ "sbsize",		"bytes",	RLIMIT_SBSIZE,	   1, 'b' },
35452072Sgreen#endif
35518016Speter	{ (char *) 0,		(char *)0,	0,		   0, '\0' }
35617987Speter};
35717987Speter
35817987Speterint
35917987Speterulimitcmd(argc, argv)
36025905Ssteve	int argc __unused;
36125905Ssteve	char **argv __unused;
36217987Speter{
36325222Ssteve	int	c;
36418018Speter	quad_t val = 0;
36517987Speter	enum { SOFT = 0x1, HARD = 0x2 }
36617987Speter			how = SOFT | HARD;
36717987Speter	const struct limits	*l;
36817987Speter	int		set, all = 0;
36917987Speter	int		optc, what;
37017987Speter	struct rlimit	limit;
37111571Sjoerg
37217987Speter	what = 'f';
37352072Sgreen	while ((optc = nextopt("HSatfdsmcnulb")) != '\0')
37417987Speter		switch (optc) {
37511571Sjoerg		case 'H':
37617987Speter			how = HARD;
37711571Sjoerg			break;
37811571Sjoerg		case 'S':
37917987Speter			how = SOFT;
38011571Sjoerg			break;
38111571Sjoerg		case 'a':
38217987Speter			all = 1;
38311571Sjoerg			break;
38417987Speter		default:
38517987Speter			what = optc;
38611571Sjoerg		}
38711571Sjoerg
38817987Speter	for (l = limits; l->name && l->option != what; l++)
38917987Speter		;
39017987Speter	if (!l->name)
39120425Ssteve		error("ulimit: internal error (%c)", what);
39217987Speter
39317987Speter	set = *argptr ? 1 : 0;
39417987Speter	if (set) {
39517987Speter		char *p = *argptr;
39617987Speter
39717987Speter		if (all || argptr[1])
39820425Ssteve			error("ulimit: too many arguments");
39917987Speter		if (strcmp(p, "unlimited") == 0)
40011571Sjoerg			val = RLIM_INFINITY;
40111571Sjoerg		else {
40217987Speter			val = (quad_t) 0;
40317987Speter
40417987Speter			while ((c = *p++) >= '0' && c <= '9')
40517987Speter			{
40617987Speter				val = (val * 10) + (long)(c - '0');
40717987Speter				if (val < (quad_t) 0)
40817987Speter					break;
40917987Speter			}
41017987Speter			if (c)
41120425Ssteve				error("ulimit: bad number");
41217987Speter			val *= l->factor;
41311571Sjoerg		}
41417987Speter	}
41517987Speter	if (all) {
41618016Speter		for (l = limits; l->name; l++) {
41718016Speter			char optbuf[40];
41818016Speter			if (getrlimit(l->cmd, &limit) < 0)
41920425Ssteve				error("ulimit: can't get limit: %s", strerror(errno));
42017987Speter			if (how & SOFT)
42117987Speter				val = limit.rlim_cur;
42217987Speter			else if (how & HARD)
42317987Speter				val = limit.rlim_max;
42417987Speter
42518016Speter			if (l->units)
42618016Speter				snprintf(optbuf, sizeof(optbuf),
42718019Speter					"(%s, -%c) ", l->units, l->option);
42818016Speter			else
42918016Speter				snprintf(optbuf, sizeof(optbuf),
43018019Speter					"(-%c) ", l->option);
43118019Speter			out1fmt("%-18s %18s ", l->name, optbuf);
43217987Speter			if (val == RLIM_INFINITY)
43317987Speter				out1fmt("unlimited\n");
43417987Speter			else
43517987Speter			{
43617987Speter				val /= l->factor;
43718018Speter				out1fmt("%qd\n", (quad_t) val);
43817987Speter			}
43911571Sjoerg		}
44017987Speter		return 0;
44111571Sjoerg	}
44217987Speter
44318016Speter	if (getrlimit(l->cmd, &limit) < 0)
44420425Ssteve		error("ulimit: can't get limit: %s", strerror(errno));
44517987Speter	if (set) {
44617987Speter		if (how & SOFT)
44717987Speter			limit.rlim_cur = val;
44817987Speter		if (how & HARD)
44917987Speter			limit.rlim_max = val;
45017987Speter		if (setrlimit(l->cmd, &limit) < 0)
45120425Ssteve			error("ulimit: bad limit: %s", strerror(errno));
45217987Speter	} else {
45317987Speter		if (how & SOFT)
45417987Speter			val = limit.rlim_cur;
45517987Speter		else if (how & HARD)
45617987Speter			val = limit.rlim_max;
45717987Speter
45817987Speter		if (val == RLIM_INFINITY)
45917987Speter			out1fmt("unlimited\n");
46017987Speter		else
46117987Speter		{
46217987Speter			val /= l->factor;
46318018Speter			out1fmt("%qd\n", (quad_t) val);
46417987Speter		}
46517987Speter	}
46611571Sjoerg	return 0;
46711571Sjoerg}
468