miscbltin.c revision 1b1fd61295d76b734f68309d0057699a1ba1cc37
1/*	$NetBSD: miscbltin.c,v 1.34.2.1 2005/04/07 11:34:20 tron Exp $	*/
2
3/*-
4 * Copyright (c) 1991, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
39#else
40__RCSID("$NetBSD: miscbltin.c,v 1.34.2.1 2005/04/07 11:34:20 tron Exp $");
41#endif
42#endif /* not lint */
43
44/*
45 * Miscelaneous builtins.
46 */
47
48#include <sys/types.h>		/* quad_t */
49#include <sys/param.h>		/* BSD4_4 */
50#include <sys/stat.h>
51#include <sys/time.h>
52#include <sys/resource.h>
53#include <unistd.h>
54#include <stdlib.h>
55#include <ctype.h>
56#include <errno.h>
57
58#include "shell.h"
59#include "options.h"
60#include "var.h"
61#include "output.h"
62#include "memalloc.h"
63#include "error.h"
64#include "miscbltin.h"
65#include "mystring.h"
66
67#undef rflag
68
69
70
71/*
72 * The read builtin.
73 * Backslahes escape the next char unless -r is specified.
74 *
75 * This uses unbuffered input, which may be avoidable in some cases.
76 *
77 * Note that if IFS=' :' then read x y should work so that:
78 * 'a b'	x='a', y='b'
79 * ' a b '	x='a', y='b'
80 * ':b'		x='',  y='b'
81 * ':'		x='',  y=''
82 * '::'		x='',  y=''
83 * ': :'	x='',  y=''
84 * ':::'	x='',  y='::'
85 * ':b c:'	x='',  y='b c:'
86 */
87
88int
89readcmd(int argc, char **argv)
90{
91	char **ap;
92	char c;
93	int rflag;
94	char *prompt;
95	const char *ifs;
96	char *p;
97	int startword;
98	int status;
99	int i;
100	int is_ifs;
101	int saveall = 0;
102
103	rflag = 0;
104	prompt = NULL;
105	while ((i = nextopt("p:r")) != '\0') {
106		if (i == 'p')
107			prompt = optionarg;
108		else
109			rflag = 1;
110	}
111
112	if (prompt && isatty(0)) {
113		out2str(prompt);
114		flushall();
115	}
116
117	if (*(ap = argptr) == NULL)
118		error("arg count");
119
120	if ((ifs = bltinlookup("IFS", 1)) == NULL)
121		ifs = " \t\n";
122
123	status = 0;
124	startword = 2;
125	STARTSTACKSTR(p);
126	for (;;) {
127		if (read(0, &c, 1) != 1) {
128			status = 1;
129			break;
130		}
131		if (c == '\0')
132			continue;
133		if (c == '\\' && !rflag) {
134			if (read(0, &c, 1) != 1) {
135				status = 1;
136				break;
137			}
138			if (c != '\n')
139				STPUTC(c, p);
140			continue;
141		}
142		if (c == '\n')
143			break;
144		if (strchr(ifs, c))
145			is_ifs = strchr(" \t\n", c) ? 1 : 2;
146		else
147			is_ifs = 0;
148
149		if (startword != 0) {
150			if (is_ifs == 1) {
151				/* Ignore leading IFS whitespace */
152				if (saveall)
153					STPUTC(c, p);
154				continue;
155			}
156			if (is_ifs == 2 && startword == 1) {
157				/* Only one non-whitespace IFS per word */
158				startword = 2;
159				if (saveall)
160					STPUTC(c, p);
161				continue;
162			}
163		}
164
165		if (is_ifs == 0) {
166			/* append this character to the current variable */
167			startword = 0;
168			if (saveall)
169				/* Not just a spare terminator */
170				saveall++;
171			STPUTC(c, p);
172			continue;
173		}
174
175		/* end of variable... */
176		startword = is_ifs;
177
178		if (ap[1] == NULL) {
179			/* Last variable needs all IFS chars */
180			saveall++;
181			STPUTC(c, p);
182			continue;
183		}
184
185		STACKSTRNUL(p);
186		setvar(*ap, stackblock(), 0);
187		ap++;
188		STARTSTACKSTR(p);
189	}
190	STACKSTRNUL(p);
191
192	/* Remove trailing IFS chars */
193	for (; stackblock() <= --p; *p = 0) {
194		if (!strchr(ifs, *p))
195			break;
196		if (strchr(" \t\n", *p))
197			/* Always remove whitespace */
198			continue;
199		if (saveall > 1)
200			/* Don't remove non-whitespace unless it was naked */
201			break;
202	}
203	setvar(*ap, stackblock(), 0);
204
205	/* Set any remaining args to "" */
206	while (*++ap != NULL)
207		setvar(*ap, nullstr, 0);
208	return status;
209}
210
211
212
213int
214umaskcmd(int argc, char **argv)
215{
216	char *ap;
217	int mask;
218	int i;
219	int symbolic_mode = 0;
220
221	while ((i = nextopt("S")) != '\0') {
222		symbolic_mode = 1;
223	}
224
225	INTOFF;
226	mask = umask(0);
227	umask(mask);
228	INTON;
229
230	if ((ap = *argptr) == NULL) {
231		if (symbolic_mode) {
232			char u[4], g[4], o[4];
233
234			i = 0;
235			if ((mask & S_IRUSR) == 0)
236				u[i++] = 'r';
237			if ((mask & S_IWUSR) == 0)
238				u[i++] = 'w';
239			if ((mask & S_IXUSR) == 0)
240				u[i++] = 'x';
241			u[i] = '\0';
242
243			i = 0;
244			if ((mask & S_IRGRP) == 0)
245				g[i++] = 'r';
246			if ((mask & S_IWGRP) == 0)
247				g[i++] = 'w';
248			if ((mask & S_IXGRP) == 0)
249				g[i++] = 'x';
250			g[i] = '\0';
251
252			i = 0;
253			if ((mask & S_IROTH) == 0)
254				o[i++] = 'r';
255			if ((mask & S_IWOTH) == 0)
256				o[i++] = 'w';
257			if ((mask & S_IXOTH) == 0)
258				o[i++] = 'x';
259			o[i] = '\0';
260
261			out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
262		} else {
263			out1fmt("%.4o\n", mask);
264		}
265	} else {
266		if (isdigit((unsigned char)*ap)) {
267			mask = 0;
268			do {
269				if (*ap >= '8' || *ap < '0')
270					error("Illegal number: %s", argv[1]);
271				mask = (mask << 3) + (*ap - '0');
272			} while (*++ap != '\0');
273			umask(mask);
274		} else
275			error("Illegal mode: %s", ap);
276	}
277	return 0;
278}
279
280#if 1
281/*
282 * ulimit builtin
283 *
284 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
285 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
286 * ash by J.T. Conklin.
287 *
288 * Public domain.
289 */
290
291struct limits {
292	const char *name;
293	int	cmd;
294	int	factor;	/* multiply by to get rlim_{cur,max} values */
295	char	option;
296};
297
298static const struct limits limits[] = {
299#ifdef RLIMIT_CPU
300	{ "time(seconds)",		RLIMIT_CPU,	   1, 't' },
301#endif
302#ifdef RLIMIT_FSIZE
303	{ "file(blocks)",		RLIMIT_FSIZE,	 512, 'f' },
304#endif
305#ifdef RLIMIT_DATA
306	{ "data(kbytes)",		RLIMIT_DATA,	1024, 'd' },
307#endif
308#ifdef RLIMIT_STACK
309	{ "stack(kbytes)",		RLIMIT_STACK,	1024, 's' },
310#endif
311#ifdef  RLIMIT_CORE
312	{ "coredump(blocks)",		RLIMIT_CORE,	 512, 'c' },
313#endif
314#ifdef RLIMIT_RSS
315	{ "memory(kbytes)",		RLIMIT_RSS,	1024, 'm' },
316#endif
317#ifdef RLIMIT_MEMLOCK
318	{ "locked memory(kbytes)",	RLIMIT_MEMLOCK, 1024, 'l' },
319#endif
320#ifdef RLIMIT_NPROC
321	{ "process(processes)",		RLIMIT_NPROC,      1, 'p' },
322#endif
323#ifdef RLIMIT_NOFILE
324	{ "nofiles(descriptors)",	RLIMIT_NOFILE,     1, 'n' },
325#endif
326#ifdef RLIMIT_VMEM
327	{ "vmemory(kbytes)",		RLIMIT_VMEM,	1024, 'v' },
328#endif
329#ifdef RLIMIT_SWAP
330	{ "swap(kbytes)",		RLIMIT_SWAP,	1024, 'w' },
331#endif
332#ifdef RLIMIT_SBSIZE
333	{ "sbsize(bytes)",		RLIMIT_SBSIZE,	   1, 'b' },
334#endif
335	{ (char *) 0,			0,		   0,  '\0' }
336};
337
338int
339ulimitcmd(int argc, char **argv)
340{
341	int	c;
342	rlim_t val = 0;
343	enum { SOFT = 0x1, HARD = 0x2 }
344			how = SOFT | HARD;
345	const struct limits	*l;
346	int		set, all = 0;
347	int		optc, what;
348	struct rlimit	limit;
349
350	what = 'f';
351	while ((optc = nextopt("HSabtfdsmcnpl")) != '\0')
352		switch (optc) {
353		case 'H':
354			how = HARD;
355			break;
356		case 'S':
357			how = SOFT;
358			break;
359		case 'a':
360			all = 1;
361			break;
362		default:
363			what = optc;
364		}
365
366	for (l = limits; l->name && l->option != what; l++)
367		;
368	if (!l->name)
369		error("internal error (%c)", what);
370
371	set = *argptr ? 1 : 0;
372	if (set) {
373		char *p = *argptr;
374
375		if (all || argptr[1])
376			error("too many arguments");
377		if (strcmp(p, "unlimited") == 0)
378			val = RLIM_INFINITY;
379		else {
380			val = (rlim_t) 0;
381
382			while ((c = *p++) >= '0' && c <= '9')
383			{
384				val = (val * 10) + (long)(c - '0');
385				if ((long)val < 0)
386					break;
387			}
388			if (c)
389				error("bad number");
390			val *= l->factor;
391		}
392	}
393	if (all) {
394		for (l = limits; l->name; l++) {
395			getrlimit(l->cmd, &limit);
396			if (how & SOFT)
397				val = limit.rlim_cur;
398			else if (how & HARD)
399				val = limit.rlim_max;
400
401			out1fmt("%-20s ", l->name);
402			if (val == RLIM_INFINITY)
403				out1fmt("unlimited\n");
404			else
405			{
406				val /= l->factor;
407#ifdef BSD4_4
408				out1fmt("%lld\n", (long long) val);
409#else
410				out1fmt("%ld\n", (long) val);
411#endif
412			}
413		}
414		return 0;
415	}
416
417	getrlimit(l->cmd, &limit);
418	if (set) {
419		if (how & HARD)
420			limit.rlim_max = val;
421		if (how & SOFT)
422			limit.rlim_cur = val;
423		if (setrlimit(l->cmd, &limit) < 0)
424			error("error setting limit (%s)", strerror(errno));
425	} else {
426		if (how & SOFT)
427			val = limit.rlim_cur;
428		else if (how & HARD)
429			val = limit.rlim_max;
430
431		if (val == RLIM_INFINITY)
432			out1fmt("unlimited\n");
433		else
434		{
435			val /= l->factor;
436#ifdef BSD4_4
437			out1fmt("%lld\n", (long long) val);
438#else
439			out1fmt("%ld\n", (long) val);
440#endif
441		}
442	}
443	return 0;
444}
445#endif
446