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 ssize_t full_read(int fd, void *buf, size_t count);
|
||||||
extern void xread(int fd, void *buf, size_t count);
|
extern void xread(int fd, void *buf, size_t count);
|
||||||
extern unsigned char xread_char(int fd);
|
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);
|
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 read_close(int fd, void *buf, size_t count);
|
||||||
extern ssize_t open_read_close(const char *filename, 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);
|
extern void *xmalloc_open_read_close(const char *filename, size_t *sizep);
|
||||||
|
53
libbb/read.c
53
libbb/read.c
@ -38,10 +38,8 @@ ssize_t full_read(int fd, void *buf, size_t len)
|
|||||||
|
|
||||||
if (cc < 0)
|
if (cc < 0)
|
||||||
return cc; /* read() returns -1 on failure. */
|
return cc; /* read() returns -1 on failure. */
|
||||||
|
|
||||||
if (cc == 0)
|
if (cc == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
buf = ((char *)buf) + cc;
|
buf = ((char *)buf) + cc;
|
||||||
total += cc;
|
total += cc;
|
||||||
len -= cc;
|
len -= cc;
|
||||||
@ -64,9 +62,7 @@ void xread(int fd, void *buf, size_t count)
|
|||||||
unsigned char xread_char(int fd)
|
unsigned char xread_char(int fd)
|
||||||
{
|
{
|
||||||
char tmp;
|
char tmp;
|
||||||
|
|
||||||
xread(fd, &tmp, 1);
|
xread(fd, &tmp, 1);
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +91,37 @@ char *reads(int fd, char *buffer, size_t size)
|
|||||||
return buffer;
|
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)
|
ssize_t read_close(int fd, void *buf, size_t size)
|
||||||
{
|
{
|
||||||
int e;
|
int e;
|
||||||
@ -113,25 +140,29 @@ ssize_t open_read_close(const char *filename, void *buf, size_t size)
|
|||||||
return read_close(fd, buf, 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)
|
void *xmalloc_open_read_close(const char *filename, size_t *sizep)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t size = sizep ? *sizep : INT_MAX;
|
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 */
|
/* /proc/N/stat files report len 0 here */
|
||||||
/* In order to make such files readable, we add small const */
|
/* 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);
|
xlseek(fd, 0, SEEK_SET);
|
||||||
|
if (len < size)
|
||||||
if (len > size)
|
size = len;
|
||||||
bb_error_msg_and_die("file '%s' is too big", filename);
|
|
||||||
size = len;
|
|
||||||
buf = xmalloc(size + 1);
|
buf = xmalloc(size + 1);
|
||||||
size = read_close(fd, buf, size);
|
size = read_close(fd, buf, size);
|
||||||
if ((ssize_t)size < 0)
|
if ((ssize_t)size < 0)
|
||||||
bb_perror_msg_and_die("'%s'", filename);
|
bb_perror_msg_and_die("'%s'", filename);
|
||||||
xrealloc(buf, size + 1);
|
xrealloc(buf, size + 1);
|
||||||
buf[size] = '\0';
|
buf[size] = '\0';
|
||||||
if (sizep) *sizep = size;
|
if (sizep)
|
||||||
|
*sizep = size;
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
@ -4262,6 +4262,7 @@ int insmod_ng_main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
int optlen;
|
||||||
void *map;
|
void *map;
|
||||||
char *filename, *options;
|
char *filename, *options;
|
||||||
|
|
||||||
@ -4270,12 +4271,12 @@ int insmod_ng_main(int argc, char **argv)
|
|||||||
bb_show_usage();
|
bb_show_usage();
|
||||||
|
|
||||||
/* Rest is options */
|
/* Rest is options */
|
||||||
options = xstrdup("");
|
options = xzalloc(1);
|
||||||
|
optlen = 0;
|
||||||
while (*++argv) {
|
while (*++argv) {
|
||||||
int optlen = strlen(options);
|
|
||||||
options = xrealloc(options, optlen + 2 + strlen(*argv) + 2);
|
options = xrealloc(options, optlen + 2 + strlen(*argv) + 2);
|
||||||
/* Spaces handled by "" pairs, but no way of escaping quotes */
|
/* 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
|
#if 0
|
||||||
|
@ -234,7 +234,7 @@ static void include_conf(struct dep_t **first, struct dep_t **current, char *buf
|
|||||||
{
|
{
|
||||||
int continuation_line = 0;
|
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)) {
|
while (reads(fd, buffer, buflen)) {
|
||||||
int l;
|
int l;
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
Various bits of what is known about busybox shells, in no particular order.
|
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
|
2007-05-24
|
||||||
hush: environment-related memory leak plugged, with net code size
|
hush: environment-related memory leak plugged, with net code size
|
||||||
decrease.
|
decrease.
|
||||||
|
@ -11567,8 +11567,8 @@ readcmd(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
#if ENABLE_ASH_READ_TIMEOUT
|
#if ENABLE_ASH_READ_TIMEOUT
|
||||||
if (ts.tv_sec || ts.tv_usec) {
|
if (ts.tv_sec || ts.tv_usec) {
|
||||||
FD_ZERO (&set);
|
FD_ZERO(&set);
|
||||||
FD_SET (0, &set);
|
FD_SET(0, &set);
|
||||||
|
|
||||||
i = select(FD_SETSIZE, &set, NULL, NULL, &ts);
|
i = select(FD_SETSIZE, &set, NULL, NULL, &ts);
|
||||||
if (!i) {
|
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 */
|
/* built-in 'read VAR' handler */
|
||||||
static int builtin_read(char **argv)
|
static int builtin_read(char **argv)
|
||||||
{
|
{
|
||||||
char string[BUFSIZ];
|
char *string;
|
||||||
char *p;
|
|
||||||
const char *name = argv[1] ? argv[1] : "REPLY";
|
const char *name = argv[1] ? argv[1] : "REPLY";
|
||||||
int name_len = strlen(name);
|
|
||||||
|
|
||||||
if (name_len >= sizeof(string) - 2)
|
string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name));
|
||||||
return EXIT_FAILURE;
|
return set_local_var(string, 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* built-in 'set [VAR=value]' handler */
|
/* 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
|
* 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);
|
buf = xmalloc_open_read_close(proFile, &len);
|
||||||
if (!optNative) {
|
if (!optNative) {
|
||||||
int entries = len/sizeof(*buf);
|
int entries = len/sizeof(*buf);
|
||||||
|
Loading…
Reference in New Issue
Block a user