diff options
author | Michael Brown <mcb30@ipxe.org> | 2021-03-03 02:24:32 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2021-03-03 02:26:42 +0000 |
commit | 65bd5c05db2a050a4c0f26ccc0b1e9828b00abbf (patch) | |
tree | 8b304e947b9960418ea95007de99ff157931f22b | |
parent | 1c4917b6a739c887acbf6f7631b1f74084430ee7 (diff) | |
download | ipxe-65bd5c05db2a050a4c0f26ccc0b1e9828b00abbf.tar.gz |
[linux] Do not assume that stat() works on sysfs files
Linux kernel 3.12 and earlier report a zero size via stat() for all
ACPI table files in sysfs. There is no way to determine the file size
other than by reading the file until EOF.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/interface/linux/linux_sysfs.c | 49 |
1 files changed, 20 insertions, 29 deletions
diff --git a/src/interface/linux/linux_sysfs.c b/src/interface/linux/linux_sysfs.c index 463bc2ab9..4f0027cd4 100644 --- a/src/interface/linux/linux_sysfs.c +++ b/src/interface/linux/linux_sysfs.c @@ -32,6 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** Read blocksize */ +#define LINUX_SYSFS_BLKSIZE 4096 + /** * Read file from sysfs * @@ -40,9 +43,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @ret len Length read, or negative error */ int linux_sysfs_read ( const char *filename, userptr_t *data ) { - size_t offset; - size_t len; + userptr_t tmp; ssize_t read; + size_t len; int fd; int rc; @@ -55,37 +58,27 @@ int linux_sysfs_read ( const char *filename, userptr_t *data ) { goto err_open; } - /* Get file length */ - if ( linux_fstat_size ( fd, &len ) == -1 ) { - rc = -ELINUX ( linux_errno ); - DBGC ( filename, "LINUX could not stat %s: %s\n", - filename, linux_strerror ( linux_errno ) ); - goto err_stat; - } + /* Read file */ + for ( *data = UNULL, len = 0 ; ; len += read ) { - /* Allocate buffer */ - *data = umalloc ( len ); - if ( ! *data ) { - rc = -ENOMEM; - DBGC ( filename, "LINUX could not allocate %zd bytes for %s\n", - len, filename ); - goto err_alloc; - } + /* (Re)allocate space */ + tmp = urealloc ( *data, ( len + LINUX_SYSFS_BLKSIZE ) ); + if ( ! tmp ) { + rc = -ENOMEM; + goto err_alloc; + } + *data = tmp; - /* Read file */ - for ( offset = 0 ; offset < len ; offset += read ) { - read = linux_read ( fd, user_to_virt ( *data, offset ), len ); + /* Read from file */ + read = linux_read ( fd, user_to_virt ( *data, len ), + LINUX_SYSFS_BLKSIZE ); + if ( read == 0 ) + break; if ( read < 0 ) { DBGC ( filename, "LINUX could not read %s: %s\n", filename, linux_strerror ( linux_errno ) ); goto err_read; } - if ( read == 0 ) { - rc = -EIO; - DBGC ( filename, "LINUX read underlength %s\n", - filename ); - goto err_eof; - } } /* Close file */ @@ -94,11 +87,9 @@ int linux_sysfs_read ( const char *filename, userptr_t *data ) { DBGC ( filename, "LINUX read %s\n", filename ); return len; - err_eof: err_read: - ufree ( *data ); err_alloc: - err_stat: + ufree ( *data ); linux_close ( fd ); err_open: return rc; |