diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-06-13 06:47:47 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-06-13 06:47:47 +0000 |
commit | d67cef2425fb5e75b75d52d9a308da6d29cd7a0d (patch) | |
tree | 5d034f518dfae9a933a701e8c42da4acbf0cb42d | |
parent | f5f75c5e82d47613847c356664e47c4be69e73aa (diff) | |
download | busybox-w32-d67cef2425fb5e75b75d52d9a308da6d29cd7a0d.tar.gz busybox-w32-d67cef2425fb5e75b75d52d9a308da6d29cd7a0d.tar.bz2 busybox-w32-d67cef2425fb5e75b75d52d9a308da6d29cd7a0d.zip |
hush: fix read builtin to not read ahead past eol and to not use
insane amounts of stack. Testsuite updated.
-rw-r--r-- | include/libbb.h | 4 | ||||
-rw-r--r-- | libbb/read.c | 53 | ||||
-rw-r--r-- | modutils/insmod.c | 7 | ||||
-rw-r--r-- | modutils/modprobe.c | 2 | ||||
-rw-r--r-- | shell/README | 3 | ||||
-rw-r--r-- | shell/ash.c | 4 | ||||
-rw-r--r-- | shell/hush.c | 16 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/read.right | 4 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/read.tests | 4 | ||||
-rw-r--r-- | util-linux/readprofile.c | 2 |
10 files changed, 68 insertions, 31 deletions
diff --git a/include/libbb.h b/include/libbb.h index ce62f4529..5aa95ea88 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -400,7 +400,11 @@ extern ssize_t safe_read(int fd, void *buf, size_t count); | |||
400 | extern ssize_t full_read(int fd, void *buf, size_t count); | 400 | extern ssize_t full_read(int fd, void *buf, size_t count); |
401 | extern void xread(int fd, void *buf, size_t count); | 401 | extern void xread(int fd, void *buf, size_t count); |
402 | extern unsigned char xread_char(int fd); | 402 | extern unsigned char xread_char(int fd); |
403 | // Read one line a-la fgets. Uses one read(), works only on seekable streams | ||
403 | extern char *reads(int fd, char *buf, size_t count); | 404 | extern char *reads(int fd, char *buf, size_t count); |
405 | // Read one line a-la fgets. Reads byte-by-byte. | ||
406 | // Useful when it is important to not read ahead. | ||
407 | extern char *xmalloc_reads(int fd, char *pfx); | ||
404 | extern ssize_t read_close(int fd, void *buf, size_t count); | 408 | extern ssize_t read_close(int fd, void *buf, size_t count); |
405 | extern ssize_t open_read_close(const char *filename, void *buf, size_t count); | 409 | extern ssize_t open_read_close(const char *filename, void *buf, size_t count); |
406 | extern void *xmalloc_open_read_close(const char *filename, size_t *sizep); | 410 | extern void *xmalloc_open_read_close(const char *filename, size_t *sizep); |
diff --git a/libbb/read.c b/libbb/read.c index c05b26b50..05bf754e0 100644 --- a/libbb/read.c +++ b/libbb/read.c | |||
@@ -38,10 +38,8 @@ ssize_t full_read(int fd, void *buf, size_t len) | |||
38 | 38 | ||
39 | if (cc < 0) | 39 | if (cc < 0) |
40 | return cc; /* read() returns -1 on failure. */ | 40 | return cc; /* read() returns -1 on failure. */ |
41 | |||
42 | if (cc == 0) | 41 | if (cc == 0) |
43 | break; | 42 | break; |
44 | |||
45 | buf = ((char *)buf) + cc; | 43 | buf = ((char *)buf) + cc; |
46 | total += cc; | 44 | total += cc; |
47 | len -= cc; | 45 | len -= cc; |
@@ -64,9 +62,7 @@ void xread(int fd, void *buf, size_t count) | |||
64 | unsigned char xread_char(int fd) | 62 | unsigned char xread_char(int fd) |
65 | { | 63 | { |
66 | char tmp; | 64 | char tmp; |
67 | |||
68 | xread(fd, &tmp, 1); | 65 | xread(fd, &tmp, 1); |
69 | |||
70 | return tmp; | 66 | return tmp; |
71 | } | 67 | } |
72 | 68 | ||
@@ -95,6 +91,37 @@ char *reads(int fd, char *buffer, size_t size) | |||
95 | return buffer; | 91 | return buffer; |
96 | } | 92 | } |
97 | 93 | ||
94 | // Read one line a-la fgets. Reads byte-by-byte. | ||
95 | // Useful when it is important to not read ahead. | ||
96 | char *xmalloc_reads(int fd, char *buf) | ||
97 | { | ||
98 | char *p; | ||
99 | int sz = buf ? strlen(buf) : 0; | ||
100 | |||
101 | goto jump_in; | ||
102 | while (1) { | ||
103 | if (p - buf == sz) { | ||
104 | jump_in: | ||
105 | buf = xrealloc(buf, sz + 128); | ||
106 | p = buf + sz; | ||
107 | sz += 128; | ||
108 | } | ||
109 | if (safe_read(fd, p, 1) != 1) { /* EOF/error */ | ||
110 | if (p == buf) { | ||
111 | /* we read nothing [and buf was NULL initially] */ | ||
112 | free(buf); | ||
113 | return NULL; | ||
114 | } | ||
115 | break; | ||
116 | } | ||
117 | if (*p == '\n') | ||
118 | break; | ||
119 | p++; | ||
120 | } | ||
121 | *p++ = '\0'; | ||
122 | return xrealloc(buf, p - buf); | ||
123 | } | ||
124 | |||
98 | ssize_t read_close(int fd, void *buf, size_t size) | 125 | ssize_t read_close(int fd, void *buf, size_t size) |
99 | { | 126 | { |
100 | int e; | 127 | int e; |
@@ -113,25 +140,29 @@ ssize_t open_read_close(const char *filename, void *buf, size_t size) | |||
113 | return read_close(fd, buf, size); | 140 | return read_close(fd, buf, size); |
114 | } | 141 | } |
115 | 142 | ||
143 | // Read (potentially big) files in one go. File size is estimated by | ||
144 | // lseek to end. | ||
116 | void *xmalloc_open_read_close(const char *filename, size_t *sizep) | 145 | void *xmalloc_open_read_close(const char *filename, size_t *sizep) |
117 | { | 146 | { |
118 | char *buf; | 147 | char *buf; |
119 | size_t size = sizep ? *sizep : INT_MAX; | 148 | size_t size = sizep ? *sizep : INT_MAX; |
120 | int fd = xopen(filename, O_RDONLY); | 149 | int fd; |
150 | off_t len; | ||
151 | |||
152 | fd = xopen(filename, O_RDONLY); | ||
121 | /* /proc/N/stat files report len 0 here */ | 153 | /* /proc/N/stat files report len 0 here */ |
122 | /* In order to make such files readable, we add small const */ | 154 | /* In order to make such files readable, we add small const */ |
123 | off_t len = xlseek(fd, 0, SEEK_END) + 256; | 155 | len = xlseek(fd, 0, SEEK_END) | 0x3ff; /* + up to 1k */ |
124 | xlseek(fd, 0, SEEK_SET); | 156 | xlseek(fd, 0, SEEK_SET); |
125 | 157 | if (len < size) | |
126 | if (len > size) | 158 | size = len; |
127 | bb_error_msg_and_die("file '%s' is too big", filename); | ||
128 | size = len; | ||
129 | buf = xmalloc(size + 1); | 159 | buf = xmalloc(size + 1); |
130 | size = read_close(fd, buf, size); | 160 | size = read_close(fd, buf, size); |
131 | if ((ssize_t)size < 0) | 161 | if ((ssize_t)size < 0) |
132 | bb_perror_msg_and_die("'%s'", filename); | 162 | bb_perror_msg_and_die("'%s'", filename); |
133 | xrealloc(buf, size + 1); | 163 | xrealloc(buf, size + 1); |
134 | buf[size] = '\0'; | 164 | buf[size] = '\0'; |
135 | if (sizep) *sizep = size; | 165 | if (sizep) |
166 | *sizep = size; | ||
136 | return buf; | 167 | return buf; |
137 | } | 168 | } |
diff --git a/modutils/insmod.c b/modutils/insmod.c index a81ca7fba..b9d8a0243 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c | |||
@@ -4262,6 +4262,7 @@ int insmod_ng_main(int argc, char **argv) | |||
4262 | { | 4262 | { |
4263 | long ret; | 4263 | long ret; |
4264 | size_t len; | 4264 | size_t len; |
4265 | int optlen; | ||
4265 | void *map; | 4266 | void *map; |
4266 | char *filename, *options; | 4267 | char *filename, *options; |
4267 | 4268 | ||
@@ -4270,12 +4271,12 @@ int insmod_ng_main(int argc, char **argv) | |||
4270 | bb_show_usage(); | 4271 | bb_show_usage(); |
4271 | 4272 | ||
4272 | /* Rest is options */ | 4273 | /* Rest is options */ |
4273 | options = xstrdup(""); | 4274 | options = xzalloc(1); |
4275 | optlen = 0; | ||
4274 | while (*++argv) { | 4276 | while (*++argv) { |
4275 | int optlen = strlen(options); | ||
4276 | options = xrealloc(options, optlen + 2 + strlen(*argv) + 2); | 4277 | options = xrealloc(options, optlen + 2 + strlen(*argv) + 2); |
4277 | /* Spaces handled by "" pairs, but no way of escaping quotes */ | 4278 | /* Spaces handled by "" pairs, but no way of escaping quotes */ |
4278 | sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv); | 4279 | optlen += sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv); |
4279 | } | 4280 | } |
4280 | 4281 | ||
4281 | #if 0 | 4282 | #if 0 |
diff --git a/modutils/modprobe.c b/modutils/modprobe.c index a7c6307f8..dbed4ea0f 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c | |||
@@ -234,7 +234,7 @@ static void include_conf(struct dep_t **first, struct dep_t **current, char *buf | |||
234 | { | 234 | { |
235 | int continuation_line = 0; | 235 | int continuation_line = 0; |
236 | 236 | ||
237 | // alias parsing is not 100% correct (no correct handling of continuation lines within an alias) ! | 237 | // alias parsing is not 100% correct (no correct handling of continuation lines within an alias)! |
238 | 238 | ||
239 | while (reads(fd, buffer, buflen)) { | 239 | while (reads(fd, buffer, buflen)) { |
240 | int l; | 240 | int l; |
diff --git a/shell/README b/shell/README index a09353d6c..b86f96cf4 100644 --- a/shell/README +++ b/shell/README | |||
@@ -1,5 +1,8 @@ | |||
1 | Various bits of what is known about busybox shells, in no particular order. | 1 | Various bits of what is known about busybox shells, in no particular order. |
2 | 2 | ||
3 | 2007-06-13 | ||
4 | hush: exec <"$1" doesn't do parameter subst | ||
5 | |||
3 | 2007-05-24 | 6 | 2007-05-24 |
4 | hush: environment-related memory leak plugged, with net code size | 7 | hush: environment-related memory leak plugged, with net code size |
5 | decrease. | 8 | decrease. |
diff --git a/shell/ash.c b/shell/ash.c index ae078e609..173beb195 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -11567,8 +11567,8 @@ readcmd(int argc, char **argv) | |||
11567 | #endif | 11567 | #endif |
11568 | #if ENABLE_ASH_READ_TIMEOUT | 11568 | #if ENABLE_ASH_READ_TIMEOUT |
11569 | if (ts.tv_sec || ts.tv_usec) { | 11569 | if (ts.tv_sec || ts.tv_usec) { |
11570 | FD_ZERO (&set); | 11570 | FD_ZERO(&set); |
11571 | FD_SET (0, &set); | 11571 | FD_SET(0, &set); |
11572 | 11572 | ||
11573 | i = select(FD_SETSIZE, &set, NULL, NULL, &ts); | 11573 | i = select(FD_SETSIZE, &set, NULL, NULL, &ts); |
11574 | if (!i) { | 11574 | if (!i) { |
diff --git a/shell/hush.c b/shell/hush.c index 40bcafdd9..e6fa3d9a5 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -942,21 +942,11 @@ static int builtin_pwd(char **argv ATTRIBUTE_UNUSED) | |||
942 | /* built-in 'read VAR' handler */ | 942 | /* built-in 'read VAR' handler */ |
943 | static int builtin_read(char **argv) | 943 | static int builtin_read(char **argv) |
944 | { | 944 | { |
945 | char string[BUFSIZ]; | 945 | char *string; |
946 | char *p; | ||
947 | const char *name = argv[1] ? argv[1] : "REPLY"; | 946 | const char *name = argv[1] ? argv[1] : "REPLY"; |
948 | int name_len = strlen(name); | ||
949 | 947 | ||
950 | if (name_len >= sizeof(string) - 2) | 948 | string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name)); |
951 | return EXIT_FAILURE; | 949 | return set_local_var(string, 0); |
952 | strcpy(string, name); | ||
953 | p = string + name_len; | ||
954 | *p++ = '='; | ||
955 | *p = '\0'; /* In case stdin has only EOF */ | ||
956 | /* read string. name_len+1 chars are already used by 'name=' */ | ||
957 | fgets(p, sizeof(string) - 1 - name_len, stdin); | ||
958 | chomp(p); | ||
959 | return set_local_var(xstrdup(string), 0); | ||
960 | } | 950 | } |
961 | 951 | ||
962 | /* built-in 'set [VAR=value]' handler */ | 952 | /* built-in 'set [VAR=value]' handler */ |
diff --git a/shell/hush_test/hush-misc/read.right b/shell/hush_test/hush-misc/read.right new file mode 100644 index 000000000..0e50e2a23 --- /dev/null +++ b/shell/hush_test/hush-misc/read.right | |||
@@ -0,0 +1,4 @@ | |||
1 | read | ||
2 | cat | ||
3 | echo "REPLY=$REPLY" | ||
4 | REPLY=exec <read.tests | ||
diff --git a/shell/hush_test/hush-misc/read.tests b/shell/hush_test/hush-misc/read.tests new file mode 100755 index 000000000..ff1acbde1 --- /dev/null +++ b/shell/hush_test/hush-misc/read.tests | |||
@@ -0,0 +1,4 @@ | |||
1 | exec <read.tests | ||
2 | read | ||
3 | cat | ||
4 | echo "REPLY=$REPLY" | ||
diff --git a/util-linux/readprofile.c b/util-linux/readprofile.c index f2bd3bbae..02afedcf0 100644 --- a/util-linux/readprofile.c +++ b/util-linux/readprofile.c | |||
@@ -99,7 +99,7 @@ int readprofile_main(int argc, char **argv) | |||
99 | /* | 99 | /* |
100 | * Use an fd for the profiling buffer, to skip stdio overhead | 100 | * Use an fd for the profiling buffer, to skip stdio overhead |
101 | */ | 101 | */ |
102 | len = INT_MAX; | 102 | len = MAXINT(ssize_t); |
103 | buf = xmalloc_open_read_close(proFile, &len); | 103 | buf = xmalloc_open_read_close(proFile, &len); |
104 | if (!optNative) { | 104 | if (!optNative) { |
105 | int entries = len/sizeof(*buf); | 105 | int entries = len/sizeof(*buf); |