]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[linux] Add a generic function for reading files from sysfs
authorMichael Brown <mcb30@ipxe.org>
Tue, 2 Mar 2021 23:37:41 +0000 (23:37 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 2 Mar 2021 23:59:30 +0000 (23:59 +0000)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/include/ipxe/errfile.h
src/include/ipxe/linux_api.h
src/include/ipxe/linux_sysfs.h [new file with mode: 0644]
src/interface/linux/linux_api.c
src/interface/linux/linux_sysfs.c [new file with mode: 0644]

index b5c5d185edf40e8a40d4b20e857b210eca1261ae..3daf7bde7ab512800bf1206a56f3f31f8f0959ee 100644 (file)
@@ -388,6 +388,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #define ERRFILE_efi_autoboot         ( ERRFILE_OTHER | 0x00530000 )
 #define ERRFILE_efi_autoexec         ( ERRFILE_OTHER | 0x00540000 )
 #define ERRFILE_efi_cachedhcp        ( ERRFILE_OTHER | 0x00550000 )
+#define ERRFILE_linux_sysfs          ( ERRFILE_OTHER | 0x00560000 )
 
 /** @} */
 
index 040b52f8c41d1ed78efcda2c7f2c7e8521385fa1..ab2e8014de6d872c47a9c8c27a9eccf074f809de 100644 (file)
@@ -46,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <linux/ioctl.h>
 #include <linux/poll.h>
 #include <linux/fs.h>
+#include <linux/stat.h>
 #define MAP_FAILED ( ( void * ) -1 )
 #endif
 
@@ -65,6 +66,8 @@ extern ssize_t __asmcall linux_read ( int fd, void *buf, size_t count );
 extern ssize_t __asmcall linux_write ( int fd, const void *buf, size_t count );
 extern int __asmcall linux_fcntl ( int fd, int cmd, ... );
 extern int __asmcall linux_ioctl ( int fd, unsigned long request, ... );
+extern int __asmcall linux_statx ( int dirfd, const char *pathname, int flags,
+                                  unsigned int mask, struct statx *statxbuf );
 extern int __asmcall linux_poll ( struct pollfd *fds, unsigned int nfds,
                                  int timeout );
 extern int __asmcall linux_nanosleep ( const struct timespec *req,
diff --git a/src/include/ipxe/linux_sysfs.h b/src/include/ipxe/linux_sysfs.h
new file mode 100644 (file)
index 0000000..d97b649
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _IPXE_LINUX_SYSFS_H
+#define _IPXE_LINUX_SYSFS_H
+
+/** @file
+ *
+ * Linux sysfs files
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/uaccess.h>
+
+extern int linux_sysfs_read ( const char *filename, userptr_t *data );
+
+#endif /* _IPXE_LINUX_SYSFS_H */
index fa694330eec26682c078a58b0cc0b4116e59b784..6fa2b0e76b557b11e0755117dd019746e64fd73c 100644 (file)
@@ -32,6 +32,7 @@
 #include <sys/mman.h>
 #include <sys/socket.h>
 #include <sys/time.h>
+#include <sys/stat.h>
 #include <netinet/in.h>
 #include <ipxe/linux_api.h>
 #include <ipxe/slirp.h>
@@ -198,6 +199,20 @@ int __asmcall linux_ioctl ( int fd, unsigned long request, ... ) {
        return ret;
 }
 
+/**
+ * Wrap statx()
+ *
+ */
+int __asmcall linux_statx ( int dirfd, const char *pathname, int flags,
+                           unsigned int mask, struct statx *statxbuf ) {
+       int ret;
+
+       ret = statx ( dirfd, pathname, flags, mask, statxbuf );
+       if ( ret == -1 )
+               linux_errno = errno;
+       return ret;
+}
+
 /**
  * Wrap poll()
  *
@@ -516,6 +531,7 @@ PROVIDE_IPXE_SYM ( linux_read );
 PROVIDE_IPXE_SYM ( linux_write );
 PROVIDE_IPXE_SYM ( linux_fcntl );
 PROVIDE_IPXE_SYM ( linux_ioctl );
+PROVIDE_IPXE_SYM ( linux_statx );
 PROVIDE_IPXE_SYM ( linux_poll );
 PROVIDE_IPXE_SYM ( linux_nanosleep );
 PROVIDE_IPXE_SYM ( linux_usleep );
diff --git a/src/interface/linux/linux_sysfs.c b/src/interface/linux/linux_sysfs.c
new file mode 100644 (file)
index 0000000..0b9f1f5
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <errno.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/linux_api.h>
+#include <ipxe/linux.h>
+#include <ipxe/linux_sysfs.h>
+
+/** @file
+ *
+ * Linux sysfs files
+ *
+ */
+
+/**
+ * Read file from sysfs
+ *
+ * @v filename         Filename
+ * @v data             Data to fill in
+ * @ret len            Length read, or negative error
+ */
+int linux_sysfs_read ( const char *filename, userptr_t *data ) {
+       struct statx statx;
+       size_t offset;
+       size_t len;
+       ssize_t read;
+       int fd;
+       int rc;
+
+       /* Open file */
+       fd = linux_open ( filename, O_RDONLY );
+       if ( fd < 0 ) {
+               rc = -ELINUX ( linux_errno );
+               DBGC ( filename, "LINUX could not open %s: %s\n",
+                      filename, linux_strerror ( linux_errno ) );
+               goto err_open;
+       }
+
+       /* Get file length */
+       if ( linux_statx ( fd, "", AT_EMPTY_PATH, STATX_SIZE, &statx ) == -1 ) {
+               rc = -ELINUX ( linux_errno );
+               DBGC ( filename, "LINUX could not stat %s: %s\n",
+                      filename, linux_strerror ( linux_errno ) );
+               goto err_stat;
+       }
+       len = statx.stx_size;
+
+       /* 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;
+       }
+
+       /* Read file */
+       for ( offset = 0 ; offset < len ; offset += read ) {
+               read = linux_read ( fd, user_to_virt ( *data, offset ), len );
+               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 */
+       linux_close ( fd );
+
+       DBGC ( filename, "LINUX read %s\n", filename );
+       return len;
+
+ err_eof:
+ err_read:
+       ufree ( *data );
+ err_alloc:
+ err_stat:
+       linux_close ( fd );
+ err_open:
+       return rc;
+}