hush: fix read builtin to not read ahead past eol and to not use
insane amounts of stack. Testsuite updated.
This commit is contained in:
parent
f5f75c5e82
commit
d67cef2425
@ -400,7 +400,11 @@ extern ssize_t safe_read(int fd, void *buf, size_t count);
|
||||
extern ssize_t full_read(int fd, void *buf, size_t count);
|
||||
extern void xread(int fd, void *buf, size_t count);
|
||||
extern unsigned char xread_char(int fd);
|
||||
// Read one line a-la fgets. Uses one read(), works only on seekable streams
|
||||
extern char *reads(int fd, char *buf, size_t count);
|
||||
// Read one line a-la fgets. Reads byte-by-byte.
|
||||
// Useful when it is important to not read ahead.
|
||||
extern char *xmalloc_reads(int fd, char *pfx);
|
||||
extern ssize_t read_close(int fd, void *buf, size_t count);
|
||||
extern ssize_t open_read_close(const char *filename, void *buf, size_t count);
|
||||
extern void *xmalloc_open_read_close(const char *filename, size_t *sizep);
|
||||
|
51
libbb/read.c
51
libbb/read.c
@ -38,10 +38,8 @@ ssize_t full_read(int fd, void *buf, size_t len)
|
||||
|
||||
if (cc < 0)
|
||||
return cc; /* read() returns -1 on failure. */
|
||||
|
||||
if (cc == 0)
|
||||
break;
|
||||
|
||||
buf = ((char *)buf) + cc;
|
||||
total += cc;
|
||||
len -= cc;
|
||||
@ -64,9 +62,7 @@ void xread(int fd, void *buf, size_t count)
|
||||
unsigned char xread_char(int fd)
|
||||
{
|
||||
char tmp;
|
||||
|
||||
xread(fd, &tmp, 1);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@ -95,6 +91,37 @@ char *reads(int fd, char *buffer, size_t size)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Read one line a-la fgets. Reads byte-by-byte.
|
||||
// Useful when it is important to not read ahead.
|
||||
char *xmalloc_reads(int fd, char *buf)
|
||||
{
|
||||
char *p;
|
||||
int sz = buf ? strlen(buf) : 0;
|
||||
|
||||
goto jump_in;
|
||||
while (1) {
|
||||
if (p - buf == sz) {
|
||||
jump_in:
|
||||
buf = xrealloc(buf, sz + 128);
|
||||
p = buf + sz;
|
||||
sz += 128;
|
||||
}
|
||||
if (safe_read(fd, p, 1) != 1) { /* EOF/error */
|
||||
if (p == buf) {
|
||||
/* we read nothing [and buf was NULL initially] */
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (*p == '\n')
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
*p++ = '\0';
|
||||
return xrealloc(buf, p - buf);
|
||||
}
|
||||
|
||||
ssize_t read_close(int fd, void *buf, size_t size)
|
||||
{
|
||||
int e;
|
||||
@ -113,18 +140,21 @@ ssize_t open_read_close(const char *filename, void *buf, size_t size)
|
||||
return read_close(fd, buf, size);
|
||||
}
|
||||
|
||||
// Read (potentially big) files in one go. File size is estimated by
|
||||
// lseek to end.
|
||||
void *xmalloc_open_read_close(const char *filename, size_t *sizep)
|
||||
{
|
||||
char *buf;
|
||||
size_t size = sizep ? *sizep : INT_MAX;
|
||||
int fd = xopen(filename, O_RDONLY);
|
||||
int fd;
|
||||
off_t len;
|
||||
|
||||
fd = xopen(filename, O_RDONLY);
|
||||
/* /proc/N/stat files report len 0 here */
|
||||
/* In order to make such files readable, we add small const */
|
||||
off_t len = xlseek(fd, 0, SEEK_END) + 256;
|
||||
len = xlseek(fd, 0, SEEK_END) | 0x3ff; /* + up to 1k */
|
||||
xlseek(fd, 0, SEEK_SET);
|
||||
|
||||
if (len > size)
|
||||
bb_error_msg_and_die("file '%s' is too big", filename);
|
||||
if (len < size)
|
||||
size = len;
|
||||
buf = xmalloc(size + 1);
|
||||
size = read_close(fd, buf, size);
|
||||
@ -132,6 +162,7 @@ void *xmalloc_open_read_close(const char *filename, size_t *sizep)
|
||||
bb_perror_msg_and_die("'%s'", filename);
|
||||
xrealloc(buf, size + 1);
|
||||
buf[size] = '\0';
|
||||
if (sizep) *sizep = size;
|
||||
if (sizep)
|
||||
*sizep = size;
|
||||
return buf;
|
||||
}
|
||||
|
@ -4262,6 +4262,7 @@ int insmod_ng_main(int argc, char **argv)
|
||||
{
|
||||
long ret;
|
||||
size_t len;
|
||||
int optlen;
|
||||
void *map;
|
||||
char *filename, *options;
|
||||
|
||||
@ -4270,12 +4271,12 @@ int insmod_ng_main(int argc, char **argv)
|
||||
bb_show_usage();
|
||||
|
||||
/* Rest is options */
|
||||
options = xstrdup("");
|
||||
options = xzalloc(1);
|
||||
optlen = 0;
|
||||
while (*++argv) {
|
||||
int optlen = strlen(options);
|
||||
options = xrealloc(options, optlen + 2 + strlen(*argv) + 2);
|
||||
/* Spaces handled by "" pairs, but no way of escaping quotes */
|
||||
sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv);
|
||||
optlen += sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -234,7 +234,7 @@ static void include_conf(struct dep_t **first, struct dep_t **current, char *buf
|
||||
{
|
||||
int continuation_line = 0;
|
||||
|
||||
// alias parsing is not 100% correct (no correct handling of continuation lines within an alias) !
|
||||
// alias parsing is not 100% correct (no correct handling of continuation lines within an alias)!
|
||||
|
||||
while (reads(fd, buffer, buflen)) {
|
||||
int l;
|
||||
|
@ -1,5 +1,8 @@
|
||||
Various bits of what is known about busybox shells, in no particular order.
|
||||
|
||||
2007-06-13
|
||||
hush: exec <"$1" doesn't do parameter subst
|
||||
|
||||
2007-05-24
|
||||
hush: environment-related memory leak plugged, with net code size
|
||||
decrease.
|
||||
|
@ -11567,8 +11567,8 @@ readcmd(int argc, char **argv)
|
||||
#endif
|
||||
#if ENABLE_ASH_READ_TIMEOUT
|
||||
if (ts.tv_sec || ts.tv_usec) {
|
||||
FD_ZERO (&set);
|
||||
FD_SET (0, &set);
|
||||
FD_ZERO(&set);
|
||||
FD_SET(0, &set);
|
||||
|
||||
i = select(FD_SETSIZE, &set, NULL, NULL, &ts);
|
||||
if (!i) {
|
||||
|
16
shell/hush.c
16
shell/hush.c
@ -942,21 +942,11 @@ static int builtin_pwd(char **argv ATTRIBUTE_UNUSED)
|
||||
/* built-in 'read VAR' handler */
|
||||
static int builtin_read(char **argv)
|
||||
{
|
||||
char string[BUFSIZ];
|
||||
char *p;
|
||||
char *string;
|
||||
const char *name = argv[1] ? argv[1] : "REPLY";
|
||||
int name_len = strlen(name);
|
||||
|
||||
if (name_len >= sizeof(string) - 2)
|
||||
return EXIT_FAILURE;
|
||||
strcpy(string, name);
|
||||
p = string + name_len;
|
||||
*p++ = '=';
|
||||
*p = '\0'; /* In case stdin has only EOF */
|
||||
/* read string. name_len+1 chars are already used by 'name=' */
|
||||
fgets(p, sizeof(string) - 1 - name_len, stdin);
|
||||
chomp(p);
|
||||
return set_local_var(xstrdup(string), 0);
|
||||
string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name));
|
||||
return set_local_var(string, 0);
|
||||
}
|
||||
|
||||
/* built-in 'set [VAR=value]' handler */
|
||||
|
4
shell/hush_test/hush-misc/read.right
Normal file
4
shell/hush_test/hush-misc/read.right
Normal file
@ -0,0 +1,4 @@
|
||||
read
|
||||
cat
|
||||
echo "REPLY=$REPLY"
|
||||
REPLY=exec <read.tests
|
4
shell/hush_test/hush-misc/read.tests
Executable file
4
shell/hush_test/hush-misc/read.tests
Executable file
@ -0,0 +1,4 @@
|
||||
exec <read.tests
|
||||
read
|
||||
cat
|
||||
echo "REPLY=$REPLY"
|
@ -99,7 +99,7 @@ int readprofile_main(int argc, char **argv)
|
||||
/*
|
||||
* Use an fd for the profiling buffer, to skip stdio overhead
|
||||
*/
|
||||
len = INT_MAX;
|
||||
len = MAXINT(ssize_t);
|
||||
buf = xmalloc_open_read_close(proFile, &len);
|
||||
if (!optNative) {
|
||||
int entries = len/sizeof(*buf);
|
||||
|
Loading…
Reference in New Issue
Block a user