miscbltin.c revision 25222
190792Sgshapiro/*-
2261370Sgshapiro * Copyright (c) 1991, 1993
390792Sgshapiro *	The Regents of the University of California.  All rights reserved.
490792Sgshapiro *
590792Sgshapiro * This code is derived from software contributed to Berkeley by
690792Sgshapiro * Kenneth Almquist.
790792Sgshapiro *
890792Sgshapiro * Redistribution and use in source and binary forms, with or without
990792Sgshapiro * modification, are permitted provided that the following conditions
1090792Sgshapiro * are met:
1190792Sgshapiro * 1. Redistributions of source code must retain the above copyright
12266711Sgshapiro *    notice, this list of conditions and the following disclaimer.
1390792Sgshapiro * 2. Redistributions in binary form must reproduce the above copyright
1490792Sgshapiro *    notice, this list of conditions and the following disclaimer in the
1590792Sgshapiro *    documentation and/or other materials provided with the distribution.
1690792Sgshapiro * 3. All advertising materials mentioning features or use of this software
1790792Sgshapiro *    must display the following acknowledgement:
1890792Sgshapiro *	This product includes software developed by the University of
1990792Sgshapiro *	California, Berkeley and its contributors.
2090792Sgshapiro * 4. Neither the name of the University nor the names of its contributors
2190792Sgshapiro *    may be used to endorse or promote products derived from this software
2290792Sgshapiro *    without specific prior written permission.
2390792Sgshapiro *
2490792Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2590792Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2690792Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2790792Sgshapiro * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2890792Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2990792Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3090792Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3190792Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3290792Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3390792Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3490792Sgshapiro * SUCH DAMAGE.
3590792Sgshapiro *
3690792Sgshapiro *	$Id: miscbltin.c,v 1.11 1997/02/22 13:58:35 peter Exp $
3790792Sgshapiro */
3890792Sgshapiro
3990792Sgshapiro#ifndef lint
4090792Sgshapirostatic char const sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
4190792Sgshapiro#endif /* not lint */
4290792Sgshapiro
4390792Sgshapiro/*
4490792Sgshapiro * Miscelaneous builtins.
4590792Sgshapiro */
4690792Sgshapiro
4790792Sgshapiro#include <sys/types.h>
4890792Sgshapiro#include <sys/stat.h>
4990792Sgshapiro#include <sys/time.h>
5090792Sgshapiro#include <sys/resource.h>
5190792Sgshapiro#include <unistd.h>
5290792Sgshapiro#include <ctype.h>
5390792Sgshapiro#include <errno.h>
5490792Sgshapiro#include <stdio.h>
5590792Sgshapiro
5690792Sgshapiro#include "shell.h"
5790792Sgshapiro#include "options.h"
5890792Sgshapiro#include "var.h"
5990792Sgshapiro#include "output.h"
6090792Sgshapiro#include "memalloc.h"
6190792Sgshapiro#include "error.h"
6290792Sgshapiro#include "mystring.h"
6390792Sgshapiro
6490792Sgshapiro#undef eflag
6590792Sgshapiro
6690792Sgshapiroextern char **argptr;		/* argument list for builtin command */
6790792Sgshapiro
6890792Sgshapiro
6990792Sgshapiro/*
7090792Sgshapiro * The read builtin.  The -e option causes backslashes to escape the
7190792Sgshapiro * following character.
7290792Sgshapiro *
7390792Sgshapiro * This uses unbuffered input, which may be avoidable in some cases.
7490792Sgshapiro */
7590792Sgshapiro
7690792Sgshapiroint
7790792Sgshapiroreadcmd(argc, argv)
7890792Sgshapiro	int argc;
7990792Sgshapiro	char **argv;
8090792Sgshapiro{
8190792Sgshapiro	char **ap;
8290792Sgshapiro	int backslash;
8390792Sgshapiro	char c;
8490792Sgshapiro	int eflag;
8590792Sgshapiro	char *prompt;
8690792Sgshapiro	char *ifs;
8790792Sgshapiro	char *p;
8890792Sgshapiro	int startword;
8990792Sgshapiro	int status;
9090792Sgshapiro	int i;
9190792Sgshapiro
9290792Sgshapiro	eflag = 0;
9390792Sgshapiro	prompt = NULL;
9490792Sgshapiro	while ((i = nextopt("ep:")) != '\0') {
9590792Sgshapiro		if (i == 'p')
9690792Sgshapiro			prompt = optarg;
9790792Sgshapiro		else
9890792Sgshapiro			eflag = 1;
9990792Sgshapiro	}
10090792Sgshapiro	if (prompt && isatty(0)) {
10190792Sgshapiro		out2str(prompt);
10290792Sgshapiro		flushall();
10390792Sgshapiro	}
10490792Sgshapiro	if (*(ap = argptr) == NULL)
10590792Sgshapiro		error("arg count");
10690792Sgshapiro	if ((ifs = bltinlookup("IFS", 1)) == NULL)
10790792Sgshapiro		ifs = nullstr;
10890792Sgshapiro	status = 0;
10990792Sgshapiro	startword = 1;
11090792Sgshapiro	backslash = 0;
11190792Sgshapiro	STARTSTACKSTR(p);
11290792Sgshapiro	for (;;) {
11390792Sgshapiro		if (read(0, &c, 1) != 1) {
11490792Sgshapiro			status = 1;
11590792Sgshapiro			break;
11690792Sgshapiro		}
11790792Sgshapiro		if (c == '\0')
11890792Sgshapiro			continue;
11990792Sgshapiro		if (backslash) {
12090792Sgshapiro			backslash = 0;
12190792Sgshapiro			if (c != '\n')
12290792Sgshapiro				STPUTC(c, p);
12390792Sgshapiro			continue;
12490792Sgshapiro		}
12590792Sgshapiro		if (eflag && c == '\\') {
12690792Sgshapiro			backslash++;
12790792Sgshapiro			continue;
12890792Sgshapiro		}
12990792Sgshapiro		if (c == '\n')
130125820Sgshapiro			break;
13190792Sgshapiro		if (startword && *ifs == ' ' && strchr(ifs, c)) {
13290792Sgshapiro			continue;
13390792Sgshapiro		}
13490792Sgshapiro		startword = 0;
13590792Sgshapiro		if (backslash && c == '\\') {
13690792Sgshapiro			if (read(0, &c, 1) != 1) {
13790792Sgshapiro				status = 1;
13890792Sgshapiro				break;
13990792Sgshapiro			}
14090792Sgshapiro			STPUTC(c, p);
14190792Sgshapiro		} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
14290792Sgshapiro			STACKSTRNUL(p);
14390792Sgshapiro			setvar(*ap, stackblock(), 0);
14490792Sgshapiro			ap++;
14590792Sgshapiro			startword = 1;
14690792Sgshapiro			STARTSTACKSTR(p);
14790792Sgshapiro		} else {
14890792Sgshapiro			STPUTC(c, p);
14990792Sgshapiro		}
15090792Sgshapiro	}
15190792Sgshapiro	STACKSTRNUL(p);
15290792Sgshapiro	setvar(*ap, stackblock(), 0);
15390792Sgshapiro	while (*++ap != NULL)
15490792Sgshapiro		setvar(*ap, nullstr, 0);
15590792Sgshapiro	return status;
15690792Sgshapiro}
15790792Sgshapiro
15890792Sgshapiro
15990792Sgshapiro
16090792Sgshapiroint
16190792Sgshapiroumaskcmd(argc, argv)
16290792Sgshapiro	int argc;
16390792Sgshapiro	char **argv;
16490792Sgshapiro{
16590792Sgshapiro	char *ap;
166125820Sgshapiro	int mask;
16790792Sgshapiro	int i;
16890792Sgshapiro	int symbolic_mode = 0;
16990792Sgshapiro
17090792Sgshapiro	while ((i = nextopt("S")) != '\0') {
17190792Sgshapiro		symbolic_mode = 1;
17290792Sgshapiro	}
17390792Sgshapiro
17490792Sgshapiro	INTOFF;
17590792Sgshapiro	mask = umask(0);
17690792Sgshapiro	umask(mask);
17790792Sgshapiro	INTON;
17890792Sgshapiro
17990792Sgshapiro	if ((ap = *argptr) == NULL) {
18090792Sgshapiro		if (symbolic_mode) {
18190792Sgshapiro			char u[4], g[4], o[4];
18290792Sgshapiro
18390792Sgshapiro			i = 0;
18490792Sgshapiro			if ((mask & S_IRUSR) == 0)
18590792Sgshapiro				u[i++] = 'r';
18690792Sgshapiro			if ((mask & S_IWUSR) == 0)
18790792Sgshapiro				u[i++] = 'w';
188			if ((mask & S_IXUSR) == 0)
189				u[i++] = 'x';
190			u[i] = '\0';
191
192			i = 0;
193			if ((mask & S_IRGRP) == 0)
194				g[i++] = 'r';
195			if ((mask & S_IWGRP) == 0)
196				g[i++] = 'w';
197			if ((mask & S_IXGRP) == 0)
198				g[i++] = 'x';
199			g[i] = '\0';
200
201			i = 0;
202			if ((mask & S_IROTH) == 0)
203				o[i++] = 'r';
204			if ((mask & S_IWOTH) == 0)
205				o[i++] = 'w';
206			if ((mask & S_IXOTH) == 0)
207				o[i++] = 'x';
208			o[i] = '\0';
209
210			out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
211		} else {
212			out1fmt("%.4o\n", mask);
213		}
214	} else {
215		if (isdigit(*ap)) {
216			mask = 0;
217			do {
218				if (*ap >= '8' || *ap < '0')
219					error("Illegal number: %s", argv[1]);
220				mask = (mask << 3) + (*ap - '0');
221			} while (*++ap != '\0');
222			umask(mask);
223		} else {
224			void *set;
225			if ((set = setmode (ap)) == 0)
226					error("Illegal number: %s", ap);
227
228			mask = getmode (set, ~mask & 0777);
229			umask(~mask & 0777);
230		}
231	}
232	return 0;
233}
234
235/*
236 * ulimit builtin
237 *
238 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
239 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
240 * ash by J.T. Conklin.
241 *
242 * Public domain.
243 */
244
245struct limits {
246	const char *name;
247	const char *units;
248	int	cmd;
249	int	factor;	/* multiply by to get rlim_{cur,max} values */
250	char	option;
251};
252
253static const struct limits limits[] = {
254#ifdef RLIMIT_CPU
255	{ "cpu time",		"seconds",	RLIMIT_CPU,	   1, 't' },
256#endif
257#ifdef RLIMIT_FSIZE
258	{ "file size",		"512-blocks",	RLIMIT_FSIZE,	 512, 'f' },
259#endif
260#ifdef RLIMIT_DATA
261	{ "data seg size",	"kbytes",	RLIMIT_DATA,	1024, 'd' },
262#endif
263#ifdef RLIMIT_STACK
264	{ "stack size",		"kbytes",	RLIMIT_STACK,	1024, 's' },
265#endif
266#ifdef  RLIMIT_CORE
267	{ "core file size",	"512-blocks",	RLIMIT_CORE,	 512, 'c' },
268#endif
269#ifdef RLIMIT_RSS
270	{ "max memory size",	"kbytes",	RLIMIT_RSS,	1024, 'm' },
271#endif
272#ifdef RLIMIT_MEMLOCK
273	{ "locked memory",	"kbytes",	RLIMIT_MEMLOCK, 1024, 'l' },
274#endif
275#ifdef RLIMIT_NPROC
276	{ "max user processes",	(char *)0,	RLIMIT_NPROC,      1, 'u' },
277#endif
278#ifdef RLIMIT_NOFILE
279	{ "open files",		(char *)0,	RLIMIT_NOFILE,     1, 'n' },
280#endif
281#ifdef RLIMIT_VMEM
282	{ "virtual mem size",	"kbytes",	RLIMIT_VMEM,	1024, 'v' },
283#endif
284#ifdef RLIMIT_SWAP
285	{ "swap limit",		"kbytes",	RLIMIT_SWAP,	1024, 'w' },
286#endif
287	{ (char *) 0,		(char *)0,	0,		   0, '\0' }
288};
289
290int
291ulimitcmd(argc, argv)
292	int argc;
293	char **argv;
294{
295	int	c;
296	quad_t val = 0;
297	enum { SOFT = 0x1, HARD = 0x2 }
298			how = SOFT | HARD;
299	const struct limits	*l;
300	int		set, all = 0;
301	int		optc, what;
302	struct rlimit	limit;
303
304	what = 'f';
305	while ((optc = nextopt("HSatfdsmcnul")) != '\0')
306		switch (optc) {
307		case 'H':
308			how = HARD;
309			break;
310		case 'S':
311			how = SOFT;
312			break;
313		case 'a':
314			all = 1;
315			break;
316		default:
317			what = optc;
318		}
319
320	for (l = limits; l->name && l->option != what; l++)
321		;
322	if (!l->name)
323		error("ulimit: internal error (%c)", what);
324
325	set = *argptr ? 1 : 0;
326	if (set) {
327		char *p = *argptr;
328
329		if (all || argptr[1])
330			error("ulimit: too many arguments");
331		if (strcmp(p, "unlimited") == 0)
332			val = RLIM_INFINITY;
333		else {
334			val = (quad_t) 0;
335
336			while ((c = *p++) >= '0' && c <= '9')
337			{
338				val = (val * 10) + (long)(c - '0');
339				if (val < (quad_t) 0)
340					break;
341			}
342			if (c)
343				error("ulimit: bad number");
344			val *= l->factor;
345		}
346	}
347	if (all) {
348		for (l = limits; l->name; l++) {
349			char optbuf[40];
350			if (getrlimit(l->cmd, &limit) < 0)
351				error("ulimit: can't get limit: %s", strerror(errno));
352			if (how & SOFT)
353				val = limit.rlim_cur;
354			else if (how & HARD)
355				val = limit.rlim_max;
356
357			if (l->units)
358				snprintf(optbuf, sizeof(optbuf),
359					"(%s, -%c) ", l->units, l->option);
360			else
361				snprintf(optbuf, sizeof(optbuf),
362					"(-%c) ", l->option);
363			out1fmt("%-18s %18s ", l->name, optbuf);
364			if (val == RLIM_INFINITY)
365				out1fmt("unlimited\n");
366			else
367			{
368				val /= l->factor;
369				out1fmt("%qd\n", (quad_t) val);
370			}
371		}
372		return 0;
373	}
374
375	if (getrlimit(l->cmd, &limit) < 0)
376		error("ulimit: can't get limit: %s", strerror(errno));
377	if (set) {
378		if (how & SOFT)
379			limit.rlim_cur = val;
380		if (how & HARD)
381			limit.rlim_max = val;
382		if (setrlimit(l->cmd, &limit) < 0)
383			error("ulimit: bad limit: %s", strerror(errno));
384	} else {
385		if (how & SOFT)
386			val = limit.rlim_cur;
387		else if (how & HARD)
388			val = limit.rlim_max;
389
390		if (val == RLIM_INFINITY)
391			out1fmt("unlimited\n");
392		else
393		{
394			val /= l->factor;
395			out1fmt("%qd\n", (quad_t) val);
396		}
397	}
398	return 0;
399}
400