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