Annotation of /trunk/mkinitrd-magellan/klibc/usr/dash/miscbltin.c
Parent Directory | Revision Log
Revision 1122 -
(hide annotations)
(download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 8 months ago) by niro
File MIME type: text/plain
File size: 11644 byte(s)
Wed Aug 18 21:11:40 2010 UTC (13 years, 8 months ago) by niro
File MIME type: text/plain
File size: 11644 byte(s)
-updated to klibc-1.5.19
1 | niro | 532 | /*- |
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 | niro | 1122 | #include "expand.h" |
60 | #include "parser.h" | ||
61 | niro | 532 | |
62 | #undef rflag | ||
63 | |||
64 | |||
65 | niro | 1122 | /** 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 | niro | 532 | |
80 | niro | 1122 | /* 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 | niro | 532 | /* |
123 | * The read builtin. The -e option causes backslashes to escape the | ||
124 | niro | 1122 | * following character. The -p option followed by an argument prompts |
125 | * with the argument. | ||
126 | niro | 532 | * |
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 | niro | 1122 | if (c == '\n') |
224 | goto resetbs; | ||
225 | STPUTC(CTLESC, p); | ||
226 | goto put; | ||
227 | niro | 532 | } |
228 | if (!rflag && c == '\\') { | ||
229 | backslash++; | ||
230 | continue; | ||
231 | } | ||
232 | if (c == '\n') | ||
233 | break; | ||
234 | put: | ||
235 | niro | 1122 | STPUTC(c, p); |
236 | resetbs: | ||
237 | backslash = 0; | ||
238 | niro | 532 | } |
239 | STACKSTRNUL(p); | ||
240 | niro | 1122 | readcmd_handle_line(stackblock(), ap, p + 1 - (char *)stackblock()); |
241 | niro | 532 | 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 | niro | 1122 | if (isdigit((unsigned char) *ap)) { |
296 | niro | 532 | 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 |