1/*	$NetBSD: miscbltin.c,v 1.39 2011/06/18 21:18:46 christos 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.39 2011/06/18 21:18:46 christos 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 "builtins.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			void *set;
276
277			INTOFF;
278			if ((set = setmode(ap)) != 0) {
279				mask = getmode(set, ~mask & 0777);
280				ckfree(set);
281			}
282			INTON;
283			if (!set)
284				error("Cannot set mode `%s' (%s)", ap,
285				    strerror(errno));
286
287			umask(~mask & 0777);
288		}
289	}
290	return 0;
291}
292
293/*
294 * ulimit builtin
295 *
296 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
297 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
298 * ash by J.T. Conklin.
299 *
300 * Public domain.
301 */
302
303struct limits {
304	const char *name;
305	const char *unit;
306	int	cmd;
307	int	factor;	/* multiply by to get rlim_{cur,max} values */
308	char	option;
309};
310
311static const struct limits limits[] = {
312#ifdef RLIMIT_CPU
313	{ "time",	"seconds",	RLIMIT_CPU,	   1, 't' },
314#endif
315#ifdef RLIMIT_FSIZE
316	{ "file",	"blocks",	RLIMIT_FSIZE,	 512, 'f' },
317#endif
318#ifdef RLIMIT_DATA
319	{ "data",	"kbytes",	RLIMIT_DATA,	1024, 'd' },
320#endif
321#ifdef RLIMIT_STACK
322	{ "stack",	"kbytes",	RLIMIT_STACK,	1024, 's' },
323#endif
324#ifdef  RLIMIT_CORE
325	{ "coredump",	"blocks",	RLIMIT_CORE,	 512, 'c' },
326#endif
327#ifdef RLIMIT_RSS
328	{ "memory",	"kbytes",	RLIMIT_RSS,	1024, 'm' },
329#endif
330#ifdef RLIMIT_MEMLOCK
331	{ "locked memory","kbytes",	RLIMIT_MEMLOCK, 1024, 'l' },
332#endif
333#ifdef RLIMIT_NPROC
334	{ "process",	"processes",	RLIMIT_NPROC,      1, 'p' },
335#endif
336#ifdef RLIMIT_NOFILE
337	{ "nofiles",	"descriptors",	RLIMIT_NOFILE,     1, 'n' },
338#endif
339#ifdef RLIMIT_VMEM
340	{ "vmemory",	"kbytes",	RLIMIT_VMEM,	1024, 'v' },
341#endif
342#ifdef RLIMIT_SWAP
343	{ "swap",	"kbytes",	RLIMIT_SWAP,	1024, 'w' },
344#endif
345#ifdef RLIMIT_SBSIZE
346	{ "sbsize",	"bytes",	RLIMIT_SBSIZE,	   1, 'b' },
347#endif
348	{ NULL,		NULL,		0,		   0,  '\0' }
349};
350
351int
352ulimitcmd(int argc, char **argv)
353{
354	int	c;
355	rlim_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("HSabtfdsmcnplv")) != '\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("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("too many arguments");
390		if (strcmp(p, "unlimited") == 0)
391			val = RLIM_INFINITY;
392		else {
393			val = (rlim_t) 0;
394
395			while ((c = *p++) >= '0' && c <= '9')
396				val = (val * 10) + (long)(c - '0');
397			if (c)
398				error("bad number");
399			val *= l->factor;
400		}
401	}
402	if (all) {
403		for (l = limits; l->name; l++) {
404			getrlimit(l->cmd, &limit);
405			if (how & SOFT)
406				val = limit.rlim_cur;
407			else if (how & HARD)
408				val = limit.rlim_max;
409
410			out1fmt("%-13s (-%c %-11s) ", l->name, l->option,
411			    l->unit);
412			if (val == RLIM_INFINITY)
413				out1fmt("unlimited\n");
414			else
415			{
416				val /= l->factor;
417#ifdef BSD4_4
418				out1fmt("%lld\n", (long long) val);
419#else
420				out1fmt("%ld\n", (long) val);
421#endif
422			}
423		}
424		return 0;
425	}
426
427	getrlimit(l->cmd, &limit);
428	if (set) {
429		if (how & HARD)
430			limit.rlim_max = val;
431		if (how & SOFT)
432			limit.rlim_cur = val;
433		if (setrlimit(l->cmd, &limit) < 0)
434			error("error setting limit (%s)", strerror(errno));
435	} else {
436		if (how & SOFT)
437			val = limit.rlim_cur;
438		else if (how & HARD)
439			val = limit.rlim_max;
440
441		if (val == RLIM_INFINITY)
442			out1fmt("unlimited\n");
443		else
444		{
445			val /= l->factor;
446#ifdef BSD4_4
447			out1fmt("%lld\n", (long long) val);
448#else
449			out1fmt("%ld\n", (long) val);
450#endif
451		}
452	}
453	return 0;
454}
455