1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1997-2005
5  *	Herbert Xu <herbert@gondor.apana.org.au>.  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 /*
36  * Miscelaneous builtins.
37  */
38 
39 #include <sys/types.h>		/* quad_t */
40 #include <sys/param.h>		/* BSD4_4 */
41 #include <sys/stat.h>
42 #include <sys/time.h>
43 #include <unistd.h>
44 #include <stdlib.h>
45 #include <ctype.h>
46 #include <inttypes.h>
47 
48 #include "shell.h"
49 #include "options.h"
50 #include "var.h"
51 #include "output.h"
52 #include "memalloc.h"
53 #include "error.h"
54 #include "miscbltin.h"
55 #include "mystring.h"
56 #include "main.h"
57 #include "expand.h"
58 #include "parser.h"
59 #include "trap.h"
60 
61 #undef rflag
62 
63 
64 /** handle one line of the read command.
65  *  more fields than variables -> remainder shall be part of last variable.
66  *  less fields than variables -> remaining variables unset.
67  *
68  *  @param line complete line of input
69  *  @param ac argument count
70  *  @param ap argument (variable) list
71  *  @param len length of line including trailing '\0'
72  */
73 static void
readcmd_handle_line(char * s,int ac,char ** ap)74 readcmd_handle_line(char *s, int ac, char **ap)
75 {
76 	struct arglist arglist;
77 	struct strlist *sl;
78 
79 	s = grabstackstr(s);
80 
81 	arglist.lastp = &arglist.list;
82 
83 	ifsbreakup(s, ac, &arglist);
84 	*arglist.lastp = NULL;
85 	ifsfree();
86 
87 	sl = arglist.list;
88 
89 	do {
90 		if (!sl) {
91 			/* nullify remaining arguments */
92 			do {
93 				setvar(*ap, nullstr, 0);
94 			} while (*++ap);
95 
96 			return;
97 		}
98 
99 		/* set variable to field */
100 		rmescapes(sl->text);
101 		setvar(*ap, sl->text, 0);
102 		sl = sl->next;
103 	} while (*++ap);
104 }
105 
106 /*
107  * The read builtin.  The -e option causes backslashes to escape the
108  * following character. The -p option followed by an argument prompts
109  * with the argument.
110  *
111  * This uses unbuffered input, which may be avoidable in some cases.
112  */
113 
114 int
readcmd(int argc,char ** argv)115 readcmd(int argc, char **argv)
116 {
117 	char **ap;
118 	char c;
119 	int rflag;
120 	char *prompt;
121 	char *p;
122 	int startloc;
123 	int newloc;
124 	int status;
125 	int i;
126 
127 	rflag = 0;
128 	prompt = NULL;
129 	while ((i = nextopt("p:r")) != '\0') {
130 		if (i == 'p')
131 			prompt = optionarg;
132 		else
133 			rflag = 1;
134 	}
135 	if (prompt && isatty(0)) {
136 		out2str(prompt);
137 #ifdef FLUSHERR
138 		flushall();
139 #endif
140 	}
141 	if (*(ap = argptr) == NULL)
142 		sh_error("arg count");
143 
144 	status = 0;
145 	STARTSTACKSTR(p);
146 
147 	goto start;
148 
149 	for (;;) {
150 		switch (read(0, &c, 1)) {
151 		case 1:
152 			break;
153 		default:
154 			if (errno == EINTR && !pendingsigs)
155 				continue;
156 				/* fall through */
157 		case 0:
158 			status = 1;
159 			goto out;
160 		}
161 		if (c == '\0')
162 			continue;
163 		if (newloc >= startloc) {
164 			if (c == '\n')
165 				goto resetbs;
166 			goto put;
167 		}
168 		if (!rflag && c == '\\') {
169 			newloc = p - (char *)stackblock();
170 			continue;
171 		}
172 		if (c == '\n')
173 			break;
174 put:
175 		CHECKSTRSPACE(2, p);
176 		if (strchr(qchars, c))
177 			USTPUTC(CTLESC, p);
178 		USTPUTC(c, p);
179 
180 		if (newloc >= startloc) {
181 resetbs:
182 			recordregion(startloc, newloc, 0);
183 start:
184 			startloc = p - (char *)stackblock();
185 			newloc = startloc - 1;
186 		}
187 	}
188 out:
189 	recordregion(startloc, p - (char *)stackblock(), 0);
190 	STACKSTRNUL(p);
191 	readcmd_handle_line(p + 1, argc - (ap - argv), ap);
192 	return status;
193 }
194 
195 
196 
197 /*
198  * umask builtin
199  *
200  * This code was ripped from pdksh 5.2.14 and hacked for use with
201  * dash by Herbert Xu.
202  *
203  * Public domain.
204  */
205 
206 int
umaskcmd(int argc,char ** argv)207 umaskcmd(int argc, char **argv)
208 {
209 	char *ap;
210 	int mask;
211 	int i;
212 	int symbolic_mode = 0;
213 
214 	while ((i = nextopt("S")) != '\0') {
215 		symbolic_mode = 1;
216 	}
217 
218 	INTOFF;
219 	mask = umask(0);
220 	umask(mask);
221 	INTON;
222 
223 	if ((ap = *argptr) == NULL) {
224 		if (symbolic_mode) {
225 			char buf[18];
226 			int j;
227 
228 			mask = ~mask;
229 			ap = buf;
230 			for (i = 0; i < 3; i++) {
231 				*ap++ = "ugo"[i];
232 				*ap++ = '=';
233 				for (j = 0; j < 3; j++)
234 					if (mask & (1 << (8 - (3*i + j))))
235 						*ap++ = "rwx"[j];
236 				*ap++ = ',';
237 			}
238 			ap[-1] = '\0';
239 			out1fmt("%s\n", buf);
240 		} else {
241 			out1fmt("%.4o\n", mask);
242 		}
243 	} else {
244 		int new_mask;
245 
246 		if (isdigit((unsigned char) *ap)) {
247 			new_mask = 0;
248 			do {
249 				if (*ap >= '8' || *ap < '0')
250 					sh_error(illnum, *argptr);
251 				new_mask = (new_mask << 3) + (*ap - '0');
252 			} while (*++ap != '\0');
253 		} else {
254 			int positions, new_val;
255 			char op;
256 
257 			mask = ~mask;
258 			new_mask = mask;
259 			positions = 0;
260 			while (*ap) {
261 				while (*ap && strchr("augo", *ap))
262 					switch (*ap++) {
263 					case 'a': positions |= 0111; break;
264 					case 'u': positions |= 0100; break;
265 					case 'g': positions |= 0010; break;
266 					case 'o': positions |= 0001; break;
267 					}
268 				if (!positions)
269 					positions = 0111; /* default is a */
270 				if (!strchr("=+-", op = *ap))
271 					break;
272 				ap++;
273 				new_val = 0;
274 				while (*ap && strchr("rwxugoXs", *ap))
275 					switch (*ap++) {
276 					case 'r': new_val |= 04; break;
277 					case 'w': new_val |= 02; break;
278 					case 'x': new_val |= 01; break;
279 					case 'u': new_val |= mask >> 6;
280 						  break;
281 					case 'g': new_val |= mask >> 3;
282 						  break;
283 					case 'o': new_val |= mask >> 0;
284 						  break;
285 					case 'X': if (mask & 0111)
286 							new_val |= 01;
287 						  break;
288 					case 's': /* ignored */
289 						  break;
290 					}
291 				new_val = (new_val & 07) * positions;
292 				switch (op) {
293 				case '-':
294 					new_mask &= ~new_val;
295 					break;
296 				case '=':
297 					new_mask = new_val
298 					    | (new_mask & ~(positions * 07));
299 					break;
300 				case '+':
301 					new_mask |= new_val;
302 				}
303 				if (*ap == ',') {
304 					positions = 0;
305 					ap++;
306 				} else if (!strchr("=+-", *ap))
307 					break;
308 			}
309 			if (*ap) {
310 				sh_error("Illegal mode: %s", *argptr);
311 				return 1;
312 			}
313 			new_mask = ~new_mask;
314 		}
315 		umask(new_mask);
316 	}
317 	return 0;
318 }
319 
320 #ifdef HAVE_GETRLIMIT
321 /*
322  * ulimit builtin
323  *
324  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
325  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
326  * ash by J.T. Conklin.
327  *
328  * Public domain.
329  */
330 
331 struct limits {
332 	const char *name;
333 	int	cmd;
334 	int	factor;	/* multiply by to get rlim_{cur,max} values */
335 	char	option;
336 };
337 
338 static const struct limits limits[] = {
339 #ifdef RLIMIT_CPU
340 	{ "time(seconds)",		RLIMIT_CPU,	   1, 't' },
341 #endif
342 #ifdef RLIMIT_FSIZE
343 	{ "file(blocks)",		RLIMIT_FSIZE,	 512, 'f' },
344 #endif
345 #ifdef RLIMIT_DATA
346 	{ "data(kbytes)",		RLIMIT_DATA,	1024, 'd' },
347 #endif
348 #ifdef RLIMIT_STACK
349 	{ "stack(kbytes)",		RLIMIT_STACK,	1024, 's' },
350 #endif
351 #ifdef RLIMIT_CORE
352 	{ "coredump(blocks)",		RLIMIT_CORE,	 512, 'c' },
353 #endif
354 #ifdef RLIMIT_RSS
355 	{ "memory(kbytes)",		RLIMIT_RSS,	1024, 'm' },
356 #endif
357 #ifdef RLIMIT_MEMLOCK
358 	{ "locked memory(kbytes)",	RLIMIT_MEMLOCK, 1024, 'l' },
359 #endif
360 #ifdef RLIMIT_NPROC
361 	{ "process",			RLIMIT_NPROC,      1, 'p' },
362 #endif
363 #ifdef RLIMIT_NOFILE
364 	{ "nofiles",			RLIMIT_NOFILE,     1, 'n' },
365 #endif
366 #ifdef RLIMIT_AS
367 	{ "vmemory(kbytes)",		RLIMIT_AS,	1024, 'v' },
368 #endif
369 #ifdef RLIMIT_LOCKS
370 	{ "locks",			RLIMIT_LOCKS,	   1, 'w' },
371 #endif
372 #ifdef RLIMIT_RTPRIO
373 	{ "rtprio",			RLIMIT_RTPRIO,	   1, 'r' },
374 #endif
375 	{ (char *) 0,			0,		   0,  '\0' }
376 };
377 
378 enum limtype { SOFT = 0x1, HARD = 0x2 };
379 
printlim(enum limtype how,const struct rlimit * limit,const struct limits * l)380 static void printlim(enum limtype how, const struct rlimit *limit,
381 		     const struct limits *l)
382 {
383 	rlim_t val;
384 
385 	val = limit->rlim_max;
386 	if (how & SOFT)
387 		val = limit->rlim_cur;
388 
389 	if (val == RLIM_INFINITY)
390 		out1fmt("unlimited\n");
391 	else {
392 		val /= l->factor;
393 		out1fmt("%" PRIdMAX "\n", (intmax_t) val);
394 	}
395 }
396 
397 int
ulimitcmd(int argc,char ** argv)398 ulimitcmd(int argc, char **argv)
399 {
400 	int	c;
401 	rlim_t val = 0;
402 	enum limtype how = SOFT | HARD;
403 	const struct limits	*l;
404 	int		set, all = 0;
405 	int		optc, what;
406 	struct rlimit	limit;
407 
408 	what = 'f';
409 	while ((optc = nextopt("HSa"
410 #ifdef RLIMIT_CPU
411 			       "t"
412 #endif
413 #ifdef RLIMIT_FSIZE
414 			       "f"
415 #endif
416 #ifdef RLIMIT_DATA
417 			       "d"
418 #endif
419 #ifdef RLIMIT_STACK
420 			       "s"
421 #endif
422 #ifdef RLIMIT_CORE
423 			       "c"
424 #endif
425 #ifdef RLIMIT_RSS
426 			       "m"
427 #endif
428 #ifdef RLIMIT_MEMLOCK
429 			       "l"
430 #endif
431 #ifdef RLIMIT_NPROC
432 			       "p"
433 #endif
434 #ifdef RLIMIT_NOFILE
435 			       "n"
436 #endif
437 #ifdef RLIMIT_AS
438 			       "v"
439 #endif
440 #ifdef RLIMIT_LOCKS
441 			       "w"
442 #endif
443 	)) != '\0')
444 		switch (optc) {
445 		case 'H':
446 			how = HARD;
447 			break;
448 		case 'S':
449 			how = SOFT;
450 			break;
451 		case 'a':
452 			all = 1;
453 			break;
454 		default:
455 			what = optc;
456 		}
457 
458 	for (l = limits; l->option != what; l++)
459 		;
460 
461 	set = *argptr ? 1 : 0;
462 	if (set) {
463 		char *p = *argptr;
464 
465 		if (all || argptr[1])
466 			sh_error("too many arguments");
467 		if (strcmp(p, "unlimited") == 0)
468 			val = RLIM_INFINITY;
469 		else {
470 			val = (rlim_t) 0;
471 
472 			while ((c = *p++) >= '0' && c <= '9')
473 			{
474 				val = (val * 10) + (long)(c - '0');
475 				if (val < (rlim_t) 0)
476 					break;
477 			}
478 			if (c)
479 				sh_error("bad number");
480 			val *= l->factor;
481 		}
482 	}
483 	if (all) {
484 		for (l = limits; l->name; l++) {
485 			getrlimit(l->cmd, &limit);
486 			out1fmt("%-20s ", l->name);
487 			printlim(how, &limit, l);
488 		}
489 		return 0;
490 	}
491 
492 	getrlimit(l->cmd, &limit);
493 	if (set) {
494 		if (how & HARD)
495 			limit.rlim_max = val;
496 		if (how & SOFT)
497 			limit.rlim_cur = val;
498 		if (setrlimit(l->cmd, &limit) < 0)
499 			sh_error("error setting limit (%s)", strerror(errno));
500 	} else {
501 		printlim(how, &limit, l);
502 	}
503 	return 0;
504 }
505 #endif
506