aboutsummaryrefslogtreecommitdiff
path: root/shell/shell_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/shell_common.c')
-rw-r--r--shell/shell_common.c82
1 files changed, 52 insertions, 30 deletions
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 154b860f8..750adc5d8 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -61,9 +61,10 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
61 const char *opt_u 61 const char *opt_u
62) 62)
63{ 63{
64 struct pollfd pfd[1];
65#define fd (pfd[0].fd) /* -u FD */
64 unsigned err; 66 unsigned err;
65 unsigned end_ms; /* -t TIMEOUT */ 67 unsigned end_ms; /* -t TIMEOUT */
66 int fd; /* -u FD */
67 int nchars; /* -n NUM */ 68 int nchars; /* -n NUM */
68 char **pp; 69 char **pp;
69 char *buffer; 70 char *buffer;
@@ -92,38 +93,43 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
92 return "invalid count"; 93 return "invalid count";
93 /* note: "-n 0": off (bash 3.2 does this too) */ 94 /* note: "-n 0": off (bash 3.2 does this too) */
94 } 95 }
96
95 end_ms = 0; 97 end_ms = 0;
96 if (opt_t) { 98 if (opt_t && !ENABLE_FEATURE_SH_READ_FRAC) {
97 end_ms = bb_strtou(opt_t, NULL, 10); 99 end_ms = bb_strtou(opt_t, NULL, 10);
98 if (errno || end_ms > UINT_MAX / 2048) 100 if (errno)
99 return "invalid timeout"; 101 return "invalid timeout";
102 if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */
103 end_ms = UINT_MAX / 2048;
100 end_ms *= 1000; 104 end_ms *= 1000;
101#if 0 /* even bash has no -t N.NNN support */ 105 }
102 ts.tv_sec = bb_strtou(opt_t, &p, 10); 106 if (opt_t && ENABLE_FEATURE_SH_READ_FRAC) {
103 ts.tv_usec = 0; 107 /* bash 4.3 (maybe earlier) supports -t N.NNNNNN */
104 /* EINVAL means number is ok, but not terminated by NUL */ 108 char *p;
105 if (*p == '.' && errno == EINVAL) { 109 /* Eat up to three fractional digits */
106 char *p2; 110 int frac_digits = 3 + 1;
107 if (*++p) { 111
108 int scale; 112 end_ms = bb_strtou(opt_t, &p, 10);
109 ts.tv_usec = bb_strtou(p, &p2, 10); 113 if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */
110 if (errno) 114 end_ms = UINT_MAX / 2048;
111 return "invalid timeout"; 115
112 scale = p2 - p; 116 if (errno) {
113 /* normalize to usec */ 117 /* EINVAL = number is ok, but not NUL terminated */
114 if (scale > 6) 118 if (errno != EINVAL || *p != '.')
119 return "invalid timeout";
120 /* Do not check the rest: bash allows "0.123456xyz" */
121 while (*++p && --frac_digits) {
122 end_ms *= 10;
123 end_ms += (*p - '0');
124 if ((unsigned char)(*p - '0') > 9)
115 return "invalid timeout"; 125 return "invalid timeout";
116 while (scale++ < 6)
117 ts.tv_usec *= 10;
118 } 126 }
119 } else if (ts.tv_sec < 0 || errno) {
120 return "invalid timeout";
121 } 127 }
122 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */ 128 while (--frac_digits > 0) {
123 return "invalid timeout"; 129 end_ms *= 10;
124 } 130 }
125#endif /* if 0 */
126 } 131 }
132
127 fd = STDIN_FILENO; 133 fd = STDIN_FILENO;
128 if (opt_u) { 134 if (opt_u) {
129 fd = bb_strtou(opt_u, NULL, 10); 135 fd = bb_strtou(opt_u, NULL, 10);
@@ -131,6 +137,19 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
131 return "invalid file descriptor"; 137 return "invalid file descriptor";
132 } 138 }
133 139
140 if (opt_t && end_ms == 0) {
141 /* "If timeout is 0, read returns immediately, without trying
142 * to read any data. The exit status is 0 if input is available
143 * on the specified file descriptor, non-zero otherwise."
144 * bash seems to ignore -p PROMPT for this use case.
145 */
146 int r;
147 pfd[0].events = POLLIN;
148 r = poll(pfd, 1, /*timeout:*/ 0);
149 /* Return 0 only if poll returns 1 ("one fd ready"), else return 1: */
150 return (const char *)(uintptr_t)(r <= 0);
151 }
152
134 if (opt_p && isatty(fd)) { 153 if (opt_p && isatty(fd)) {
135 fputs(opt_p, stderr); 154 fputs(opt_p, stderr);
136 fflush_all(); 155 fflush_all();
@@ -165,21 +184,24 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
165 retval = (const char *)(uintptr_t)0; 184 retval = (const char *)(uintptr_t)0;
166 startword = 1; 185 startword = 1;
167 backslash = 0; 186 backslash = 0;
168 if (end_ms) /* NB: end_ms stays nonzero: */ 187 if (opt_t)
169 end_ms = ((unsigned)monotonic_ms() + end_ms) | 1; 188 end_ms += (unsigned)monotonic_ms();
170 buffer = NULL; 189 buffer = NULL;
171 bufpos = 0; 190 bufpos = 0;
172 do { 191 do {
173 char c; 192 char c;
174 struct pollfd pfd[1];
175 int timeout; 193 int timeout;
176 194
177 if ((bufpos & 0xff) == 0) 195 if ((bufpos & 0xff) == 0)
178 buffer = xrealloc(buffer, bufpos + 0x101); 196 buffer = xrealloc(buffer, bufpos + 0x101);
179 197
180 timeout = -1; 198 timeout = -1;
181 if (end_ms) { 199 if (opt_t) {
182 timeout = end_ms - (unsigned)monotonic_ms(); 200 timeout = end_ms - (unsigned)monotonic_ms();
201 /* ^^^^^^^^^^^^^ all values are unsigned,
202 * wrapping math is used here, good even if
203 * 32-bit unix time wrapped (year 2038+).
204 */
183 if (timeout <= 0) { /* already late? */ 205 if (timeout <= 0) { /* already late? */
184 retval = (const char *)(uintptr_t)1; 206 retval = (const char *)(uintptr_t)1;
185 goto ret; 207 goto ret;
@@ -192,9 +214,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
192 */ 214 */
193 errno = 0; 215 errno = 0;
194#if !ENABLE_PLATFORM_MINGW32 216#if !ENABLE_PLATFORM_MINGW32
195 pfd[0].fd = fd;
196 pfd[0].events = POLLIN; 217 pfd[0].events = POLLIN;
197 if (poll(pfd, 1, timeout) != 1) { 218 if (poll(pfd, 1, timeout) <= 0) {
198 /* timed out, or EINTR */ 219 /* timed out, or EINTR */
199 err = errno; 220 err = errno;
200 retval = (const char *)(uintptr_t)1; 221 retval = (const char *)(uintptr_t)1;
@@ -278,6 +299,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
278 299
279 errno = err; 300 errno = err;
280 return retval; 301 return retval;
302#undef fd
281} 303}
282 304
283/* ulimit builtin */ 305/* ulimit builtin */