miscbltin.c revision 80381
163128Sps/*-
263128Sps * Copyright (c) 1991, 1993
363128Sps *	The Regents of the University of California.  All rights reserved.
463128Sps *
563128Sps * This code is derived from software contributed to Berkeley by
663128Sps * Kenneth Almquist.
763128Sps *
863128Sps * Redistribution and use in source and binary forms, with or without
963128Sps * modification, are permitted provided that the following conditions
1063128Sps * are met:
1163128Sps * 1. Redistributions of source code must retain the above copyright
1263128Sps *    notice, this list of conditions and the following disclaimer.
1363128Sps * 2. Redistributions in binary form must reproduce the above copyright
1463128Sps *    notice, this list of conditions and the following disclaimer in the
1563128Sps *    documentation and/or other materials provided with the distribution.
1663128Sps * 3. All advertising materials mentioning features or use of this software
1763128Sps *    must display the following acknowledgement:
1863128Sps *	This product includes software developed by the University of
1963128Sps *	California, Berkeley and its contributors.
2063128Sps * 4. Neither the name of the University nor the names of its contributors
2163128Sps *    may be used to endorse or promote products derived from this software
2263128Sps *    without specific prior written permission.
2363128Sps *
2463128Sps * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2563128Sps * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2663128Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2763128Sps * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2863128Sps * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2963128Sps * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30195941Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31195941Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32195941Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33195941Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34195941Sdelphij * SUCH DAMAGE.
35195941Sdelphij */
36195941Sdelphij
3763128Sps#ifndef lint
3863128Sps#if 0
3963128Spsstatic char sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
4063128Sps#endif
4163128Spsstatic const char rcsid[] =
4263128Sps  "$FreeBSD: head/bin/sh/miscbltin.c 80381 2001-07-26 11:02:39Z sheldonh $";
4363128Sps#endif /* not lint */
4463128Sps
4563128Sps/*
4663128Sps * Miscellaneous builtins.
4763128Sps */
4863128Sps
4963128Sps#include <sys/types.h>
5063128Sps#include <sys/stat.h>
5163128Sps#include <sys/time.h>
5263128Sps#include <sys/resource.h>
5363128Sps#include <unistd.h>
5463128Sps#include <ctype.h>
5563128Sps#include <errno.h>
5663128Sps#include <stdio.h>
5763128Sps#include <stdlib.h>
5863128Sps#include <termios.h>
5963128Sps
60#include "shell.h"
61#include "options.h"
62#include "var.h"
63#include "output.h"
64#include "memalloc.h"
65#include "error.h"
66#include "mystring.h"
67
68#undef eflag
69
70/*
71 * The read builtin.  The -r option causes backslashes to be treated like
72 * ordinary characters.
73 *
74 * This uses unbuffered input, which may be avoidable in some cases.
75 */
76
77int
78readcmd(argc, argv)
79	int argc __unused;
80	char **argv __unused;
81{
82	char **ap;
83	int backslash;
84	char c;
85	int rflag;
86	char *prompt;
87	char *ifs;
88	char *p;
89	int startword;
90	int status;
91	int i;
92	struct timeval tv;
93	char *tvptr;
94	fd_set ifds;
95	struct termios told, tnew;
96	int tsaved;
97
98	rflag = 0;
99	prompt = NULL;
100	tv.tv_sec = -1;
101	tv.tv_usec = 0;
102	while ((i = nextopt("erp:t:")) != '\0') {
103		switch(i) {
104		case 'p':
105			prompt = shoptarg;
106			break;
107		case 'e':
108			break;
109		case 'r':
110			rflag = 1;
111			break;
112		case 't':
113			tv.tv_sec = strtol(shoptarg, &tvptr, 0);
114			if (tvptr == shoptarg)
115				error("timeout value");
116			switch(*tvptr) {
117			case 0:
118			case 's':
119				break;
120			case 'h':
121				tv.tv_sec *= 60;
122				/* FALLTHROUGH */
123			case 'm':
124				tv.tv_sec *= 60;
125				break;
126			default:
127				error("timeout unit");
128			}
129			break;
130		}
131	}
132	if (prompt && isatty(0)) {
133		out2str(prompt);
134		flushall();
135	}
136	if (*(ap = argptr) == NULL)
137		error("arg count");
138	if ((ifs = bltinlookup("IFS", 1)) == NULL)
139		ifs = nullstr;
140
141	if (tv.tv_sec >= 0) {
142		/*
143		 * See if we can disable input processing; this will
144		 * not give the desired result if we are in a pipeline
145		 * and someone upstream is still in line-by-line mode.
146		 */
147		tsaved = 0;
148		if (tcgetattr(0, &told) == 0) {
149			memcpy(&tnew, &told, sizeof(told));
150			cfmakeraw(&tnew);
151			tcsetattr(0, TCSANOW, &tnew);
152			tsaved = 1;
153		}
154		/*
155		 * Wait for something to become available.
156		 */
157		FD_ZERO(&ifds);
158		FD_SET(0, &ifds);
159		status = select(1, &ifds, NULL, NULL, &tv);
160		if (tsaved)
161			tcsetattr(0, TCSANOW, &told);
162		/*
163		 * If there's nothing ready, return an error.
164		 */
165		if (status <= 0)
166			return(1);
167	}
168
169	status = 0;
170	startword = 1;
171	backslash = 0;
172	STARTSTACKSTR(p);
173	for (;;) {
174		if (read(STDIN_FILENO, &c, 1) != 1) {
175			status = 1;
176			break;
177		}
178		if (c == '\0')
179			continue;
180		if (backslash) {
181			backslash = 0;
182			if (c != '\n')
183				STPUTC(c, p);
184			continue;
185		}
186		if (!rflag && c == '\\') {
187			backslash++;
188			continue;
189		}
190		if (c == '\n')
191			break;
192		if (startword && *ifs == ' ' && strchr(ifs, c)) {
193			continue;
194		}
195		startword = 0;
196		if (backslash && c == '\\') {
197			if (read(STDIN_FILENO, &c, 1) != 1) {
198				status = 1;
199				break;
200			}
201			STPUTC(c, p);
202		} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
203			STACKSTRNUL(p);
204			setvar(*ap, stackblock(), 0);
205			ap++;
206			startword = 1;
207			STARTSTACKSTR(p);
208		} else {
209			STPUTC(c, p);
210		}
211	}
212	STACKSTRNUL(p);
213	setvar(*ap, stackblock(), 0);
214	while (*++ap != NULL)
215		setvar(*ap, nullstr, 0);
216	return status;
217}
218
219
220
221int
222umaskcmd(argc, argv)
223	int argc __unused;
224	char **argv;
225{
226	char *ap;
227	int mask;
228	int i;
229	int symbolic_mode = 0;
230
231	while ((i = nextopt("S")) != '\0') {
232		symbolic_mode = 1;
233	}
234
235	INTOFF;
236	mask = umask(0);
237	umask(mask);
238	INTON;
239
240	if ((ap = *argptr) == NULL) {
241		if (symbolic_mode) {
242			char u[4], g[4], o[4];
243
244			i = 0;
245			if ((mask & S_IRUSR) == 0)
246				u[i++] = 'r';
247			if ((mask & S_IWUSR) == 0)
248				u[i++] = 'w';
249			if ((mask & S_IXUSR) == 0)
250				u[i++] = 'x';
251			u[i] = '\0';
252
253			i = 0;
254			if ((mask & S_IRGRP) == 0)
255				g[i++] = 'r';
256			if ((mask & S_IWGRP) == 0)
257				g[i++] = 'w';
258			if ((mask & S_IXGRP) == 0)
259				g[i++] = 'x';
260			g[i] = '\0';
261
262			i = 0;
263			if ((mask & S_IROTH) == 0)
264				o[i++] = 'r';
265			if ((mask & S_IWOTH) == 0)
266				o[i++] = 'w';
267			if ((mask & S_IXOTH) == 0)
268				o[i++] = 'x';
269			o[i] = '\0';
270
271			out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
272		} else {
273			out1fmt("%.4o\n", mask);
274		}
275	} else {
276		if (isdigit(*ap)) {
277			mask = 0;
278			do {
279				if (*ap >= '8' || *ap < '0')
280					error("Illegal number: %s", argv[1]);
281				mask = (mask << 3) + (*ap - '0');
282			} while (*++ap != '\0');
283			umask(mask);
284		} else {
285			void *set;
286			if ((set = setmode (ap)) == 0)
287				error("Illegal number: %s", ap);
288
289			mask = getmode (set, ~mask & 0777);
290			umask(~mask & 0777);
291			free(set);
292		}
293	}
294	return 0;
295}
296
297/*
298 * ulimit builtin
299 *
300 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
301 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
302 * ash by J.T. Conklin.
303 *
304 * Public domain.
305 */
306
307struct limits {
308	const char *name;
309	const char *units;
310	int	cmd;
311	int	factor;	/* multiply by to get rlim_{cur,max} values */
312	char	option;
313};
314
315static const struct limits limits[] = {
316#ifdef RLIMIT_CPU
317	{ "cpu time",		"seconds",	RLIMIT_CPU,	   1, 't' },
318#endif
319#ifdef RLIMIT_FSIZE
320	{ "file size",		"512-blocks",	RLIMIT_FSIZE,	 512, 'f' },
321#endif
322#ifdef RLIMIT_DATA
323	{ "data seg size",	"kbytes",	RLIMIT_DATA,	1024, 'd' },
324#endif
325#ifdef RLIMIT_STACK
326	{ "stack size",		"kbytes",	RLIMIT_STACK,	1024, 's' },
327#endif
328#ifdef  RLIMIT_CORE
329	{ "core file size",	"512-blocks",	RLIMIT_CORE,	 512, 'c' },
330#endif
331#ifdef RLIMIT_RSS
332	{ "max memory size",	"kbytes",	RLIMIT_RSS,	1024, 'm' },
333#endif
334#ifdef RLIMIT_MEMLOCK
335	{ "locked memory",	"kbytes",	RLIMIT_MEMLOCK, 1024, 'l' },
336#endif
337#ifdef RLIMIT_NPROC
338	{ "max user processes",	(char *)0,	RLIMIT_NPROC,      1, 'u' },
339#endif
340#ifdef RLIMIT_NOFILE
341	{ "open files",		(char *)0,	RLIMIT_NOFILE,     1, 'n' },
342#endif
343#ifdef RLIMIT_VMEM
344	{ "virtual mem size",	"kbytes",	RLIMIT_VMEM,	1024, 'v' },
345#endif
346#ifdef RLIMIT_SWAP
347	{ "swap limit",		"kbytes",	RLIMIT_SWAP,	1024, 'w' },
348#endif
349#ifdef RLIMIT_SBSIZE
350	{ "sbsize",		"bytes",	RLIMIT_SBSIZE,	   1, 'b' },
351#endif
352	{ (char *) 0,		(char *)0,	0,		   0, '\0' }
353};
354
355int
356ulimitcmd(argc, argv)
357	int argc __unused;
358	char **argv __unused;
359{
360	int	c;
361	quad_t val = 0;
362	enum { SOFT = 0x1, HARD = 0x2 }
363			how = SOFT | HARD;
364	const struct limits	*l;
365	int		set, all = 0;
366	int		optc, what;
367	struct rlimit	limit;
368
369	what = 'f';
370	while ((optc = nextopt("HSatfdsmcnulb")) != '\0')
371		switch (optc) {
372		case 'H':
373			how = HARD;
374			break;
375		case 'S':
376			how = SOFT;
377			break;
378		case 'a':
379			all = 1;
380			break;
381		default:
382			what = optc;
383		}
384
385	for (l = limits; l->name && l->option != what; l++)
386		;
387	if (!l->name)
388		error("ulimit: internal error (%c)", what);
389
390	set = *argptr ? 1 : 0;
391	if (set) {
392		char *p = *argptr;
393
394		if (all || argptr[1])
395			error("ulimit: too many arguments");
396		if (strcmp(p, "unlimited") == 0)
397			val = RLIM_INFINITY;
398		else {
399			val = (quad_t) 0;
400
401			while ((c = *p++) >= '0' && c <= '9')
402			{
403				val = (val * 10) + (long)(c - '0');
404				if (val < (quad_t) 0)
405					break;
406			}
407			if (c)
408				error("ulimit: bad number");
409			val *= l->factor;
410		}
411	}
412	if (all) {
413		for (l = limits; l->name; l++) {
414			char optbuf[40];
415			if (getrlimit(l->cmd, &limit) < 0)
416				error("ulimit: can't get limit: %s", strerror(errno));
417			if (how & SOFT)
418				val = limit.rlim_cur;
419			else if (how & HARD)
420				val = limit.rlim_max;
421
422			if (l->units)
423				snprintf(optbuf, sizeof(optbuf),
424					"(%s, -%c) ", l->units, l->option);
425			else
426				snprintf(optbuf, sizeof(optbuf),
427					"(-%c) ", l->option);
428			out1fmt("%-18s %18s ", l->name, optbuf);
429			if (val == RLIM_INFINITY)
430				out1fmt("unlimited\n");
431			else
432			{
433				val /= l->factor;
434				out1fmt("%qd\n", (quad_t) val);
435			}
436		}
437		return 0;
438	}
439
440	if (getrlimit(l->cmd, &limit) < 0)
441		error("ulimit: can't get limit: %s", strerror(errno));
442	if (set) {
443		if (how & SOFT)
444			limit.rlim_cur = val;
445		if (how & HARD)
446			limit.rlim_max = val;
447		if (setrlimit(l->cmd, &limit) < 0)
448			error("ulimit: bad limit: %s", strerror(errno));
449	} else {
450		if (how & SOFT)
451			val = limit.rlim_cur;
452		else if (how & HARD)
453			val = limit.rlim_max;
454
455		if (val == RLIM_INFINITY)
456			out1fmt("unlimited\n");
457		else
458		{
459			val /= l->factor;
460			out1fmt("%qd\n", (quad_t) val);
461		}
462	}
463	return 0;
464}
465