aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--include/libbb.h2
-rw-r--r--libbb/lineedit.c4
-rw-r--r--libbb/read.c56
-rw-r--r--shell/ash.c11
-rw-r--r--shell/hush.c8
-rw-r--r--shell/msh.c9
6 files changed, 75 insertions, 15 deletions
diff --git a/include/libbb.h b/include/libbb.h
index a91eac466..eb8b2f620 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -475,6 +475,7 @@ extern void *xzalloc(size_t size);
475extern void *xrealloc(void *old, size_t size); 475extern void *xrealloc(void *old, size_t size);
476 476
477extern ssize_t safe_read(int fd, void *buf, size_t count); 477extern ssize_t safe_read(int fd, void *buf, size_t count);
478extern ssize_t nonblock_safe_read(int fd, void *buf, size_t count);
478extern ssize_t full_read(int fd, void *buf, size_t count); 479extern ssize_t full_read(int fd, void *buf, size_t count);
479extern void xread(int fd, void *buf, size_t count); 480extern void xread(int fd, void *buf, size_t count);
480extern unsigned char xread_char(int fd); 481extern unsigned char xread_char(int fd);
@@ -482,6 +483,7 @@ extern unsigned char xread_char(int fd);
482extern char *reads(int fd, char *buf, size_t count); 483extern char *reads(int fd, char *buf, size_t count);
483// Read one line a-la fgets. Reads byte-by-byte. 484// Read one line a-la fgets. Reads byte-by-byte.
484// Useful when it is important to not read ahead. 485// Useful when it is important to not read ahead.
486// Bytes are appended to pfx (which must be malloced, or NULL).
485extern char *xmalloc_reads(int fd, char *pfx); 487extern char *xmalloc_reads(int fd, char *pfx);
486extern ssize_t read_close(int fd, void *buf, size_t count); 488extern ssize_t read_close(int fd, void *buf, size_t count);
487extern ssize_t open_read_close(const char *filename, void *buf, size_t count); 489extern ssize_t open_read_close(const char *filename, void *buf, size_t count);
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);
diff --git a/shell/ash.c b/shell/ash.c
index 65f94f682..debe8ecdd 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5428,7 +5428,7 @@ expbackq(union node *cmd, int quoted, int quotes)
5428 read: 5428 read:
5429 if (in.fd < 0) 5429 if (in.fd < 0)
5430 break; 5430 break;
5431 i = safe_read(in.fd, buf, sizeof(buf)); 5431 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5432 TRACE(("expbackq: read returns %d\n", i)); 5432 TRACE(("expbackq: read returns %d\n", i));
5433 if (i <= 0) 5433 if (i <= 0)
5434 break; 5434 break;
@@ -8678,7 +8678,7 @@ preadfd(void)
8678 retry: 8678 retry:
8679#if ENABLE_FEATURE_EDITING 8679#if ENABLE_FEATURE_EDITING
8680 if (!iflag || parsefile->fd) 8680 if (!iflag || parsefile->fd)
8681 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 8681 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8682 else { 8682 else {
8683#if ENABLE_FEATURE_TAB_COMPLETION 8683#if ENABLE_FEATURE_TAB_COMPLETION
8684 line_input_state->path_lookup = pathval(); 8684 line_input_state->path_lookup = pathval();
@@ -8700,9 +8700,11 @@ preadfd(void)
8700 } 8700 }
8701 } 8701 }
8702#else 8702#else
8703 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 8703 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8704#endif 8704#endif
8705 8705
8706#if 0
8707/* nonblock_safe_read() handles this problem */
8706 if (nr < 0) { 8708 if (nr < 0) {
8707 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 8709 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
8708 int flags = fcntl(0, F_GETFL); 8710 int flags = fcntl(0, F_GETFL);
@@ -8715,6 +8717,7 @@ preadfd(void)
8715 } 8717 }
8716 } 8718 }
8717 } 8719 }
8720#endif
8718 return nr; 8721 return nr;
8719} 8722}
8720 8723
@@ -11801,7 +11804,7 @@ readcmd(int argc, char **argv)
11801 backslash = 0; 11804 backslash = 0;
11802 STARTSTACKSTR(p); 11805 STARTSTACKSTR(p);
11803 do { 11806 do {
11804 if (read(0, &c, 1) != 1) { 11807 if (nonblock_safe_read(0, &c, 1) != 1) {
11805 status = 1; 11808 status = 1;
11806 break; 11809 break;
11807 } 11810 }
diff --git a/shell/hush.c b/shell/hush.c
index 4d4843173..820fd888d 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1273,10 +1273,10 @@ static void get_user_input(struct in_str *i)
1273 prompt_str = setup_prompt_string(i->promptmode); 1273 prompt_str = setup_prompt_string(i->promptmode);
1274#if ENABLE_FEATURE_EDITING 1274#if ENABLE_FEATURE_EDITING
1275 /* Enable command line editing only while a command line 1275 /* Enable command line editing only while a command line
1276 * is actually being read; otherwise, we'll end up bequeathing 1276 * is actually being read */
1277 * atexit() handlers and other unwanted stuff to our 1277 do {
1278 * child processes (rob@sysgo.de) */ 1278 r = read_line_input(prompt_str, user_input_buf, BUFSIZ-1, line_input_state);
1279 r = read_line_input(prompt_str, user_input_buf, BUFSIZ-1, line_input_state); 1279 } while (r == 0); /* repeat if Ctrl-C */
1280 i->eof_flag = (r < 0); 1280 i->eof_flag = (r < 0);
1281 if (i->eof_flag) { /* EOF/error detected */ 1281 if (i->eof_flag) { /* EOF/error detected */
1282 user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */ 1282 user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */
diff --git a/shell/msh.c b/shell/msh.c
index fd287f16e..917b08a1e 100644
--- a/shell/msh.c
+++ b/shell/msh.c
@@ -42,6 +42,7 @@
42# define xmalloc(size) malloc(size) 42# define xmalloc(size) malloc(size)
43# define msh_main(argc,argv) main(argc,argv) 43# define msh_main(argc,argv) main(argc,argv)
44# define safe_read(fd,buf,count) read(fd,buf,count) 44# define safe_read(fd,buf,count) read(fd,buf,count)
45# define nonblock_safe_read(fd,buf,count) read(fd,buf,count)
45# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1]) 46# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
46# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1]) 47# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
47# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) 48# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
@@ -3376,7 +3377,7 @@ static int doread(struct op *t)
3376 } 3377 }
3377 for (wp = t->words + 1; *wp; wp++) { 3378 for (wp = t->words + 1; *wp; wp++) {
3378 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) { 3379 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
3379 nb = read(0, cp, sizeof(*cp)); 3380 nb = nonblock_safe_read(0, cp, sizeof(*cp));
3380 if (nb != sizeof(*cp)) 3381 if (nb != sizeof(*cp))
3381 break; 3382 break;
3382 nl = (*cp == '\n'); 3383 nl = (*cp == '\n');
@@ -4799,7 +4800,7 @@ static int filechar(struct ioarg *ap)
4799 if (i) 4800 if (i)
4800 lseek(ap->afile, ap->afpos, SEEK_SET); 4801 lseek(ap->afile, ap->afpos, SEEK_SET);
4801 4802
4802 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf)); 4803 i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4803 if (i <= 0) { 4804 if (i <= 0) {
4804 closef(ap->afile); 4805 closef(ap->afile);
4805 return 0; 4806 return 0;
@@ -4830,7 +4831,7 @@ static int filechar(struct ioarg *ap)
4830 return c; 4831 return c;
4831 } 4832 }
4832#endif 4833#endif
4833 i = safe_read(ap->afile, &c, sizeof(c)); 4834 i = nonblock_safe_read(ap->afile, &c, sizeof(c));
4834 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0); 4835 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
4835} 4836}
4836 4837
@@ -4841,7 +4842,7 @@ static int herechar(struct ioarg *ap)
4841{ 4842{
4842 char c; 4843 char c;
4843 4844
4844 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) { 4845 if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4845 close(ap->afile); 4846 close(ap->afile);
4846 c = '\0'; 4847 c = '\0';
4847 } 4848 }