miscbltin.c revision 181905
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 * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#ifndef lint
3436150Scharnier#if 0
3536150Scharnierstatic char sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
3636150Scharnier#endif
371556Srgrimes#endif /* not lint */
3899110Sobrien#include <sys/cdefs.h>
3999110Sobrien__FBSDID("$FreeBSD: head/bin/sh/miscbltin.c 181905 2008-08-20 08:31:58Z ed $");
401556Srgrimes
411556Srgrimes/*
4246684Skris * Miscellaneous builtins.
431556Srgrimes */
441556Srgrimes
4517987Speter#include <sys/types.h>
4617987Speter#include <sys/stat.h>
4717987Speter#include <sys/time.h>
4817987Speter#include <sys/resource.h>
4917987Speter#include <unistd.h>
5017987Speter#include <ctype.h>
5118016Speter#include <errno.h>
52104282Smux#include <stdint.h>
5318018Speter#include <stdio.h>
5438536Scracauer#include <stdlib.h>
5529983Smsmith#include <termios.h>
5617987Speter
571556Srgrimes#include "shell.h"
581556Srgrimes#include "options.h"
591556Srgrimes#include "var.h"
601556Srgrimes#include "output.h"
611556Srgrimes#include "memalloc.h"
621556Srgrimes#include "error.h"
631556Srgrimes#include "mystring.h"
641556Srgrimes
651556Srgrimes#undef eflag
661556Srgrimes
67149018Sstefanfint readcmd(int, char **);
68149018Sstefanfint umaskcmd(int, char **);
69149018Sstefanfint ulimitcmd(int, char **);
70149018Sstefanf
711556Srgrimes/*
7250394Stg * The read builtin.  The -r option causes backslashes to be treated like
7350394Stg * ordinary characters.
741556Srgrimes *
751556Srgrimes * This uses unbuffered input, which may be avoidable in some cases.
761556Srgrimes */
771556Srgrimes
7817987Speterint
7990111Simpreadcmd(int argc __unused, char **argv __unused)
8017987Speter{
811556Srgrimes	char **ap;
821556Srgrimes	int backslash;
831556Srgrimes	char c;
8450394Stg	int rflag;
851556Srgrimes	char *prompt;
861556Srgrimes	char *ifs;
871556Srgrimes	char *p;
881556Srgrimes	int startword;
891556Srgrimes	int status;
901556Srgrimes	int i;
9129983Smsmith	struct timeval tv;
9229983Smsmith	char *tvptr;
9329983Smsmith	fd_set ifds;
9429983Smsmith	struct termios told, tnew;
9529983Smsmith	int tsaved;
961556Srgrimes
9750394Stg	rflag = 0;
981556Srgrimes	prompt = NULL;
9929983Smsmith	tv.tv_sec = -1;
10029983Smsmith	tv.tv_usec = 0;
10150394Stg	while ((i = nextopt("erp:t:")) != '\0') {
10229983Smsmith		switch(i) {
10329983Smsmith		case 'p':
10459436Scracauer			prompt = shoptarg;
10529983Smsmith			break;
10629983Smsmith		case 'e':
10729983Smsmith			break;
10850394Stg		case 'r':
10950394Stg			rflag = 1;
11050394Stg			break;
11129983Smsmith		case 't':
11259436Scracauer			tv.tv_sec = strtol(shoptarg, &tvptr, 0);
11359436Scracauer			if (tvptr == shoptarg)
11429983Smsmith				error("timeout value");
11529983Smsmith			switch(*tvptr) {
11629983Smsmith			case 0:
11729983Smsmith			case 's':
11829983Smsmith				break;
11929983Smsmith			case 'h':
12029983Smsmith				tv.tv_sec *= 60;
12129983Smsmith				/* FALLTHROUGH */
12229983Smsmith			case 'm':
12329983Smsmith				tv.tv_sec *= 60;
12429983Smsmith				break;
12529983Smsmith			default:
12629983Smsmith				error("timeout unit");
12729983Smsmith			}
12829983Smsmith			break;
12929983Smsmith		}
1301556Srgrimes	}
1311556Srgrimes	if (prompt && isatty(0)) {
1321556Srgrimes		out2str(prompt);
1331556Srgrimes		flushall();
1341556Srgrimes	}
1351556Srgrimes	if (*(ap = argptr) == NULL)
1361556Srgrimes		error("arg count");
1371556Srgrimes	if ((ifs = bltinlookup("IFS", 1)) == NULL)
1381556Srgrimes		ifs = nullstr;
13929983Smsmith
14029983Smsmith	if (tv.tv_sec >= 0) {
14129983Smsmith		/*
14229983Smsmith		 * See if we can disable input processing; this will
14329983Smsmith		 * not give the desired result if we are in a pipeline
14429983Smsmith		 * and someone upstream is still in line-by-line mode.
14529983Smsmith		 */
14629983Smsmith		tsaved = 0;
14729983Smsmith		if (tcgetattr(0, &told) == 0) {
14829983Smsmith			memcpy(&tnew, &told, sizeof(told));
14929983Smsmith			cfmakeraw(&tnew);
15029983Smsmith			tcsetattr(0, TCSANOW, &tnew);
15129983Smsmith			tsaved = 1;
15229983Smsmith		}
15329983Smsmith		/*
15429983Smsmith		 * Wait for something to become available.
15529983Smsmith		 */
15629983Smsmith		FD_ZERO(&ifds);
15729983Smsmith		FD_SET(0, &ifds);
15829983Smsmith		status = select(1, &ifds, NULL, NULL, &tv);
15929983Smsmith		if (tsaved)
16029983Smsmith			tcsetattr(0, TCSANOW, &told);
16129983Smsmith		/*
16229983Smsmith		 * If there's nothing ready, return an error.
16329983Smsmith		 */
16429983Smsmith		if (status <= 0)
16529983Smsmith			return(1);
16629983Smsmith	}
16729983Smsmith
1681556Srgrimes	status = 0;
1691556Srgrimes	startword = 1;
1701556Srgrimes	backslash = 0;
1711556Srgrimes	STARTSTACKSTR(p);
1721556Srgrimes	for (;;) {
17380381Ssheldonh		if (read(STDIN_FILENO, &c, 1) != 1) {
1741556Srgrimes			status = 1;
1751556Srgrimes			break;
1761556Srgrimes		}
1771556Srgrimes		if (c == '\0')
1781556Srgrimes			continue;
1791556Srgrimes		if (backslash) {
1801556Srgrimes			backslash = 0;
1811556Srgrimes			if (c != '\n')
1821556Srgrimes				STPUTC(c, p);
1831556Srgrimes			continue;
1841556Srgrimes		}
18550394Stg		if (!rflag && c == '\\') {
1861556Srgrimes			backslash++;
1871556Srgrimes			continue;
1881556Srgrimes		}
1891556Srgrimes		if (c == '\n')
1901556Srgrimes			break;
1911556Srgrimes		if (startword && *ifs == ' ' && strchr(ifs, c)) {
1921556Srgrimes			continue;
1931556Srgrimes		}
1941556Srgrimes		startword = 0;
195149825Srse		if (ap[1] != NULL && strchr(ifs, c) != NULL) {
1961556Srgrimes			STACKSTRNUL(p);
1971556Srgrimes			setvar(*ap, stackblock(), 0);
1981556Srgrimes			ap++;
1991556Srgrimes			startword = 1;
2001556Srgrimes			STARTSTACKSTR(p);
2011556Srgrimes		} else {
2021556Srgrimes			STPUTC(c, p);
2031556Srgrimes		}
2041556Srgrimes	}
2051556Srgrimes	STACKSTRNUL(p);
2061556Srgrimes	setvar(*ap, stackblock(), 0);
2071556Srgrimes	while (*++ap != NULL)
2081556Srgrimes		setvar(*ap, nullstr, 0);
2091556Srgrimes	return status;
2101556Srgrimes}
2111556Srgrimes
2121556Srgrimes
2131556Srgrimes
21417987Speterint
21590111Simpumaskcmd(int argc __unused, char **argv)
21617987Speter{
21717987Speter	char *ap;
2181556Srgrimes	int mask;
2191556Srgrimes	int i;
22017987Speter	int symbolic_mode = 0;
2211556Srgrimes
22217987Speter	while ((i = nextopt("S")) != '\0') {
22317987Speter		symbolic_mode = 1;
2241556Srgrimes	}
22511571Sjoerg
22617987Speter	INTOFF;
22717987Speter	mask = umask(0);
22817987Speter	umask(mask);
22917987Speter	INTON;
23011571Sjoerg
23117987Speter	if ((ap = *argptr) == NULL) {
23217987Speter		if (symbolic_mode) {
23317987Speter			char u[4], g[4], o[4];
23411571Sjoerg
23517987Speter			i = 0;
23617987Speter			if ((mask & S_IRUSR) == 0)
23717987Speter				u[i++] = 'r';
23817987Speter			if ((mask & S_IWUSR) == 0)
23917987Speter				u[i++] = 'w';
24017987Speter			if ((mask & S_IXUSR) == 0)
24117987Speter				u[i++] = 'x';
24217987Speter			u[i] = '\0';
24311571Sjoerg
24417987Speter			i = 0;
24517987Speter			if ((mask & S_IRGRP) == 0)
24617987Speter				g[i++] = 'r';
24717987Speter			if ((mask & S_IWGRP) == 0)
24817987Speter				g[i++] = 'w';
24917987Speter			if ((mask & S_IXGRP) == 0)
25017987Speter				g[i++] = 'x';
25117987Speter			g[i] = '\0';
25211571Sjoerg
25317987Speter			i = 0;
25417987Speter			if ((mask & S_IROTH) == 0)
25517987Speter				o[i++] = 'r';
25617987Speter			if ((mask & S_IWOTH) == 0)
25717987Speter				o[i++] = 'w';
25817987Speter			if ((mask & S_IXOTH) == 0)
25917987Speter				o[i++] = 'x';
26017987Speter			o[i] = '\0';
26111571Sjoerg
26217987Speter			out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
26317987Speter		} else {
26417987Speter			out1fmt("%.4o\n", mask);
26517987Speter		}
26617987Speter	} else {
26717987Speter		if (isdigit(*ap)) {
26817987Speter			mask = 0;
26917987Speter			do {
27017987Speter				if (*ap >= '8' || *ap < '0')
271149918Sstefanf					error("Illegal number: %s", *argptr);
27217987Speter				mask = (mask << 3) + (*ap - '0');
27317987Speter			} while (*++ap != '\0');
27417987Speter			umask(mask);
27517987Speter		} else {
27620425Ssteve			void *set;
277151795Sstefanf			INTOFF;
27817987Speter			if ((set = setmode (ap)) == 0)
27941844Simp				error("Illegal number: %s", ap);
28011571Sjoerg
28117987Speter			mask = getmode (set, ~mask & 0777);
28217987Speter			umask(~mask & 0777);
28341844Simp			free(set);
284151795Sstefanf			INTON;
28517987Speter		}
28617987Speter	}
28711571Sjoerg	return 0;
28811571Sjoerg}
28911571Sjoerg
29017987Speter/*
29117987Speter * ulimit builtin
29217987Speter *
29317987Speter * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
29417987Speter * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
29517987Speter * ash by J.T. Conklin.
29617987Speter *
29717987Speter * Public domain.
29817987Speter */
29911571Sjoerg
30017987Speterstruct limits {
30117987Speter	const char *name;
30218016Speter	const char *units;
30317987Speter	int	cmd;
30417987Speter	int	factor;	/* multiply by to get rlim_{cur,max} values */
30517987Speter	char	option;
30617987Speter};
30711571Sjoerg
30817987Speterstatic const struct limits limits[] = {
30917987Speter#ifdef RLIMIT_CPU
31018016Speter	{ "cpu time",		"seconds",	RLIMIT_CPU,	   1, 't' },
31117987Speter#endif
31217987Speter#ifdef RLIMIT_FSIZE
31318016Speter	{ "file size",		"512-blocks",	RLIMIT_FSIZE,	 512, 'f' },
31417987Speter#endif
31517987Speter#ifdef RLIMIT_DATA
31618016Speter	{ "data seg size",	"kbytes",	RLIMIT_DATA,	1024, 'd' },
31717987Speter#endif
31817987Speter#ifdef RLIMIT_STACK
31918016Speter	{ "stack size",		"kbytes",	RLIMIT_STACK,	1024, 's' },
32017987Speter#endif
32117987Speter#ifdef  RLIMIT_CORE
32218016Speter	{ "core file size",	"512-blocks",	RLIMIT_CORE,	 512, 'c' },
32317987Speter#endif
32417987Speter#ifdef RLIMIT_RSS
32518016Speter	{ "max memory size",	"kbytes",	RLIMIT_RSS,	1024, 'm' },
32617987Speter#endif
32717987Speter#ifdef RLIMIT_MEMLOCK
32818016Speter	{ "locked memory",	"kbytes",	RLIMIT_MEMLOCK, 1024, 'l' },
32917987Speter#endif
33017987Speter#ifdef RLIMIT_NPROC
33118016Speter	{ "max user processes",	(char *)0,	RLIMIT_NPROC,      1, 'u' },
33217987Speter#endif
33317987Speter#ifdef RLIMIT_NOFILE
33418016Speter	{ "open files",		(char *)0,	RLIMIT_NOFILE,     1, 'n' },
33517987Speter#endif
33617987Speter#ifdef RLIMIT_VMEM
33718016Speter	{ "virtual mem size",	"kbytes",	RLIMIT_VMEM,	1024, 'v' },
33817987Speter#endif
33917987Speter#ifdef RLIMIT_SWAP
34018016Speter	{ "swap limit",		"kbytes",	RLIMIT_SWAP,	1024, 'w' },
34117987Speter#endif
34252072Sgreen#ifdef RLIMIT_SBSIZE
34352072Sgreen	{ "sbsize",		"bytes",	RLIMIT_SBSIZE,	   1, 'b' },
34452072Sgreen#endif
345181905Sed#ifdef RLIMIT_NPTS
346181905Sed	{ "pseudo-terminals",	(char *)0,	RLIMIT_NPTS,	   1, 'p' },
347181905Sed#endif
34818016Speter	{ (char *) 0,		(char *)0,	0,		   0, '\0' }
34917987Speter};
35017987Speter
35117987Speterint
35290111Simpulimitcmd(int argc __unused, char **argv __unused)
35317987Speter{
35425222Ssteve	int	c;
355104282Smux	rlim_t val = 0;
35617987Speter	enum { SOFT = 0x1, HARD = 0x2 }
35717987Speter			how = SOFT | HARD;
35817987Speter	const struct limits	*l;
35917987Speter	int		set, all = 0;
36017987Speter	int		optc, what;
36117987Speter	struct rlimit	limit;
36211571Sjoerg
36317987Speter	what = 'f';
364181905Sed	while ((optc = nextopt("HSatfdsmcnuvlbp")) != '\0')
36517987Speter		switch (optc) {
36611571Sjoerg		case 'H':
36717987Speter			how = HARD;
36811571Sjoerg			break;
36911571Sjoerg		case 'S':
37017987Speter			how = SOFT;
37111571Sjoerg			break;
37211571Sjoerg		case 'a':
37317987Speter			all = 1;
37411571Sjoerg			break;
37517987Speter		default:
37617987Speter			what = optc;
37711571Sjoerg		}
37811571Sjoerg
37917987Speter	for (l = limits; l->name && l->option != what; l++)
38017987Speter		;
38117987Speter	if (!l->name)
382104208Stjr		error("internal error (%c)", what);
38317987Speter
38417987Speter	set = *argptr ? 1 : 0;
38517987Speter	if (set) {
38617987Speter		char *p = *argptr;
38717987Speter
38817987Speter		if (all || argptr[1])
389104208Stjr			error("too many arguments");
39017987Speter		if (strcmp(p, "unlimited") == 0)
39111571Sjoerg			val = RLIM_INFINITY;
39211571Sjoerg		else {
393104282Smux			val = 0;
39417987Speter
39517987Speter			while ((c = *p++) >= '0' && c <= '9')
39617987Speter			{
39717987Speter				val = (val * 10) + (long)(c - '0');
398104282Smux				if (val < 0)
39917987Speter					break;
40017987Speter			}
40117987Speter			if (c)
402104208Stjr				error("bad number");
40317987Speter			val *= l->factor;
40411571Sjoerg		}
40517987Speter	}
40617987Speter	if (all) {
407155301Sschweikh		for (l = limits; l->name; l++) {
40818016Speter			char optbuf[40];
40918016Speter			if (getrlimit(l->cmd, &limit) < 0)
410104208Stjr				error("can't get limit: %s", strerror(errno));
41117987Speter			if (how & SOFT)
41217987Speter				val = limit.rlim_cur;
41317987Speter			else if (how & HARD)
41417987Speter				val = limit.rlim_max;
41517987Speter
41618016Speter			if (l->units)
41718016Speter				snprintf(optbuf, sizeof(optbuf),
41818019Speter					"(%s, -%c) ", l->units, l->option);
41918016Speter			else
42018016Speter				snprintf(optbuf, sizeof(optbuf),
42118019Speter					"(-%c) ", l->option);
42218019Speter			out1fmt("%-18s %18s ", l->name, optbuf);
42317987Speter			if (val == RLIM_INFINITY)
42417987Speter				out1fmt("unlimited\n");
42517987Speter			else
42617987Speter			{
42717987Speter				val /= l->factor;
428104282Smux				out1fmt("%jd\n", (intmax_t)val);
42917987Speter			}
43011571Sjoerg		}
43117987Speter		return 0;
43211571Sjoerg	}
43317987Speter
43418016Speter	if (getrlimit(l->cmd, &limit) < 0)
435104208Stjr		error("can't get limit: %s", strerror(errno));
43617987Speter	if (set) {
43717987Speter		if (how & SOFT)
43817987Speter			limit.rlim_cur = val;
43917987Speter		if (how & HARD)
44017987Speter			limit.rlim_max = val;
44117987Speter		if (setrlimit(l->cmd, &limit) < 0)
442104208Stjr			error("bad limit: %s", strerror(errno));
44317987Speter	} else {
44417987Speter		if (how & SOFT)
44517987Speter			val = limit.rlim_cur;
44617987Speter		else if (how & HARD)
44717987Speter			val = limit.rlim_max;
44817987Speter
44917987Speter		if (val == RLIM_INFINITY)
45017987Speter			out1fmt("unlimited\n");
45117987Speter		else
45217987Speter		{
45317987Speter			val /= l->factor;
454104282Smux			out1fmt("%jd\n", (intmax_t)val);
45517987Speter		}
45617987Speter	}
45711571Sjoerg	return 0;
45811571Sjoerg}
459