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 bf56f3d78..a9f8d8413 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -57,9 +57,10 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
57 const char *opt_u 57 const char *opt_u
58) 58)
59{ 59{
60 struct pollfd pfd[1];
61#define fd (pfd[0].fd) /* -u FD */
60 unsigned err; 62 unsigned err;
61 unsigned end_ms; /* -t TIMEOUT */ 63 unsigned end_ms; /* -t TIMEOUT */
62 int fd; /* -u FD */
63 int nchars; /* -n NUM */ 64 int nchars; /* -n NUM */
64 char **pp; 65 char **pp;
65 char *buffer; 66 char *buffer;
@@ -88,38 +89,43 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
88 return "invalid count"; 89 return "invalid count";
89 /* note: "-n 0": off (bash 3.2 does this too) */ 90 /* note: "-n 0": off (bash 3.2 does this too) */
90 } 91 }
92
91 end_ms = 0; 93 end_ms = 0;
92 if (opt_t) { 94 if (opt_t && !ENABLE_FEATURE_SH_READ_FRAC) {
93 end_ms = bb_strtou(opt_t, NULL, 10); 95 end_ms = bb_strtou(opt_t, NULL, 10);
94 if (errno || end_ms > UINT_MAX / 2048) 96 if (errno)
95 return "invalid timeout"; 97 return "invalid timeout";
98 if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */
99 end_ms = UINT_MAX / 2048;
96 end_ms *= 1000; 100 end_ms *= 1000;
97#if 0 /* even bash has no -t N.NNN support */ 101 }
98 ts.tv_sec = bb_strtou(opt_t, &p, 10); 102 if (opt_t && ENABLE_FEATURE_SH_READ_FRAC) {
99 ts.tv_usec = 0; 103 /* bash 4.3 (maybe earlier) supports -t N.NNNNNN */
100 /* EINVAL means number is ok, but not terminated by NUL */ 104 char *p;
101 if (*p == '.' && errno == EINVAL) { 105 /* Eat up to three fractional digits */
102 char *p2; 106 int frac_digits = 3 + 1;
103 if (*++p) { 107
104 int scale; 108 end_ms = bb_strtou(opt_t, &p, 10);
105 ts.tv_usec = bb_strtou(p, &p2, 10); 109 if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */
106 if (errno) 110 end_ms = UINT_MAX / 2048;
107 return "invalid timeout"; 111
108 scale = p2 - p; 112 if (errno) {
109 /* normalize to usec */ 113 /* EINVAL = number is ok, but not NUL terminated */
110 if (scale > 6) 114 if (errno != EINVAL || *p != '.')
115 return "invalid timeout";
116 /* Do not check the rest: bash allows "0.123456xyz" */
117 while (*++p && --frac_digits) {
118 end_ms *= 10;
119 end_ms += (*p - '0');
120 if ((unsigned char)(*p - '0') > 9)
111 return "invalid timeout"; 121 return "invalid timeout";
112 while (scale++ < 6)
113 ts.tv_usec *= 10;
114 } 122 }
115 } else if (ts.tv_sec < 0 || errno) {
116 return "invalid timeout";
117 } 123 }
118 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */ 124 while (--frac_digits > 0) {
119 return "invalid timeout"; 125 end_ms *= 10;
120 } 126 }
121#endif /* if 0 */
122 } 127 }
128
123 fd = STDIN_FILENO; 129 fd = STDIN_FILENO;
124 if (opt_u) { 130 if (opt_u) {
125 fd = bb_strtou(opt_u, NULL, 10); 131 fd = bb_strtou(opt_u, NULL, 10);
@@ -127,6 +133,19 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
127 return "invalid file descriptor"; 133 return "invalid file descriptor";
128 } 134 }
129 135
136 if (opt_t && end_ms == 0) {
137 /* "If timeout is 0, read returns immediately, without trying
138 * to read any data. The exit status is 0 if input is available
139 * on the specified file descriptor, non-zero otherwise."
140 * bash seems to ignore -p PROMPT for this use case.
141 */
142 int r;
143 pfd[0].events = POLLIN;
144 r = poll(pfd, 1, /*timeout:*/ 0);
145 /* Return 0 only if poll returns 1 ("one fd ready"), else return 1: */
146 return (const char *)(uintptr_t)(r <= 0);
147 }
148
130 if (opt_p && isatty(fd)) { 149 if (opt_p && isatty(fd)) {
131 fputs(opt_p, stderr); 150 fputs(opt_p, stderr);
132 fflush_all(); 151 fflush_all();
@@ -161,21 +180,24 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
161 retval = (const char *)(uintptr_t)0; 180 retval = (const char *)(uintptr_t)0;
162 startword = 1; 181 startword = 1;
163 backslash = 0; 182 backslash = 0;
164 if (end_ms) /* NB: end_ms stays nonzero: */ 183 if (opt_t)
165 end_ms = ((unsigned)monotonic_ms() + end_ms) | 1; 184 end_ms += (unsigned)monotonic_ms();
166 buffer = NULL; 185 buffer = NULL;
167 bufpos = 0; 186 bufpos = 0;
168 do { 187 do {
169 char c; 188 char c;
170 struct pollfd pfd[1];
171 int timeout; 189 int timeout;
172 190
173 if ((bufpos & 0xff) == 0) 191 if ((bufpos & 0xff) == 0)
174 buffer = xrealloc(buffer, bufpos + 0x101); 192 buffer = xrealloc(buffer, bufpos + 0x101);
175 193
176 timeout = -1; 194 timeout = -1;
177 if (end_ms) { 195 if (opt_t) {
178 timeout = end_ms - (unsigned)monotonic_ms(); 196 timeout = end_ms - (unsigned)monotonic_ms();
197 /* ^^^^^^^^^^^^^ all values are unsigned,
198 * wrapping math is used here, good even if
199 * 32-bit unix time wrapped (year 2038+).
200 */
179 if (timeout <= 0) { /* already late? */ 201 if (timeout <= 0) { /* already late? */
180 retval = (const char *)(uintptr_t)1; 202 retval = (const char *)(uintptr_t)1;
181 goto ret; 203 goto ret;
@@ -187,9 +209,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
187 * regardless of SA_RESTART-ness of that signal! 209 * regardless of SA_RESTART-ness of that signal!
188 */ 210 */
189 errno = 0; 211 errno = 0;
190 pfd[0].fd = fd;
191 pfd[0].events = POLLIN; 212 pfd[0].events = POLLIN;
192 if (poll(pfd, 1, timeout) != 1) { 213 if (poll(pfd, 1, timeout) <= 0) {
193 /* timed out, or EINTR */ 214 /* timed out, or EINTR */
194 err = errno; 215 err = errno;
195 retval = (const char *)(uintptr_t)1; 216 retval = (const char *)(uintptr_t)1;
@@ -272,6 +293,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
272 293
273 errno = err; 294 errno = err;
274 return retval; 295 return retval;
296#undef fd
275} 297}
276 298
277/* ulimit builtin */ 299/* ulimit builtin */