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