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); |
