miscbltin.c revision 18019
1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	$Id: miscbltin.c,v 1.7 1996/09/03 14:15:54 peter Exp $
37 */
38
39#ifndef lint
40static char sccsid[] = "@(#)miscbltin.c	8.4 (Berkeley) 5/4/95";
41#endif /* not lint */
42
43/*
44 * Miscelaneous builtins.
45 */
46
47#include <sys/types.h>
48#include <sys/stat.h>
49#include <sys/time.h>
50#include <sys/resource.h>
51#include <unistd.h>
52#include <ctype.h>
53#include <errno.h>
54#include <stdio.h>
55
56#include "shell.h"
57#include "options.h"
58#include "var.h"
59#include "output.h"
60#include "memalloc.h"
61#include "error.h"
62#include "mystring.h"
63
64#undef eflag
65
66extern char **argptr;		/* argument list for builtin command */
67
68
69/*
70 * The read builtin.  The -e option causes backslashes to escape the
71 * following character.
72 *
73 * This uses unbuffered input, which may be avoidable in some cases.
74 */
75
76int
77readcmd(argc, argv)
78	int argc;
79	char **argv;
80{
81	char **ap;
82	int backslash;
83	char c;
84	int eflag;
85	char *prompt;
86	char *ifs;
87	char *p;
88	int startword;
89	int status;
90	int i;
91
92	eflag = 0;
93	prompt = NULL;
94	while ((i = nextopt("ep:")) != '\0') {
95		if (i == 'p')
96			prompt = optarg;
97		else
98			eflag = 1;
99	}
100	if (prompt && isatty(0)) {
101		out2str(prompt);
102		flushall();
103	}
104	if (*(ap = argptr) == NULL)
105		error("arg count");
106	if ((ifs = bltinlookup("IFS", 1)) == NULL)
107		ifs = nullstr;
108	status = 0;
109	startword = 1;
110	backslash = 0;
111	STARTSTACKSTR(p);
112	for (;;) {
113		if (read(0, &c, 1) != 1) {
114			status = 1;
115			break;
116		}
117		if (c == '\0')
118			continue;
119		if (backslash) {
120			backslash = 0;
121			if (c != '\n')
122				STPUTC(c, p);
123			continue;
124		}
125		if (eflag && c == '\\') {
126			backslash++;
127			continue;
128		}
129		if (c == '\n')
130			break;
131		if (startword && *ifs == ' ' && strchr(ifs, c)) {
132			continue;
133		}
134		startword = 0;
135		if (backslash && c == '\\') {
136			if (read(0, &c, 1) != 1) {
137				status = 1;
138				break;
139			}
140			STPUTC(c, p);
141		} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
142			STACKSTRNUL(p);
143			setvar(*ap, stackblock(), 0);
144			ap++;
145			startword = 1;
146			STARTSTACKSTR(p);
147		} else {
148			STPUTC(c, p);
149		}
150	}
151	STACKSTRNUL(p);
152	setvar(*ap, stackblock(), 0);
153	while (*++ap != NULL)
154		setvar(*ap, nullstr, 0);
155	return status;
156}
157
158
159
160int
161umaskcmd(argc, argv)
162	int argc;
163	char **argv;
164{
165	char *ap;
166	int mask;
167	int i;
168	int symbolic_mode = 0;
169
170	while ((i = nextopt("S")) != '\0') {
171		symbolic_mode = 1;
172	}
173
174	INTOFF;
175	mask = umask(0);
176	umask(mask);
177	INTON;
178
179	if ((ap = *argptr) == NULL) {
180		if (symbolic_mode) {
181			char u[4], g[4], o[4];
182
183			i = 0;
184			if ((mask & S_IRUSR) == 0)
185				u[i++] = 'r';
186			if ((mask & S_IWUSR) == 0)
187				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	register 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("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("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("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("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("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("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
391	if (!set) {
392		if (val == RLIM_INFINITY)
393			out1fmt("unlimited\n");
394		else
395		{
396			val /= l->factor;
397			out1fmt("%qd\n", (quad_t) val);
398		}
399	}
400	return 0;
401}
402