1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include "libbb.h"
20#include "shell_common.h"
21
22const char defifsvar[] ALIGN1 = "IFS= \t\n";
23const char defoptindvar[] ALIGN1 = "OPTIND=1";
24
25
26
27
28
29
30
31
32
33
34
35const char* FAST_FUNC
36shell_builtin_read(struct builtin_read_params *params)
37{
38 struct pollfd pfd[1];
39#define fd (pfd[0].fd)
40 unsigned err;
41 unsigned end_ms;
42 int nchars;
43 char **pp;
44 char *buffer;
45 char delim;
46 struct termios tty, old_tty;
47 const char *retval;
48 int bufpos;
49 int startword;
50 smallint backslash;
51 char **argv;
52 const char *ifs;
53 int read_flags;
54
55 errno = err = 0;
56
57 argv = params->argv;
58 pp = argv;
59 while (*pp) {
60 if (endofname(*pp)[0] != '\0') {
61
62 bb_error_msg("read: '%s': bad variable name", *pp);
63 return (const char *)(uintptr_t)1;
64 }
65 pp++;
66 }
67
68 nchars = 0;
69 if (params->opt_n) {
70 nchars = bb_strtou(params->opt_n, NULL, 10);
71 if (nchars < 0 || errno)
72 return "invalid count";
73
74 }
75
76 end_ms = 0;
77 if (params->opt_t && !ENABLE_FEATURE_SH_READ_FRAC) {
78 end_ms = bb_strtou(params->opt_t, NULL, 10);
79 if (errno)
80 return "invalid timeout";
81 if (end_ms > UINT_MAX / 2048)
82 end_ms = UINT_MAX / 2048;
83 end_ms *= 1000;
84 }
85 if (params->opt_t && ENABLE_FEATURE_SH_READ_FRAC) {
86
87 char *p;
88
89 int frac_digits = 3 + 1;
90
91 end_ms = bb_strtou(params->opt_t, &p, 10);
92 if (end_ms > UINT_MAX / 2048)
93 end_ms = UINT_MAX / 2048;
94
95 if (errno) {
96
97 if (errno != EINVAL || *p != '.')
98 return "invalid timeout";
99
100 while (*++p && --frac_digits) {
101 end_ms *= 10;
102 end_ms += (*p - '0');
103 if ((unsigned char)(*p - '0') > 9)
104 return "invalid timeout";
105 }
106 }
107 while (--frac_digits > 0) {
108 end_ms *= 10;
109 }
110 }
111
112 fd = STDIN_FILENO;
113 if (params->opt_u) {
114 fd = bb_strtou(params->opt_u, NULL, 10);
115 if (fd < 0 || errno)
116 return "invalid file descriptor";
117 }
118
119 if (params->opt_t && end_ms == 0) {
120
121
122
123
124
125 int r;
126 pfd[0].events = POLLIN;
127 r = poll(pfd, 1, 0);
128
129 return (const char *)(uintptr_t)(r <= 0);
130 }
131
132 if (params->opt_p && isatty(fd)) {
133 fputs(params->opt_p, stderr);
134 fflush_all();
135 }
136
137 ifs = params->ifs;
138 if (ifs == NULL)
139 ifs = defifs;
140
141 read_flags = params->read_flags;
142 if (nchars || (read_flags & BUILTIN_READ_SILENT)) {
143 tcgetattr(fd, &tty);
144 old_tty = tty;
145 if (nchars) {
146 tty.c_lflag &= ~ICANON;
147
148
149
150
151 tty.c_cc[VMIN] = 1;
152
153 tty.c_cc[VTIME] = 0;
154 }
155 if (read_flags & BUILTIN_READ_SILENT) {
156 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
157 }
158
159 read_flags |= BUILTIN_READ_SILENT;
160
161
162 tcsetattr(fd, TCSANOW, &tty);
163 }
164
165 retval = (const char *)(uintptr_t)0;
166 startword = 1;
167 backslash = 0;
168 if (params->opt_t)
169 end_ms += (unsigned)monotonic_ms();
170 buffer = NULL;
171 bufpos = 0;
172 delim = params->opt_d ? params->opt_d[0] : '\n';
173 do {
174 char c;
175 int timeout;
176
177 if ((bufpos & 0xff) == 0)
178 buffer = xrealloc(buffer, bufpos + 0x101);
179
180 timeout = -1;
181 if (params->opt_t) {
182 timeout = end_ms - (unsigned)monotonic_ms();
183
184
185
186
187 if (timeout <= 0) {
188 retval = (const char *)(uintptr_t)1;
189 goto ret;
190 }
191 }
192
193
194
195
196
197 errno = 0;
198 pfd[0].events = POLLIN;
199 if (poll(pfd, 1, timeout) <= 0) {
200
201 err = errno;
202 retval = (const char *)(uintptr_t)1;
203 goto ret;
204 }
205 if (read(fd, &buffer[bufpos], 1) != 1) {
206 err = errno;
207 retval = (const char *)(uintptr_t)1;
208 break;
209 }
210
211 c = buffer[bufpos];
212 if (!(read_flags & BUILTIN_READ_RAW)) {
213 if (backslash) {
214 backslash = 0;
215 if (c != '\n')
216 goto put;
217 continue;
218 }
219 if (c == '\\') {
220 backslash = 1;
221 continue;
222 }
223 }
224 if (c == delim)
225 break;
226 if (c == '\0')
227 continue;
228
229
230
231
232
233 if (argv[0]) {
234
235 const char *is_ifs = strchr(ifs, c);
236 if (startword && is_ifs) {
237 if (isspace(c))
238 continue;
239
240 startword--;
241 if (startword == 1)
242 continue;
243 }
244 startword = 0;
245 if (argv[1] != NULL && is_ifs) {
246 buffer[bufpos] = '\0';
247 bufpos = 0;
248 params->setvar(*argv, buffer);
249 argv++;
250
251 startword = isspace(c) ? 2 : 1;
252 continue;
253 }
254 }
255 put:
256 bufpos++;
257 } while (--nchars);
258
259 if (argv[0]) {
260
261 while (--bufpos >= 0
262 && isspace(buffer[bufpos])
263 && strchr(ifs, buffer[bufpos]) != NULL
264 ) {
265 continue;
266 }
267 buffer[bufpos + 1] = '\0';
268
269
270
271
272
273
274
275
276
277
278
279
280 if (bufpos >= 0
281 && strchr(ifs, buffer[bufpos]) != NULL
282 ) {
283
284
285 while (--bufpos >= 0
286 && isspace(buffer[bufpos])
287 && strchr(ifs, buffer[bufpos]) != NULL
288 ) {
289 continue;
290 }
291
292 if (strcspn(buffer, ifs) >= ++bufpos) {
293
294
295 buffer[bufpos] = '\0';
296 }
297 }
298
299
300 params->setvar(*argv, buffer);
301
302 while (*++argv)
303 params->setvar(*argv, "");
304 } else {
305
306 buffer[bufpos] = '\0';
307 params->setvar("REPLY", buffer);
308 }
309
310 ret:
311 free(buffer);
312 if (read_flags & BUILTIN_READ_SILENT)
313 tcsetattr(fd, TCSANOW, &old_tty);
314
315 errno = err;
316 return retval;
317#undef fd
318}
319
320
321
322struct limits {
323 uint8_t cmd;
324 uint8_t factor_shift;
325};
326
327
328static const struct limits limits_tbl[] ALIGN2 = {
329 { RLIMIT_CORE, 9, },
330 { RLIMIT_DATA, 10, },
331#ifdef RLIMIT_NICE
332 { RLIMIT_NICE, 0, },
333#define LIMIT_F_IDX 3
334#else
335
336#define LIMIT_F_IDX 2
337#endif
338 { RLIMIT_FSIZE, 9, },
339#ifdef RLIMIT_SIGPENDING
340 { RLIMIT_SIGPENDING, 0, },
341#endif
342#ifdef RLIMIT_MEMLOCK
343 { RLIMIT_MEMLOCK, 10, },
344#endif
345#ifdef RLIMIT_RSS
346 { RLIMIT_RSS, 10, },
347#endif
348#ifdef RLIMIT_NOFILE
349 { RLIMIT_NOFILE, 0, },
350#endif
351#ifdef RLIMIT_MSGQUEUE
352 { RLIMIT_MSGQUEUE, 0, },
353#endif
354#ifdef RLIMIT_RTPRIO
355 { RLIMIT_RTPRIO, 0, },
356#endif
357#ifdef RLIMIT_STACK
358 { RLIMIT_STACK, 10, },
359#endif
360#ifdef RLIMIT_CPU
361 { RLIMIT_CPU, 0, },
362#endif
363#ifdef RLIMIT_NPROC
364 { RLIMIT_NPROC, 0, },
365#endif
366#ifdef RLIMIT_AS
367 { RLIMIT_AS, 10, },
368#endif
369#ifdef RLIMIT_LOCKS
370 { RLIMIT_LOCKS, 0, },
371#endif
372};
373
374
375
376
377static const char limits_help[] ALIGN1 =
378 "core file size (blocks)"
379 "\0""data seg size (kb)"
380#ifdef RLIMIT_NICE
381 "\0""scheduling priority"
382#endif
383 "\0""file size (blocks)"
384#ifdef RLIMIT_SIGPENDING
385 "\0""pending signals"
386#endif
387#ifdef RLIMIT_MEMLOCK
388 "\0""max locked memory (kb)"
389#endif
390#ifdef RLIMIT_RSS
391 "\0""max memory size (kb)"
392#endif
393#ifdef RLIMIT_NOFILE
394 "\0""open files"
395#endif
396#ifdef RLIMIT_MSGQUEUE
397 "\0""POSIX message queues (bytes)"
398#endif
399#ifdef RLIMIT_RTPRIO
400 "\0""real-time priority"
401#endif
402#ifdef RLIMIT_STACK
403 "\0""stack size (kb)"
404#endif
405#ifdef RLIMIT_CPU
406 "\0""cpu time (seconds)"
407#endif
408#ifdef RLIMIT_NPROC
409 "\0""max user processes"
410#endif
411#ifdef RLIMIT_AS
412 "\0""virtual memory (kb)"
413#endif
414#ifdef RLIMIT_LOCKS
415 "\0""file locks"
416#endif
417;
418
419static const char limit_chars[] ALIGN1 =
420 "c"
421 "d"
422#ifdef RLIMIT_NICE
423 "e"
424#endif
425 "f"
426#ifdef RLIMIT_SIGPENDING
427 "i"
428#endif
429#ifdef RLIMIT_MEMLOCK
430 "l"
431#endif
432#ifdef RLIMIT_RSS
433 "m"
434#endif
435#ifdef RLIMIT_NOFILE
436 "n"
437#endif
438#ifdef RLIMIT_MSGQUEUE
439 "q"
440#endif
441#ifdef RLIMIT_RTPRIO
442 "r"
443#endif
444#ifdef RLIMIT_STACK
445 "s"
446#endif
447#ifdef RLIMIT_CPU
448 "t"
449#endif
450#ifdef RLIMIT_NPROC
451 "u"
452#endif
453#ifdef RLIMIT_AS
454 "v"
455#endif
456#ifdef RLIMIT_LOCKS
457 "x"
458#endif
459;
460
461
462static const char ulimit_opt_string[] ALIGN1 = "-HSa"
463 "c::"
464 "d::"
465#ifdef RLIMIT_NICE
466 "e::"
467#endif
468 "f::"
469#ifdef RLIMIT_SIGPENDING
470 "i::"
471#endif
472#ifdef RLIMIT_MEMLOCK
473 "l::"
474#endif
475#ifdef RLIMIT_RSS
476 "m::"
477#endif
478#ifdef RLIMIT_NOFILE
479 "n::"
480#endif
481#ifdef RLIMIT_MSGQUEUE
482 "q::"
483#endif
484#ifdef RLIMIT_RTPRIO
485 "r::"
486#endif
487#ifdef RLIMIT_STACK
488 "s::"
489#endif
490#ifdef RLIMIT_CPU
491 "t::"
492#endif
493#ifdef RLIMIT_NPROC
494 "u::"
495#endif
496#ifdef RLIMIT_AS
497 "v::"
498#endif
499#ifdef RLIMIT_LOCKS
500 "x::"
501#endif
502;
503
504enum {
505 OPT_hard = (1 << 0),
506 OPT_soft = (1 << 1),
507 OPT_all = (1 << 2),
508};
509
510static void printlim(unsigned opts, const struct rlimit *limit,
511 const struct limits *l)
512{
513 rlim_t val;
514
515 val = limit->rlim_max;
516 if (opts & OPT_soft)
517 val = limit->rlim_cur;
518
519 if (val == RLIM_INFINITY)
520 puts("unlimited");
521 else {
522 val >>= l->factor_shift;
523 printf("%llu\n", (long long) val);
524 }
525}
526
527int FAST_FUNC
528shell_builtin_ulimit(char **argv)
529{
530 struct rlimit limit;
531 unsigned opt_cnt;
532 unsigned opts;
533 unsigned argc;
534 unsigned i;
535
536
537
538
539
540
541
542
543 GETOPT_RESET();
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578 argc = string_array_len(argv);
579
580
581
582
583
584 opt_cnt = 0;
585 opts = 0;
586 while (1) {
587 int opt_char = getopt(argc, argv, ulimit_opt_string);
588
589 if (opt_char == -1)
590 break;
591 if (opt_char == 'H') {
592 opts |= OPT_hard;
593 continue;
594 }
595 if (opt_char == 'S') {
596 opts |= OPT_soft;
597 continue;
598 }
599 if (opt_char == 'a') {
600 opts |= OPT_all;
601 continue;
602 }
603 if (opt_char == '?') {
604
605 return EXIT_FAILURE;
606 }
607 opt_cnt++;
608 }
609
610 if (!(opts & (OPT_hard | OPT_soft)))
611 opts |= (OPT_hard | OPT_soft);
612 if (opts & OPT_all) {
613 const char *help = limits_help;
614 for (i = 0; i < ARRAY_SIZE(limits_tbl); i++) {
615 getrlimit(limits_tbl[i].cmd, &limit);
616 printf("%-32s(-%c) ", help, limit_chars[i]);
617 printlim(opts, &limit, &limits_tbl[i]);
618 help += strlen(help) + 1;
619 }
620 return EXIT_SUCCESS;
621 }
622
623
624 GETOPT_RESET();
625 while (1) {
626 char *val_str;
627 int opt_char = getopt(argc, argv, ulimit_opt_string);
628
629 if (opt_char == -1)
630 break;
631 if (opt_char == 'H')
632 continue;
633 if (opt_char == 'S')
634 continue;
635
636
637 if (opt_char == 1)
638 opt_char = 'f';
639 i = strchrnul(limit_chars, opt_char) - limit_chars;
640
641
642 val_str = optarg;
643 if (!val_str && argv[optind] && argv[optind][0] != '-')
644 val_str = argv[optind++];
645
646 getrlimit(limits_tbl[i].cmd, &limit);
647 if (!val_str) {
648 if (opt_cnt > 1)
649 printf("%-32s(-%c) ", nth_string(limits_help, i), limit_chars[i]);
650 printlim(opts, &limit, &limits_tbl[i]);
651 } else {
652 rlim_t val = RLIM_INFINITY;
653 if (strcmp(val_str, "unlimited") != 0) {
654 if (sizeof(val) == sizeof(int))
655 val = bb_strtou(val_str, NULL, 10);
656 else if (sizeof(val) == sizeof(long))
657 val = bb_strtoul(val_str, NULL, 10);
658 else
659 val = bb_strtoull(val_str, NULL, 10);
660 if (errno) {
661 bb_error_msg("invalid number '%s'", val_str);
662 return EXIT_FAILURE;
663 }
664 val <<= limits_tbl[i].factor_shift;
665 }
666
667
668
669
670 if (opts & OPT_hard)
671 limit.rlim_max = val;
672 if (opts & OPT_soft)
673 limit.rlim_cur = val;
674
675 if (setrlimit(limits_tbl[i].cmd, &limit) < 0) {
676 bb_simple_perror_msg("error setting limit");
677 return EXIT_FAILURE;
678 }
679 }
680 }
681
682 if (opt_cnt == 0) {
683
684 getrlimit(RLIMIT_FSIZE, &limit);
685 printlim(opts, &limit, &limits_tbl[LIMIT_F_IDX]);
686 }
687
688 return EXIT_SUCCESS;
689}
690