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': not a valid identifier", *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 (c == '\0')
213 continue;
214 if (!(read_flags & BUILTIN_READ_RAW)) {
215 if (backslash) {
216 backslash = 0;
217 if (c != '\n')
218 goto put;
219 continue;
220 }
221 if (c == '\\') {
222 backslash = 1;
223 continue;
224 }
225 }
226 if (c == delim)
227 break;
228
229
230
231
232
233 if (!params->opt_d && 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 const char *name;
326};
327
328static const struct limits limits_tbl[] = {
329 { RLIMIT_CORE, 9, "core file size (blocks)" },
330 { RLIMIT_DATA, 10, "data seg size (kb)" },
331 { RLIMIT_NICE, 0, "scheduling priority" },
332 { RLIMIT_FSIZE, 9, "file size (blocks)" },
333#define LIMIT_F_IDX 3
334#ifdef RLIMIT_SIGPENDING
335 { RLIMIT_SIGPENDING, 0, "pending signals" },
336#endif
337#ifdef RLIMIT_MEMLOCK
338 { RLIMIT_MEMLOCK, 10, "max locked memory (kb)" },
339#endif
340#ifdef RLIMIT_RSS
341 { RLIMIT_RSS, 10, "max memory size (kb)" },
342#endif
343#ifdef RLIMIT_NOFILE
344 { RLIMIT_NOFILE, 0, "open files" },
345#endif
346#ifdef RLIMIT_MSGQUEUE
347 { RLIMIT_MSGQUEUE, 0, "POSIX message queues (bytes)" },
348#endif
349#ifdef RLIMIT_RTPRIO
350 { RLIMIT_RTPRIO, 0, "real-time priority" },
351#endif
352#ifdef RLIMIT_STACK
353 { RLIMIT_STACK, 10, "stack size (kb)" },
354#endif
355#ifdef RLIMIT_CPU
356 { RLIMIT_CPU, 0, "cpu time (seconds)" },
357#endif
358#ifdef RLIMIT_NPROC
359 { RLIMIT_NPROC, 0, "max user processes" },
360#endif
361#ifdef RLIMIT_AS
362 { RLIMIT_AS, 10, "virtual memory (kb)" },
363#endif
364#ifdef RLIMIT_LOCKS
365 { RLIMIT_LOCKS, 0, "file locks" },
366#endif
367};
368
369
370
371static const char limit_chars[] ALIGN1 =
372 "c"
373 "d"
374 "e"
375 "f"
376#ifdef RLIMIT_SIGPENDING
377 "i"
378#endif
379#ifdef RLIMIT_MEMLOCK
380 "l"
381#endif
382#ifdef RLIMIT_RSS
383 "m"
384#endif
385#ifdef RLIMIT_NOFILE
386 "n"
387#endif
388#ifdef RLIMIT_MSGQUEUE
389 "q"
390#endif
391#ifdef RLIMIT_RTPRIO
392 "r"
393#endif
394#ifdef RLIMIT_STACK
395 "s"
396#endif
397#ifdef RLIMIT_CPU
398 "t"
399#endif
400#ifdef RLIMIT_NPROC
401 "u"
402#endif
403#ifdef RLIMIT_AS
404 "v"
405#endif
406#ifdef RLIMIT_LOCKS
407 "x"
408#endif
409;
410
411
412static const char ulimit_opt_string[] ALIGN1 = "-HSa"
413 "c::"
414 "d::"
415 "e::"
416 "f::"
417#ifdef RLIMIT_SIGPENDING
418 "i::"
419#endif
420#ifdef RLIMIT_MEMLOCK
421 "l::"
422#endif
423#ifdef RLIMIT_RSS
424 "m::"
425#endif
426#ifdef RLIMIT_NOFILE
427 "n::"
428#endif
429#ifdef RLIMIT_MSGQUEUE
430 "q::"
431#endif
432#ifdef RLIMIT_RTPRIO
433 "r::"
434#endif
435#ifdef RLIMIT_STACK
436 "s::"
437#endif
438#ifdef RLIMIT_CPU
439 "t::"
440#endif
441#ifdef RLIMIT_NPROC
442 "u::"
443#endif
444#ifdef RLIMIT_AS
445 "v::"
446#endif
447#ifdef RLIMIT_LOCKS
448 "x::"
449#endif
450;
451
452enum {
453 OPT_hard = (1 << 0),
454 OPT_soft = (1 << 1),
455 OPT_all = (1 << 2),
456};
457
458static void printlim(unsigned opts, const struct rlimit *limit,
459 const struct limits *l)
460{
461 rlim_t val;
462
463 val = limit->rlim_max;
464 if (opts & OPT_soft)
465 val = limit->rlim_cur;
466
467 if (val == RLIM_INFINITY)
468 puts("unlimited");
469 else {
470 val >>= l->factor_shift;
471 printf("%llu\n", (long long) val);
472 }
473}
474
475int FAST_FUNC
476shell_builtin_ulimit(char **argv)
477{
478 struct rlimit limit;
479 unsigned opt_cnt;
480 unsigned opts;
481 unsigned argc;
482 unsigned i;
483
484
485
486
487
488
489
490
491 GETOPT_RESET();
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526 argc = string_array_len(argv);
527
528
529
530
531
532 opt_cnt = 0;
533 opts = 0;
534 while (1) {
535 int opt_char = getopt(argc, argv, ulimit_opt_string);
536
537 if (opt_char == -1)
538 break;
539 if (opt_char == 'H') {
540 opts |= OPT_hard;
541 continue;
542 }
543 if (opt_char == 'S') {
544 opts |= OPT_soft;
545 continue;
546 }
547 if (opt_char == 'a') {
548 opts |= OPT_all;
549 continue;
550 }
551 if (opt_char == '?') {
552
553 return EXIT_FAILURE;
554 }
555 opt_cnt++;
556 }
557
558 if (!(opts & (OPT_hard | OPT_soft)))
559 opts |= (OPT_hard | OPT_soft);
560 if (opts & OPT_all) {
561 for (i = 0; i < ARRAY_SIZE(limits_tbl); i++) {
562 getrlimit(limits_tbl[i].cmd, &limit);
563 printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]);
564 printlim(opts, &limit, &limits_tbl[i]);
565 }
566 return EXIT_SUCCESS;
567 }
568
569
570 GETOPT_RESET();
571 while (1) {
572 char *val_str;
573 int opt_char = getopt(argc, argv, ulimit_opt_string);
574
575 if (opt_char == -1)
576 break;
577 if (opt_char == 'H')
578 continue;
579 if (opt_char == 'S')
580 continue;
581
582
583 if (opt_char == 1)
584 opt_char = 'f';
585 i = strchrnul(limit_chars, opt_char) - limit_chars;
586
587
588 val_str = optarg;
589 if (!val_str && argv[optind] && argv[optind][0] != '-')
590 val_str = argv[optind++];
591
592 getrlimit(limits_tbl[i].cmd, &limit);
593 if (!val_str) {
594 if (opt_cnt > 1)
595 printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]);
596 printlim(opts, &limit, &limits_tbl[i]);
597 } else {
598 rlim_t val = RLIM_INFINITY;
599 if (strcmp(val_str, "unlimited") != 0) {
600 if (sizeof(val) == sizeof(int))
601 val = bb_strtou(val_str, NULL, 10);
602 else if (sizeof(val) == sizeof(long))
603 val = bb_strtoul(val_str, NULL, 10);
604 else
605 val = bb_strtoull(val_str, NULL, 10);
606 if (errno) {
607 bb_error_msg("invalid number '%s'", val_str);
608 return EXIT_FAILURE;
609 }
610 val <<= limits_tbl[i].factor_shift;
611 }
612
613
614
615
616 if (opts & OPT_hard)
617 limit.rlim_max = val;
618 if (opts & OPT_soft)
619 limit.rlim_cur = val;
620
621 if (setrlimit(limits_tbl[i].cmd, &limit) < 0) {
622 bb_perror_msg("error setting limit");
623 return EXIT_FAILURE;
624 }
625 }
626 }
627
628 if (opt_cnt == 0) {
629
630 getrlimit(limits_tbl[LIMIT_F_IDX].cmd, &limit);
631 printlim(opts, &limit, &limits_tbl[LIMIT_F_IDX]);
632 }
633
634 return EXIT_SUCCESS;
635}
636