miscbltin.c revision 99110
10SN/A/*-
21410Sihse * Copyright (c) 1991, 1993
30SN/A *	The Regents of the University of California.  All rights reserved.
40SN/A *
50SN/A * This code is derived from software contributed to Berkeley by
60SN/A * Kenneth Almquist.
7180SN/A *
80SN/A * Redistribution and use in source and binary forms, with or without
9180SN/A * modification, are permitted provided that the following conditions
100SN/A * are met:
110SN/A * 1. Redistributions of source code must retain the above copyright
120SN/A *    notice, this list of conditions and the following disclaimer.
130SN/A * 2. Redistributions in binary form must reproduce the above copyright
140SN/A *    notice, this list of conditions and the following disclaimer in the
150SN/A *    documentation and/or other materials provided with the distribution.
160SN/A * 3. All advertising materials mentioning features or use of this software
170SN/A *    must display the following acknowledgement:
180SN/A *	This product includes software developed by the University of
190SN/A *	California, Berkeley and its contributors.
200SN/A * 4. Neither the name of the University nor the names of its contributors
21180SN/A *    may be used to endorse or promote products derived from this software
22180SN/A *    without specific prior written permission.
23180SN/A *
240SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
250SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261410Sihse * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271410Sihse * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281410Sihse * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291410Sihse * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301410Sihse * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311410Sihse * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32910SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33910SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341410Sihse * SUCH DAMAGE.
355SN/A */
36910SN/A
371410Sihse#ifndef lint
38910SN/A#if 0
39338SN/Astatic char sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
401426Sihse#endif
411410Sihse#endif /* not lint */
421426Sihse#include <sys/cdefs.h>
431410Sihse__FBSDID("$FreeBSD: head/bin/sh/miscbltin.c 99110 2002-06-30 05:15:05Z obrien $");
441410Sihse
451426Sihse/*
461426Sihse * Miscellaneous builtins.
47311SN/A */
481426Sihse
491426Sihse#include <sys/types.h>
501426Sihse#include <sys/stat.h>
511410Sihse#include <sys/time.h>
521426Sihse#include <sys/resource.h>
531651Sihse#include <unistd.h>
541651Sihse#include <ctype.h>
551120SN/A#include <errno.h>
561410Sihse#include <stdio.h>
571410Sihse#include <stdlib.h>
581410Sihse#include <termios.h>
591426Sihse
601426Sihse#include "shell.h"
611426Sihse#include "options.h"
621426Sihse#include "var.h"
631426Sihse#include "output.h"
641426Sihse#include "memalloc.h"
651426Sihse#include "error.h"
661426Sihse#include "mystring.h"
671426Sihse
681426Sihse#undef eflag
691426Sihse
701426Sihse/*
711426Sihse * The read builtin.  The -r option causes backslashes to be treated like
721426Sihse * ordinary characters.
731426Sihse *
741426Sihse * This uses unbuffered input, which may be avoidable in some cases.
751426Sihse */
761426Sihse
771426Sihseint
781426Sihsereadcmd(int argc __unused, char **argv __unused)
791426Sihse{
801426Sihse	char **ap;
811426Sihse	int backslash;
821426Sihse	char c;
831426Sihse	int rflag;
841426Sihse	char *prompt;
851426Sihse	char *ifs;
861426Sihse	char *p;
871426Sihse	int startword;
881426Sihse	int status;
891426Sihse	int i;
901426Sihse	struct timeval tv;
911426Sihse	char *tvptr;
921426Sihse	fd_set ifds;
931426Sihse	struct termios told, tnew;
941426Sihse	int tsaved;
951426Sihse
961426Sihse	rflag = 0;
971426Sihse	prompt = NULL;
981426Sihse	tv.tv_sec = -1;
991426Sihse	tv.tv_usec = 0;
1001426Sihse	while ((i = nextopt("erp:t:")) != '\0') {
1011426Sihse		switch(i) {
1021426Sihse		case 'p':
1031426Sihse			prompt = shoptarg;
1041426Sihse			break;
1051426Sihse		case 'e':
1061426Sihse			break;
1071426Sihse		case 'r':
1081426Sihse			rflag = 1;
1091426Sihse			break;
1101426Sihse		case 't':
1111426Sihse			tv.tv_sec = strtol(shoptarg, &tvptr, 0);
1121426Sihse			if (tvptr == shoptarg)
1131426Sihse				error("timeout value");
1141426Sihse			switch(*tvptr) {
1151426Sihse			case 0:
1161426Sihse			case 's':
1171426Sihse				break;
1181426Sihse			case 'h':
1191426Sihse				tv.tv_sec *= 60;
1201426Sihse				/* FALLTHROUGH */
1211426Sihse			case 'm':
1221426Sihse				tv.tv_sec *= 60;
1231426Sihse				break;
1241410Sihse			default:
1251120SN/A				error("timeout unit");
1261426Sihse			}
1271426Sihse			break;
1281426Sihse		}
1291426Sihse	}
1301426Sihse	if (prompt && isatty(0)) {
1311426Sihse		out2str(prompt);
1321426Sihse		flushall();
1331410Sihse	}
1341426Sihse	if (*(ap = argptr) == NULL)
1351426Sihse		error("arg count");
1361426Sihse	if ((ifs = bltinlookup("IFS", 1)) == NULL)
13727SN/A		ifs = nullstr;
1381410Sihse
1391410Sihse	if (tv.tv_sec >= 0) {
1401701Sihse		/*
1411701Sihse		 * See if we can disable input processing; this will
1421701Sihse		 * not give the desired result if we are in a pipeline
1431410Sihse		 * and someone upstream is still in line-by-line mode.
1441410Sihse		 */
1451410Sihse		tsaved = 0;
1461410Sihse		if (tcgetattr(0, &told) == 0) {
1471410Sihse			memcpy(&tnew, &told, sizeof(told));
1481410Sihse			cfmakeraw(&tnew);
1491410Sihse			tcsetattr(0, TCSANOW, &tnew);
1501426Sihse			tsaved = 1;
1511426Sihse		}
1521410Sihse		/*
1531410Sihse		 * Wait for something to become available.
1541410Sihse		 */
1551156SN/A		FD_ZERO(&ifds);
1561120SN/A		FD_SET(0, &ifds);
1571936Sihse		status = select(1, &ifds, NULL, NULL, &tv);
1581936Sihse		if (tsaved)
1591936Sihse			tcsetattr(0, TCSANOW, &told);
1601426Sihse		/*
1611426Sihse		 * If there's nothing ready, return an error.
1621426Sihse		 */
1631426Sihse		if (status <= 0)
1641410Sihse			return(1);
16527SN/A	}
1661426Sihse
1671426Sihse	status = 0;
1681426Sihse	startword = 1;
1691426Sihse	backslash = 0;
1701426Sihse	STARTSTACKSTR(p);
1711426Sihse	for (;;) {
1721651Sihse		if (read(STDIN_FILENO, &c, 1) != 1) {
1731651Sihse			status = 1;
1741915Sihse			break;
1751651Sihse		}
1761651Sihse		if (c == '\0')
1771651Sihse			continue;
1781651Sihse		if (backslash) {
1791426Sihse			backslash = 0;
1801426Sihse			if (c != '\n')
1811426Sihse				STPUTC(c, p);
1821426Sihse			continue;
1831651Sihse		}
1841426Sihse		if (!rflag && c == '\\') {
1851410Sihse			backslash++;
1861410Sihse			continue;
1871410Sihse		}
1881651Sihse		if (c == '\n')
1891410Sihse			break;
1901426Sihse		if (startword && *ifs == ' ' && strchr(ifs, c)) {
1911651Sihse			continue;
1921651Sihse		}
1931651Sihse		startword = 0;
1941651Sihse		if (backslash && c == '\\') {
1951651Sihse			if (read(STDIN_FILENO, &c, 1) != 1) {
1961651Sihse				status = 1;
1971651Sihse				break;
1981651Sihse			}
1991651Sihse			STPUTC(c, p);
2001651Sihse		} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
2011651Sihse			STACKSTRNUL(p);
2021651Sihse			setvar(*ap, stackblock(), 0);
2031651Sihse			ap++;
2041651Sihse			startword = 1;
2051410Sihse			STARTSTACKSTR(p);
2061410Sihse		} else {
2071410Sihse			STPUTC(c, p);
2081410Sihse		}
2090SN/A	}
2101426Sihse	STACKSTRNUL(p);
2111410Sihse	setvar(*ap, stackblock(), 0);
2121410Sihse	while (*++ap != NULL)
2131410Sihse		setvar(*ap, nullstr, 0);
2141410Sihse	return status;
2151410Sihse}
2161410Sihse
2171410Sihse
2181410Sihse
2191410Sihseint
2201426Sihseumaskcmd(int argc __unused, char **argv)
2211426Sihse{
2221426Sihse	char *ap;
2231426Sihse	int mask;
2241426Sihse	int i;
2251426Sihse	int symbolic_mode = 0;
2261426Sihse
2271426Sihse	while ((i = nextopt("S")) != '\0') {
2281651Sihse		symbolic_mode = 1;
2291651Sihse	}
2301651Sihse
2311410Sihse	INTOFF;
2321862Serikj	mask = umask(0);
2331862Serikj	umask(mask);
2341410Sihse	INTON;
2351410Sihse
2361410Sihse	if ((ap = *argptr) == NULL) {
2371410Sihse		if (symbolic_mode) {
2381410Sihse			char u[4], g[4], o[4];
2391410Sihse
2401426Sihse			i = 0;
2411426Sihse			if ((mask & S_IRUSR) == 0)
2421426Sihse				u[i++] = 'r';
2431426Sihse			if ((mask & S_IWUSR) == 0)
2441426Sihse				u[i++] = 'w';
2451426Sihse			if ((mask & S_IXUSR) == 0)
2461426Sihse				u[i++] = 'x';
2471426Sihse			u[i] = '\0';
2481426Sihse
2491426Sihse			i = 0;
2501426Sihse			if ((mask & S_IRGRP) == 0)
2511426Sihse				g[i++] = 'r';
2521426Sihse			if ((mask & S_IWGRP) == 0)
2531327SN/A				g[i++] = 'w';
2541628Sihse			if ((mask & S_IXGRP) == 0)
2551628Sihse				g[i++] = 'x';
2561628Sihse			g[i] = '\0';
2571410Sihse
2581410Sihse			i = 0;
2591410Sihse			if ((mask & S_IROTH) == 0)
2601410Sihse				o[i++] = 'r';
2611410Sihse			if ((mask & S_IWOTH) == 0)
2621410Sihse				o[i++] = 'w';
2631410Sihse			if ((mask & S_IXOTH) == 0)
2641410Sihse				o[i++] = 'x';
2651410Sihse			o[i] = '\0';
2661426Sihse
2671426Sihse			out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
2681426Sihse		} else {
2691410Sihse			out1fmt("%.4o\n", mask);
2701651Sihse		}
2711426Sihse	} else {
2721426Sihse		if (isdigit(*ap)) {
2731410Sihse			mask = 0;
2741410Sihse			do {
2751410Sihse				if (*ap >= '8' || *ap < '0')
2761410Sihse					error("Illegal number: %s", argv[1]);
2771410Sihse				mask = (mask << 3) + (*ap - '0');
2780SN/A			} while (*++ap != '\0');
2791426Sihse			umask(mask);
2801426Sihse		} else {
2811426Sihse			void *set;
2821623Sihse			if ((set = setmode (ap)) == 0)
2831862Serikj				error("Illegal number: %s", ap);
2841426Sihse
2851426Sihse			mask = getmode (set, ~mask & 0777);
2861862Serikj			umask(~mask & 0777);
2871426Sihse			free(set);
2881426Sihse		}
2891426Sihse	}
2901426Sihse	return 0;
2911426Sihse}
2921426Sihse
2931426Sihse/*
2941426Sihse * ulimit builtin
2951862Serikj *
2961623Sihse * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
2971862Serikj * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
2981862Serikj * ash by J.T. Conklin.
2991862Serikj *
3001862Serikj * Public domain.
3011623Sihse */
3021623Sihse
3031623Sihsestruct limits {
3041426Sihse	const char *name;
3051426Sihse	const char *units;
3061426Sihse	int	cmd;
3071426Sihse	int	factor;	/* multiply by to get rlim_{cur,max} values */
3081862Serikj	char	option;
3091410Sihse};
3101410Sihse
3111623Sihsestatic const struct limits limits[] = {
3121745Sihse#ifdef RLIMIT_CPU
3131745Sihse	{ "cpu time",		"seconds",	RLIMIT_CPU,	   1, 't' },
3141745Sihse#endif
3151745Sihse#ifdef RLIMIT_FSIZE
3161745Sihse	{ "file size",		"512-blocks",	RLIMIT_FSIZE,	 512, 'f' },
3171623Sihse#endif
3181623Sihse#ifdef RLIMIT_DATA
3191651Sihse	{ "data seg size",	"kbytes",	RLIMIT_DATA,	1024, 'd' },
3201651Sihse#endif
3211900Sihse#ifdef RLIMIT_STACK
3221745Sihse	{ "stack size",		"kbytes",	RLIMIT_STACK,	1024, 's' },
3231651Sihse#endif
3241651Sihse#ifdef  RLIMIT_CORE
3251926Serikj	{ "core file size",	"512-blocks",	RLIMIT_CORE,	 512, 'c' },
3261745Sihse#endif
3271745Sihse#ifdef RLIMIT_RSS
3281651Sihse	{ "max memory size",	"kbytes",	RLIMIT_RSS,	1024, 'm' },
3291623Sihse#endif
3301410Sihse#ifdef RLIMIT_MEMLOCK
331	{ "locked memory",	"kbytes",	RLIMIT_MEMLOCK, 1024, 'l' },
332#endif
333#ifdef RLIMIT_NPROC
334	{ "max user processes",	(char *)0,	RLIMIT_NPROC,      1, 'u' },
335#endif
336#ifdef RLIMIT_NOFILE
337	{ "open files",		(char *)0,	RLIMIT_NOFILE,     1, 'n' },
338#endif
339#ifdef RLIMIT_VMEM
340	{ "virtual mem size",	"kbytes",	RLIMIT_VMEM,	1024, 'v' },
341#endif
342#ifdef RLIMIT_SWAP
343	{ "swap limit",		"kbytes",	RLIMIT_SWAP,	1024, 'w' },
344#endif
345#ifdef RLIMIT_SBSIZE
346	{ "sbsize",		"bytes",	RLIMIT_SBSIZE,	   1, 'b' },
347#endif
348	{ (char *) 0,		(char *)0,	0,		   0, '\0' }
349};
350
351int
352ulimitcmd(int argc __unused, char **argv __unused)
353{
354	int	c;
355	quad_t val = 0;
356	enum { SOFT = 0x1, HARD = 0x2 }
357			how = SOFT | HARD;
358	const struct limits	*l;
359	int		set, all = 0;
360	int		optc, what;
361	struct rlimit	limit;
362
363	what = 'f';
364	while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0')
365		switch (optc) {
366		case 'H':
367			how = HARD;
368			break;
369		case 'S':
370			how = SOFT;
371			break;
372		case 'a':
373			all = 1;
374			break;
375		default:
376			what = optc;
377		}
378
379	for (l = limits; l->name && l->option != what; l++)
380		;
381	if (!l->name)
382		error("ulimit: internal error (%c)", what);
383
384	set = *argptr ? 1 : 0;
385	if (set) {
386		char *p = *argptr;
387
388		if (all || argptr[1])
389			error("ulimit: too many arguments");
390		if (strcmp(p, "unlimited") == 0)
391			val = RLIM_INFINITY;
392		else {
393			val = (quad_t) 0;
394
395			while ((c = *p++) >= '0' && c <= '9')
396			{
397				val = (val * 10) + (long)(c - '0');
398				if (val < (quad_t) 0)
399					break;
400			}
401			if (c)
402				error("ulimit: bad number");
403			val *= l->factor;
404		}
405	}
406	if (all) {
407		for (l = limits; l->name; l++) {
408			char optbuf[40];
409			if (getrlimit(l->cmd, &limit) < 0)
410				error("ulimit: can't get limit: %s", strerror(errno));
411			if (how & SOFT)
412				val = limit.rlim_cur;
413			else if (how & HARD)
414				val = limit.rlim_max;
415
416			if (l->units)
417				snprintf(optbuf, sizeof(optbuf),
418					"(%s, -%c) ", l->units, l->option);
419			else
420				snprintf(optbuf, sizeof(optbuf),
421					"(-%c) ", l->option);
422			out1fmt("%-18s %18s ", l->name, optbuf);
423			if (val == RLIM_INFINITY)
424				out1fmt("unlimited\n");
425			else
426			{
427				val /= l->factor;
428				out1fmt("%qd\n", (quad_t) val);
429			}
430		}
431		return 0;
432	}
433
434	if (getrlimit(l->cmd, &limit) < 0)
435		error("ulimit: can't get limit: %s", strerror(errno));
436	if (set) {
437		if (how & SOFT)
438			limit.rlim_cur = val;
439		if (how & HARD)
440			limit.rlim_max = val;
441		if (setrlimit(l->cmd, &limit) < 0)
442			error("ulimit: bad limit: %s", strerror(errno));
443	} else {
444		if (how & SOFT)
445			val = limit.rlim_cur;
446		else if (how & HARD)
447			val = limit.rlim_max;
448
449		if (val == RLIM_INFINITY)
450			out1fmt("unlimited\n");
451		else
452		{
453			val /= l->factor;
454			out1fmt("%qd\n", (quad_t) val);
455		}
456	}
457	return 0;
458}
459