aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-02-20 22:23:24 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-02-20 22:23:24 +0000
commite376d454bb70ed41bbc3eb0358d37fa30c94358d (patch)
treeeb53c600dcde841a7617a19f819ae3e9cfe7fd84 /libbb
parentae86a338b89c1339588226cb2298e1785aaa7b90 (diff)
downloadbusybox-w32-e376d454bb70ed41bbc3eb0358d37fa30c94358d.tar.gz
busybox-w32-e376d454bb70ed41bbc3eb0358d37fa30c94358d.tar.bz2
busybox-w32-e376d454bb70ed41bbc3eb0358d37fa30c94358d.zip
libbb: introduce and use nonblock_safe_read(). Yay!
Our shells are immune from this nasty O_NONBLOCK now! function old new delta nonblock_safe_read - 78 +78 file_get 276 295 +19 generateMTFValues 428 435 +7 read_line_input 1776 1772 -4 preadbuffer 543 450 -93 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/2 up/down: 104/-97) Total: 7 bytes text data bss dec hex filename 615190 715 23924 639829 9c355 busybox_old 615168 715 23924 639807 9c33f busybox_unstripped
Diffstat (limited to 'libbb')
-rw-r--r--libbb/lineedit.c4
-rw-r--r--libbb/read.c56
2 files changed, 57 insertions, 3 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 529344f6c..9aab63702 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -1408,9 +1408,9 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t
1408 parse_and_put_prompt(prompt); 1408 parse_and_put_prompt(prompt);
1409 1409
1410 while (1) { 1410 while (1) {
1411 fflush(stdout); 1411 fflush(NULL);
1412 1412
1413 if (safe_read(STDIN_FILENO, &c, 1) < 1) { 1413 if (nonblock_safe_read(STDIN_FILENO, &c, 1) < 1) {
1414 /* if we can't read input then exit */ 1414 /* if we can't read input then exit */
1415 goto prepare_to_die; 1415 goto prepare_to_die;
1416 } 1416 }
diff --git a/libbb/read.c b/libbb/read.c
index 502d407c4..2cd86b81b 100644
--- a/libbb/read.c
+++ b/libbb/read.c
@@ -20,6 +20,58 @@ ssize_t safe_read(int fd, void *buf, size_t count)
20 return n; 20 return n;
21} 21}
22 22
23/* Suppose that you are a shell. You start child processes.
24 * They work and eventually exit. You want to get user input.
25 * You read stdin. But what happens if last child switched
26 * its stdin into O_NONBLOCK mode?
27 *
28 * *** SURPRISE! It will affect the parent too! ***
29 * *** BIG SURPRISE! It stays even after child exits! ***
30 *
31 * This is a design bug in UNIX API.
32 * fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
33 * will set nonblocking mode not only on _your_ stdin, but
34 * also on stdin of your parent, etc.
35 *
36 * In general,
37 * fd2 = dup(fd1);
38 * fcntl(fd2, F_SETFL, fcntl(fd2, F_GETFL, 0) | O_NONBLOCK);
39 * sets both fd1 and fd2 to O_NONBLOCK. This includes cases
40 * where duping is done implicitly by fork() etc.
41 *
42 * We need
43 * fcntl(fd2, F_SETFD, fcntl(fd2, F_GETFD, 0) | O_NONBLOCK);
44 * (note SETFD, not SETFL!) but such thing doesn't exist.
45 *
46 * Alternatively, we need nonblocking_read(fd, ...) which doesn't
47 * require O_NONBLOCK dance at all. Actually, it exists:
48 * n = recv(fd, buf, len, MSG_DONTWAIT);
49 * "MSG_DONTWAIT:
50 * Enables non-blocking operation; if the operation
51 * would block, EAGAIN is returned."
52 * but recv() works only for sockets!
53 *
54 * So far I don't see any good solution, I can only propose
55 * that affected readers should be careful and use this routine,
56 * which detects EAGAIN and uses poll() to wait on the fd.
57 * Thanksfully, poll() doesn't give rat's ass about O_NONBLOCK flag.
58 */
59ssize_t nonblock_safe_read(int fd, void *buf, size_t count)
60{
61 struct pollfd pfd[1];
62 ssize_t n;
63
64 while (1) {
65 n = safe_read(fd, buf, count);
66 if (n >= 0 || errno != EAGAIN)
67 return n;
68 /* fd is in O_NONBLOCK mode. Wait using poll and repeat */
69 pfd[0].fd = fd;
70 pfd[0].events = POLLIN;
71 safe_poll(pfd, 1, -1);
72 }
73}
74
23/* 75/*
24 * Read all of the supplied buffer from a file. 76 * Read all of the supplied buffer from a file.
25 * This does multiple reads as necessary. 77 * This does multiple reads as necessary.
@@ -93,6 +145,7 @@ char *reads(int fd, char *buffer, size_t size)
93 145
94// Read one line a-la fgets. Reads byte-by-byte. 146// Read one line a-la fgets. Reads byte-by-byte.
95// Useful when it is important to not read ahead. 147// Useful when it is important to not read ahead.
148// Bytes are appended to pfx (which must be malloced, or NULL).
96char *xmalloc_reads(int fd, char *buf) 149char *xmalloc_reads(int fd, char *buf)
97{ 150{
98 char *p; 151 char *p;
@@ -106,7 +159,8 @@ char *xmalloc_reads(int fd, char *buf)
106 p = buf + sz; 159 p = buf + sz;
107 sz += 128; 160 sz += 128;
108 } 161 }
109 if (safe_read(fd, p, 1) != 1) { /* EOF/error */ 162 /* nonblock_safe_read() because we are used by e.g. shells */
163 if (nonblock_safe_read(fd, p, 1) != 1) { /* EOF/error */
110 if (p == buf) { 164 if (p == buf) {
111 /* we read nothing [and buf was NULL initially] */ 165 /* we read nothing [and buf was NULL initially] */
112 free(buf); 166 free(buf);