Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/dash/miscbltin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1122 - (show 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)
-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