miscbltin.c revision 25222
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.
353044Sdg *
3625222Ssteve *	$Id: miscbltin.c,v 1.11 1997/02/22 13:58:35 peter Exp $
371556Srgrimes */
381556Srgrimes
391556Srgrimes#ifndef lint
4020425Sstevestatic char const sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
411556Srgrimes#endif /* not lint */
421556Srgrimes
431556Srgrimes/*
441556Srgrimes * Miscelaneous builtins.
451556Srgrimes */
461556Srgrimes
4717987Speter#include <sys/types.h>
4817987Speter#include <sys/stat.h>
4917987Speter#include <sys/time.h>
5017987Speter#include <sys/resource.h>
5117987Speter#include <unistd.h>
5217987Speter#include <ctype.h>
5318016Speter#include <errno.h>
5418018Speter#include <stdio.h>
5517987Speter
561556Srgrimes#include "shell.h"
571556Srgrimes#include "options.h"
581556Srgrimes#include "var.h"
591556Srgrimes#include "output.h"
601556Srgrimes#include "memalloc.h"
611556Srgrimes#include "error.h"
621556Srgrimes#include "mystring.h"
631556Srgrimes
641556Srgrimes#undef eflag
651556Srgrimes
661556Srgrimesextern char **argptr;		/* argument list for builtin command */
671556Srgrimes
681556Srgrimes
691556Srgrimes/*
701556Srgrimes * The read builtin.  The -e option causes backslashes to escape the
711556Srgrimes * following character.
721556Srgrimes *
731556Srgrimes * This uses unbuffered input, which may be avoidable in some cases.
741556Srgrimes */
751556Srgrimes
7617987Speterint
7717987Speterreadcmd(argc, argv)
7817987Speter	int argc;
7920425Ssteve	char **argv;
8017987Speter{
811556Srgrimes	char **ap;
821556Srgrimes	int backslash;
831556Srgrimes	char c;
841556Srgrimes	int eflag;
851556Srgrimes	char *prompt;
861556Srgrimes	char *ifs;
871556Srgrimes	char *p;
881556Srgrimes	int startword;
891556Srgrimes	int status;
901556Srgrimes	int i;
911556Srgrimes
921556Srgrimes	eflag = 0;
931556Srgrimes	prompt = NULL;
941556Srgrimes	while ((i = nextopt("ep:")) != '\0') {
951556Srgrimes		if (i == 'p')
961556Srgrimes			prompt = optarg;
971556Srgrimes		else
981556Srgrimes			eflag = 1;
991556Srgrimes	}
1001556Srgrimes	if (prompt && isatty(0)) {
1011556Srgrimes		out2str(prompt);
1021556Srgrimes		flushall();
1031556Srgrimes	}
1041556Srgrimes	if (*(ap = argptr) == NULL)
1051556Srgrimes		error("arg count");
1061556Srgrimes	if ((ifs = bltinlookup("IFS", 1)) == NULL)
1071556Srgrimes		ifs = nullstr;
1081556Srgrimes	status = 0;
1091556Srgrimes	startword = 1;
1101556Srgrimes	backslash = 0;
1111556Srgrimes	STARTSTACKSTR(p);
1121556Srgrimes	for (;;) {
1131556Srgrimes		if (read(0, &c, 1) != 1) {
1141556Srgrimes			status = 1;
1151556Srgrimes			break;
1161556Srgrimes		}
1171556Srgrimes		if (c == '\0')
1181556Srgrimes			continue;
1191556Srgrimes		if (backslash) {
1201556Srgrimes			backslash = 0;
1211556Srgrimes			if (c != '\n')
1221556Srgrimes				STPUTC(c, p);
1231556Srgrimes			continue;
1241556Srgrimes		}
1251556Srgrimes		if (eflag && c == '\\') {
1261556Srgrimes			backslash++;
1271556Srgrimes			continue;
1281556Srgrimes		}
1291556Srgrimes		if (c == '\n')
1301556Srgrimes			break;
1311556Srgrimes		if (startword && *ifs == ' ' && strchr(ifs, c)) {
1321556Srgrimes			continue;
1331556Srgrimes		}
1341556Srgrimes		startword = 0;
1351556Srgrimes		if (backslash && c == '\\') {
1361556Srgrimes			if (read(0, &c, 1) != 1) {
1371556Srgrimes				status = 1;
1381556Srgrimes				break;
1391556Srgrimes			}
1401556Srgrimes			STPUTC(c, p);
1411556Srgrimes		} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
1421556Srgrimes			STACKSTRNUL(p);
1431556Srgrimes			setvar(*ap, stackblock(), 0);
1441556Srgrimes			ap++;
1451556Srgrimes			startword = 1;
1461556Srgrimes			STARTSTACKSTR(p);
1471556Srgrimes		} else {
1481556Srgrimes			STPUTC(c, p);
1491556Srgrimes		}
1501556Srgrimes	}
1511556Srgrimes	STACKSTRNUL(p);
1521556Srgrimes	setvar(*ap, stackblock(), 0);
1531556Srgrimes	while (*++ap != NULL)
1541556Srgrimes		setvar(*ap, nullstr, 0);
1551556Srgrimes	return status;
1561556Srgrimes}
1571556Srgrimes
1581556Srgrimes
1591556Srgrimes
16017987Speterint
16117987Speterumaskcmd(argc, argv)
16217987Speter	int argc;
16320425Ssteve	char **argv;
16417987Speter{
16517987Speter	char *ap;
1661556Srgrimes	int mask;
1671556Srgrimes	int i;
16817987Speter	int symbolic_mode = 0;
1691556Srgrimes
17017987Speter	while ((i = nextopt("S")) != '\0') {
17117987Speter		symbolic_mode = 1;
1721556Srgrimes	}
17311571Sjoerg
17417987Speter	INTOFF;
17517987Speter	mask = umask(0);
17617987Speter	umask(mask);
17717987Speter	INTON;
17811571Sjoerg
17917987Speter	if ((ap = *argptr) == NULL) {
18017987Speter		if (symbolic_mode) {
18117987Speter			char u[4], g[4], o[4];
18211571Sjoerg
18317987Speter			i = 0;
18417987Speter			if ((mask & S_IRUSR) == 0)
18517987Speter				u[i++] = 'r';
18617987Speter			if ((mask & S_IWUSR) == 0)
18717987Speter				u[i++] = 'w';
18817987Speter			if ((mask & S_IXUSR) == 0)
18917987Speter				u[i++] = 'x';
19017987Speter			u[i] = '\0';
19111571Sjoerg
19217987Speter			i = 0;
19317987Speter			if ((mask & S_IRGRP) == 0)
19417987Speter				g[i++] = 'r';
19517987Speter			if ((mask & S_IWGRP) == 0)
19617987Speter				g[i++] = 'w';
19717987Speter			if ((mask & S_IXGRP) == 0)
19817987Speter				g[i++] = 'x';
19917987Speter			g[i] = '\0';
20011571Sjoerg
20117987Speter			i = 0;
20217987Speter			if ((mask & S_IROTH) == 0)
20317987Speter				o[i++] = 'r';
20417987Speter			if ((mask & S_IWOTH) == 0)
20517987Speter				o[i++] = 'w';
20617987Speter			if ((mask & S_IXOTH) == 0)
20717987Speter				o[i++] = 'x';
20817987Speter			o[i] = '\0';
20911571Sjoerg
21017987Speter			out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
21117987Speter		} else {
21217987Speter			out1fmt("%.4o\n", mask);
21317987Speter		}
21417987Speter	} else {
21517987Speter		if (isdigit(*ap)) {
21617987Speter			mask = 0;
21717987Speter			do {
21817987Speter				if (*ap >= '8' || *ap < '0')
21917987Speter					error("Illegal number: %s", argv[1]);
22017987Speter				mask = (mask << 3) + (*ap - '0');
22117987Speter			} while (*++ap != '\0');
22217987Speter			umask(mask);
22317987Speter		} else {
22420425Ssteve			void *set;
22517987Speter			if ((set = setmode (ap)) == 0)
22617987Speter					error("Illegal number: %s", ap);
22711571Sjoerg
22817987Speter			mask = getmode (set, ~mask & 0777);
22917987Speter			umask(~mask & 0777);
23017987Speter		}
23117987Speter	}
23211571Sjoerg	return 0;
23311571Sjoerg}
23411571Sjoerg
23517987Speter/*
23617987Speter * ulimit builtin
23717987Speter *
23817987Speter * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
23917987Speter * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
24017987Speter * ash by J.T. Conklin.
24117987Speter *
24217987Speter * Public domain.
24317987Speter */
24411571Sjoerg
24517987Speterstruct limits {
24617987Speter	const char *name;
24718016Speter	const char *units;
24817987Speter	int	cmd;
24917987Speter	int	factor;	/* multiply by to get rlim_{cur,max} values */
25017987Speter	char	option;
25117987Speter};
25211571Sjoerg
25317987Speterstatic const struct limits limits[] = {
25417987Speter#ifdef RLIMIT_CPU
25518016Speter	{ "cpu time",		"seconds",	RLIMIT_CPU,	   1, 't' },
25617987Speter#endif
25717987Speter#ifdef RLIMIT_FSIZE
25818016Speter	{ "file size",		"512-blocks",	RLIMIT_FSIZE,	 512, 'f' },
25917987Speter#endif
26017987Speter#ifdef RLIMIT_DATA
26118016Speter	{ "data seg size",	"kbytes",	RLIMIT_DATA,	1024, 'd' },
26217987Speter#endif
26317987Speter#ifdef RLIMIT_STACK
26418016Speter	{ "stack size",		"kbytes",	RLIMIT_STACK,	1024, 's' },
26517987Speter#endif
26617987Speter#ifdef  RLIMIT_CORE
26718016Speter	{ "core file size",	"512-blocks",	RLIMIT_CORE,	 512, 'c' },
26817987Speter#endif
26917987Speter#ifdef RLIMIT_RSS
27018016Speter	{ "max memory size",	"kbytes",	RLIMIT_RSS,	1024, 'm' },
27117987Speter#endif
27217987Speter#ifdef RLIMIT_MEMLOCK
27318016Speter	{ "locked memory",	"kbytes",	RLIMIT_MEMLOCK, 1024, 'l' },
27417987Speter#endif
27517987Speter#ifdef RLIMIT_NPROC
27618016Speter	{ "max user processes",	(char *)0,	RLIMIT_NPROC,      1, 'u' },
27717987Speter#endif
27817987Speter#ifdef RLIMIT_NOFILE
27918016Speter	{ "open files",		(char *)0,	RLIMIT_NOFILE,     1, 'n' },
28017987Speter#endif
28117987Speter#ifdef RLIMIT_VMEM
28218016Speter	{ "virtual mem size",	"kbytes",	RLIMIT_VMEM,	1024, 'v' },
28317987Speter#endif
28417987Speter#ifdef RLIMIT_SWAP
28518016Speter	{ "swap limit",		"kbytes",	RLIMIT_SWAP,	1024, 'w' },
28617987Speter#endif
28718016Speter	{ (char *) 0,		(char *)0,	0,		   0, '\0' }
28817987Speter};
28917987Speter
29017987Speterint
29117987Speterulimitcmd(argc, argv)
29217987Speter	int argc;
29317987Speter	char **argv;
29417987Speter{
29525222Ssteve	int	c;
29618018Speter	quad_t val = 0;
29717987Speter	enum { SOFT = 0x1, HARD = 0x2 }
29817987Speter			how = SOFT | HARD;
29917987Speter	const struct limits	*l;
30017987Speter	int		set, all = 0;
30117987Speter	int		optc, what;
30217987Speter	struct rlimit	limit;
30311571Sjoerg
30417987Speter	what = 'f';
30518016Speter	while ((optc = nextopt("HSatfdsmcnul")) != '\0')
30617987Speter		switch (optc) {
30711571Sjoerg		case 'H':
30817987Speter			how = HARD;
30911571Sjoerg			break;
31011571Sjoerg		case 'S':
31117987Speter			how = SOFT;
31211571Sjoerg			break;
31311571Sjoerg		case 'a':
31417987Speter			all = 1;
31511571Sjoerg			break;
31617987Speter		default:
31717987Speter			what = optc;
31811571Sjoerg		}
31911571Sjoerg
32017987Speter	for (l = limits; l->name && l->option != what; l++)
32117987Speter		;
32217987Speter	if (!l->name)
32320425Ssteve		error("ulimit: internal error (%c)", what);
32417987Speter
32517987Speter	set = *argptr ? 1 : 0;
32617987Speter	if (set) {
32717987Speter		char *p = *argptr;
32817987Speter
32917987Speter		if (all || argptr[1])
33020425Ssteve			error("ulimit: too many arguments");
33117987Speter		if (strcmp(p, "unlimited") == 0)
33211571Sjoerg			val = RLIM_INFINITY;
33311571Sjoerg		else {
33417987Speter			val = (quad_t) 0;
33517987Speter
33617987Speter			while ((c = *p++) >= '0' && c <= '9')
33717987Speter			{
33817987Speter				val = (val * 10) + (long)(c - '0');
33917987Speter				if (val < (quad_t) 0)
34017987Speter					break;
34117987Speter			}
34217987Speter			if (c)
34320425Ssteve				error("ulimit: bad number");
34417987Speter			val *= l->factor;
34511571Sjoerg		}
34617987Speter	}
34717987Speter	if (all) {
34818016Speter		for (l = limits; l->name; l++) {
34918016Speter			char optbuf[40];
35018016Speter			if (getrlimit(l->cmd, &limit) < 0)
35120425Ssteve				error("ulimit: can't get limit: %s", strerror(errno));
35217987Speter			if (how & SOFT)
35317987Speter				val = limit.rlim_cur;
35417987Speter			else if (how & HARD)
35517987Speter				val = limit.rlim_max;
35617987Speter
35718016Speter			if (l->units)
35818016Speter				snprintf(optbuf, sizeof(optbuf),
35918019Speter					"(%s, -%c) ", l->units, l->option);
36018016Speter			else
36118016Speter				snprintf(optbuf, sizeof(optbuf),
36218019Speter					"(-%c) ", l->option);
36318019Speter			out1fmt("%-18s %18s ", l->name, optbuf);
36417987Speter			if (val == RLIM_INFINITY)
36517987Speter				out1fmt("unlimited\n");
36617987Speter			else
36717987Speter			{
36817987Speter				val /= l->factor;
36918018Speter				out1fmt("%qd\n", (quad_t) val);
37017987Speter			}
37111571Sjoerg		}
37217987Speter		return 0;
37311571Sjoerg	}
37417987Speter
37518016Speter	if (getrlimit(l->cmd, &limit) < 0)
37620425Ssteve		error("ulimit: can't get limit: %s", strerror(errno));
37717987Speter	if (set) {
37817987Speter		if (how & SOFT)
37917987Speter			limit.rlim_cur = val;
38017987Speter		if (how & HARD)
38117987Speter			limit.rlim_max = val;
38217987Speter		if (setrlimit(l->cmd, &limit) < 0)
38320425Ssteve			error("ulimit: bad limit: %s", strerror(errno));
38417987Speter	} else {
38517987Speter		if (how & SOFT)
38617987Speter			val = limit.rlim_cur;
38717987Speter		else if (how & HARD)
38817987Speter			val = limit.rlim_max;
38917987Speter
39017987Speter		if (val == RLIM_INFINITY)
39117987Speter			out1fmt("unlimited\n");
39217987Speter		else
39317987Speter		{
39417987Speter			val /= l->factor;
39518018Speter			out1fmt("%qd\n", (quad_t) val);
39617987Speter		}
39717987Speter	}
39811571Sjoerg	return 0;
39911571Sjoerg}
400