From 07f84566d5c24f3f52f19fa17505392dec5c869d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 4 Aug 2007 01:22:52 +0100 Subject: [PATCH 1/3] Make read_user() non-blocking, and add select() call. --- src/core/posix_io.c | 94 ++++++++++++++++++++++-------------- src/include/gpxe/posix_io.h | 54 +++++++++++++++++++++ src/interface/pxe/pxe_tftp.c | 53 ++++++++++++++------ 3 files changed, 151 insertions(+), 50 deletions(-) diff --git a/src/core/posix_io.c b/src/core/posix_io.c index 21f818bf..530ce651 100644 --- a/src/core/posix_io.c +++ b/src/core/posix_io.c @@ -60,12 +60,6 @@ struct posix_file { /** List of open files */ static LIST_HEAD ( posix_files ); -/** Minimum file descriptor that will ever be allocated */ -#define POSIX_FD_MIN ( 1 ) - -/** Maximum file descriptor that will ever be allocated */ -#define POSIX_FD_MAX ( 255 ) - /** * Free open file * @@ -251,6 +245,38 @@ int open ( const char *uri_string ) { return rc; } +/** + * Check file descriptors for readiness + * + * @v readfds File descriptors to check + * @v wait Wait until data is ready + * @ret nready Number of ready file descriptors + */ +int select ( fd_set *readfds, int wait ) { + struct posix_file *file; + int fd; + + do { + for ( fd = POSIX_FD_MIN ; fd <= POSIX_FD_MAX ; fd++ ) { + if ( ! FD_ISSET ( fd, readfds ) ) + continue; + file = posix_fd_to_file ( fd ); + if ( ! file ) + return -EBADF; + if ( ( list_empty ( &file->data ) ) && + ( file->rc != -EINPROGRESS ) ) + continue; + /* Data is available or status has changed */ + FD_ZERO ( readfds ); + FD_SET ( fd, readfds ); + return 1; + } + step(); + } while ( wait ); + + return 0; +} + /** * Read data from file * @@ -258,47 +284,45 @@ int open ( const char *uri_string ) { * @v offset Starting offset within data buffer * @v len Maximum length to read * @ret len Actual length read, or negative error number + * + * This call is non-blocking; if no data is available to read then + * -EWOULDBLOCK will be returned. */ ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) { struct posix_file *file; struct io_buffer *iobuf; - size_t frag_len; - ssize_t len = 0; + size_t len; /* Identify file */ file = posix_fd_to_file ( fd ); if ( ! file ) return -EBADF; - while ( 1 ) { - /* Try to fetch more data if none available */ - if ( list_empty ( &file->data ) ) - step(); - /* Dequeue at most one received I/O buffer into user buffer */ - list_for_each_entry ( iobuf, &file->data, list ) { - frag_len = iob_len ( iobuf ); - if ( frag_len > max_len ) - frag_len = max_len; - copy_to_user ( buffer, offset, iobuf->data, - frag_len ); - iob_pull ( iobuf, frag_len ); - if ( ! iob_len ( iobuf ) ) { - list_del ( &iobuf-> list ); - free_iob ( iobuf ); - } - file->pos += frag_len; - len += frag_len; - offset += frag_len; - max_len -= frag_len; - break; + /* Try to fetch more data if none available */ + if ( list_empty ( &file->data ) ) + step(); + + /* Dequeue at most one received I/O buffer into user buffer */ + list_for_each_entry ( iobuf, &file->data, list ) { + len = iob_len ( iobuf ); + if ( len > max_len ) + len = max_len; + copy_to_user ( buffer, offset, iobuf->data, len ); + iob_pull ( iobuf, len ); + if ( ! iob_len ( iobuf ) ) { + list_del ( &iobuf->list ); + free_iob ( iobuf ); } - /* If buffer is full, return */ - if ( ! max_len ) - return len; - /* If file has completed, return */ - if ( file->rc != -EINPROGRESS ) - return ( file->rc ? file->rc : len ); + file->pos += len; + return len; } + + /* If file has completed, return (after returning all data) */ + if ( file->rc != -EINPROGRESS ) + return file->rc; + + /* No data ready and file still in progress; return -WOULDBLOCK */ + return -EWOULDBLOCK; } /** diff --git a/src/include/gpxe/posix_io.h b/src/include/gpxe/posix_io.h index a5cf0c75..9984db00 100644 --- a/src/include/gpxe/posix_io.h +++ b/src/include/gpxe/posix_io.h @@ -10,12 +10,66 @@ #include #include +/** Minimum file descriptor that will ever be allocated */ +#define POSIX_FD_MIN ( 1 ) + +/** Maximum file descriptor that will ever be allocated */ +#define POSIX_FD_MAX ( 31 ) + +/** File descriptor set as used for select() */ +typedef uint32_t fd_set; + extern int open ( const char *uri_string ); extern ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t len ); +extern int select ( fd_set *readfds, int wait ); extern ssize_t fsize ( int fd ); extern int close ( int fd ); +/** + * Zero a file descriptor set + * + * @v set File descriptor set + */ +static inline __attribute__ (( always_inline )) void +FD_ZERO ( fd_set *set ) { + *set = 0; +} + +/** + * Set a bit within a file descriptor set + * + * @v fd File descriptor + * @v set File descriptor set + */ +static inline __attribute__ (( always_inline )) void +FD_SET ( int fd, fd_set *set ) { + *set |= ( 1 << fd ); +} + +/** + * Clear a bit within a file descriptor set + * + * @v fd File descriptor + * @v set File descriptor set + */ +static inline __attribute__ (( always_inline )) void +FD_CLR ( int fd, fd_set *set ) { + *set &= ~( 1 << fd ); +} + +/** + * Test a bit within a file descriptor set + * + * @v fd File descriptor + * @v set File descriptor set + * @ret is_set Corresponding bit is set + */ +static inline __attribute__ (( always_inline )) int +FD_ISSET ( int fd, fd_set *set ) { + return ( *set & ( 1 << fd ) ); +} + /** * Read data from file * diff --git a/src/interface/pxe/pxe_tftp.c b/src/interface/pxe/pxe_tftp.c index 5197a631..64f7ffd5 100644 --- a/src/interface/pxe/pxe_tftp.c +++ b/src/interface/pxe/pxe_tftp.c @@ -78,6 +78,37 @@ static void pxe_tftp_build_uri ( char *uri_string, ( ( filename[0] == '/' ) ? "" : "/" ), filename ); } +/** + * Read as much as possible from file + * + * @v fd File descriptor + * @v buffer Data buffer + * @v max_len Maximum length to read + * @ret len Actual length read, or negative error + */ +static ssize_t pxe_tftp_read_all ( int fd, userptr_t buffer, + size_t max_len ) { + fd_set fdset; + off_t offset = 0; + int ready; + ssize_t len; + + do { + FD_ZERO ( &fdset ); + FD_SET ( fd, &fdset ); + ready = select ( &fdset, 1 ); + if ( ready < 0 ) + return ready; + len = read_user ( fd, buffer, offset, max_len ); + if ( len < 0 ) + return len; + offset += len; + max_len -= len; + } while ( max_len && len ); + + return offset; +} + /** * TFTP OPEN * @@ -251,11 +282,12 @@ PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) { buffer = real_to_user ( tftp_read->Buffer.segment, tftp_read->Buffer.offset ); - len = read_user ( pxe_single_fd, buffer, 0, pxe_single_blksize ); + len = pxe_tftp_read_all ( pxe_single_fd, buffer, pxe_single_blksize ); if ( len < 0 ) { tftp_read->Status = PXENV_STATUS ( len ); return PXENV_EXIT_FAILURE; } + tftp_read->BufferSize = len; tftp_read->PacketNumber = ++pxe_single_blkidx; @@ -359,10 +391,8 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE char uri_string[PXE_URI_LEN]; int fd; userptr_t buffer; - size_t max_len; - ssize_t frag_len; - size_t len = 0; - int rc = -ENOBUFS; + ssize_t len; + int rc = 0; DBG ( "PXENV_TFTP_READ_FILE" ); @@ -384,16 +414,9 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE /* Read file */ buffer = phys_to_user ( tftp_read_file->Buffer ); - max_len = tftp_read_file->BufferSize; - while ( max_len ) { - frag_len = read_user ( fd, buffer, len, max_len ); - if ( frag_len <= 0 ) { - rc = frag_len; - break; - } - len += frag_len; - max_len -= frag_len; - } + len = pxe_tftp_read_all ( fd, buffer, tftp_read_file->BufferSize ); + if ( len < 0 ) + rc = len; close ( fd ); tftp_read_file->BufferSize = len; From 950057eeeddcd6d253fcdeb43adf94f2953c14b9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 4 Aug 2007 01:23:37 +0100 Subject: [PATCH 2/3] Add PXE FILE API. --- src/arch/i386/interface/pxe/pxe_call.c | 25 ++++ src/include/pxe.h | 5 + src/include/pxe_api.h | 131 +++++++++++++++++ src/interface/pxe/pxe_file.c | 191 +++++++++++++++++++++++++ 4 files changed, 352 insertions(+) create mode 100644 src/interface/pxe/pxe_file.c diff --git a/src/arch/i386/interface/pxe/pxe_call.c b/src/arch/i386/interface/pxe/pxe_call.c index 1c1b5066..8f1dd0a2 100644 --- a/src/arch/i386/interface/pxe/pxe_call.c +++ b/src/arch/i386/interface/pxe/pxe_call.c @@ -91,6 +91,11 @@ union pxenv_call { ( struct s_PXENV_UNDI_GET_IFACE_INFO * ); PXENV_EXIT_t ( * undi_get_state ) ( struct s_PXENV_UNDI_GET_STATE * ); PXENV_EXIT_t ( * undi_isr ) ( struct s_PXENV_UNDI_ISR * ); + PXENV_EXIT_t ( * file_open ) ( struct s_PXENV_FILE_OPEN * ); + PXENV_EXIT_t ( * file_close ) ( struct s_PXENV_FILE_CLOSE * ); + PXENV_EXIT_t ( * file_select ) ( struct s_PXENV_FILE_SELECT * ); + PXENV_EXIT_t ( * file_read ) ( struct s_PXENV_FILE_READ * ); + PXENV_EXIT_t ( * get_file_size ) ( struct s_PXENV_GET_FILE_SIZE * ); }; /** @@ -269,6 +274,26 @@ __cdecl void pxe_api_call ( struct i386_all_regs *ix86 ) { pxenv_call.undi_isr = pxenv_undi_isr; param_len = sizeof ( pxenv_any.undi_isr ); break; + case PXENV_FILE_OPEN: + pxenv_call.file_open = pxenv_file_open; + param_len = sizeof ( pxenv_any.file_open ); + break; + case PXENV_FILE_CLOSE: + pxenv_call.file_close = pxenv_file_close; + param_len = sizeof ( pxenv_any.file_close ); + break; + case PXENV_FILE_SELECT: + pxenv_call.file_select = pxenv_file_select; + param_len = sizeof ( pxenv_any.file_select ); + break; + case PXENV_FILE_READ: + pxenv_call.file_read = pxenv_file_read; + param_len = sizeof ( pxenv_any.file_read ); + break; + case PXENV_GET_FILE_SIZE: + pxenv_call.get_file_size = pxenv_get_file_size; + param_len = sizeof ( pxenv_any.get_file_size ); + break; default: DBG ( "PXENV_UNKNOWN_%hx", opcode ); pxenv_call.unknown = pxenv_unknown; diff --git a/src/include/pxe.h b/src/include/pxe.h index 301bb10b..ecb664d5 100644 --- a/src/include/pxe.h +++ b/src/include/pxe.h @@ -58,6 +58,11 @@ union u_PXENV_ANY { struct s_PXENV_UNDI_GET_IFACE_INFO undi_get_iface_info; struct s_PXENV_UNDI_GET_STATE undi_get_state; struct s_PXENV_UNDI_ISR undi_isr; + struct s_PXENV_FILE_OPEN file_open; + struct s_PXENV_FILE_CLOSE file_close; + struct s_PXENV_FILE_SELECT file_select; + struct s_PXENV_FILE_READ file_read; + struct s_PXENV_GET_FILE_SIZE get_file_size; }; typedef union u_PXENV_ANY PXENV_ANY_t; diff --git a/src/include/pxe_api.h b/src/include/pxe_api.h index e6441325..8dc1607a 100644 --- a/src/include/pxe_api.h +++ b/src/include/pxe_api.h @@ -1555,6 +1555,137 @@ extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ); /** @} */ /* pxe_undi_api */ +/** @defgroup pxe_file_api PXE FILE API + * + * POSIX-like file operations + * + * @{ + */ + +/** @defgroup pxenv_file_open PXENV_FILE_OPEN + * + * FILE OPEN + * + * @{ + */ + +/** PXE API function code for pxenv_file_open() */ +#define PXENV_FILE_OPEN 0x00e0 + +/** Parameter block for pxenv_file_open() */ +struct s_PXENV_FILE_OPEN { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t FileHandle; /**< File handle */ + SEGOFF16_t FileName; /**< File URL */ + UINT32_t Reserved; /**< Reserved */ +} PACKED; + +typedef struct s_PXENV_FILE_OPEN PXENV_FILE_OPEN_t; + +extern PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ); + +/** @} */ /* pxenv_file_open */ + +/** @defgroup pxenv_file_close PXENV_FILE_CLOSE + * + * FILE CLOSE + * + * @{ + */ + +/** PXE API function code for pxenv_file_close() */ +#define PXENV_FILE_CLOSE 0x00e1 + +/** Parameter block for pxenv_file_close() */ +struct s_PXENV_FILE_CLOSE { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t FileHandle; /**< File handle */ +} PACKED; + +typedef struct s_PXENV_FILE_CLOSE PXENV_FILE_CLOSE_t; + +extern PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE + *file_close ); + +/** @} */ /* pxenv_file_close */ + +/** @defgroup pxenv_file_select PXENV_FILE_SELECT + * + * FILE SELECT + * + * @{ + */ + +/** PXE API function code for pxenv_file_select() */ +#define PXENV_FILE_SELECT 0x00e2 + +/** File is ready for reading */ +#define RDY_READ 0x0001 + +/** Parameter block for pxenv_file_select() */ +struct s_PXENV_FILE_SELECT { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t FileHandle; /**< File handle */ + UINT16_t Ready; /**< Indication of readiness */ +} PACKED; + +typedef struct s_PXENV_FILE_SELECT PXENV_FILE_SELECT_t; + +extern PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT + *file_select ); + +/** @} */ /* pxenv_file_select */ + +/** @defgroup pxenv_file_read PXENV_FILE_READ + * + * FILE READ + * + * @{ + */ + +/** PXE API function code for pxenv_file_read() */ +#define PXENV_FILE_READ 0x00e3 + +/** Parameter block for pxenv_file_read() */ +struct s_PXENV_FILE_READ { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t FileHandle; /**< File handle */ + UINT16_t BufferSize; /**< Data buffer size */ + SEGOFF16_t Buffer; /**< Data buffer */ +} PACKED; + +typedef struct s_PXENV_FILE_READ PXENV_FILE_READ_t; + +extern PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ); + +/** @} */ /* pxenv_file_read */ + +/** @defgroup pxenv_get_file_size PXENV_GET_FILE_SIZE + * + * GET FILE SIZE + * + * @{ + */ + +/** PXE API function code for pxenv_get_file_size() */ +#define PXENV_GET_FILE_SIZE 0x00e4 + +/** Parameter block for pxenv_get_file_size() */ +struct s_PXENV_GET_FILE_SIZE { + PXENV_STATUS_t Status; /**< PXE status code */ + UINT16_t FileHandle; /**< File handle */ + UINT32_t FileSize; /**< File size */ +} PACKED; + +typedef struct s_PXENV_GET_FILE_SIZE PXENV_GET_FILE_SIZE_t; + +extern PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE + *get_file_size ); + +/** @} */ /* pxenv_get_file_size */ + +/** @} */ /* pxe_file_api */ + /** @defgroup pxe_loader_api PXE Loader API * * The UNDI ROM loader API diff --git a/src/interface/pxe/pxe_file.c b/src/interface/pxe/pxe_file.c new file mode 100644 index 00000000..01dac8f7 --- /dev/null +++ b/src/interface/pxe/pxe_file.c @@ -0,0 +1,191 @@ +/** @file + * + * PXE FILE API + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Copyright (C) 2007 Michael Brown . + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 1 ); + +/** + * FILE OPEN + * + * @v file_open Pointer to a struct s_PXENV_FILE_OPEN + * @v s_PXENV_FILE_OPEN::FileName URL of file to open + * @ret #PXENV_EXIT_SUCCESS File was opened + * @ret #PXENV_EXIT_FAILURE File was not opened + * @ret s_PXENV_FILE_OPEN::Status PXE status code + * @ret s_PXENV_FILE_OPEN::FileHandle Handle of opened file + * + */ +PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) { + userptr_t filename; + size_t filename_len; + int fd; + + DBG ( "PXENV_FILE_OPEN" ); + + /* Copy name from external program, and open it */ + filename = real_to_user ( file_open->FileName.segment, + file_open->FileName.offset ); + filename_len = strlen_user ( filename, 0 ); + { + char uri_string[ filename_len + 1 ]; + + copy_from_user ( uri_string, filename, 0, + sizeof ( uri_string ) ); + DBG ( " %s", uri_string ); + fd = open ( uri_string ); + } + + if ( fd < 0 ) { + file_open->Status = PXENV_STATUS ( fd ); + return PXENV_EXIT_FAILURE; + } + + DBG ( " as file %d", fd ); + + file_open->FileHandle = fd; + file_open->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * FILE CLOSE + * + * @v file_close Pointer to a struct s_PXENV_FILE_CLOSE + * @v s_PXENV_FILE_CLOSE::FileHandle File handle + * @ret #PXENV_EXIT_SUCCESS File was closed + * @ret #PXENV_EXIT_FAILURE File was not closed + * @ret s_PXENV_FILE_CLOSE::Status PXE status code + * + */ +PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) { + + DBG ( "PXENV_FILE_CLOSE %d", file_close->FileHandle ); + + close ( file_close->FileHandle ); + file_close->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * FILE SELECT + * + * @v file_select Pointer to a struct s_PXENV_FILE_SELECT + * @v s_PXENV_FILE_SELECT::FileHandle File handle + * @ret #PXENV_EXIT_SUCCESS File has been checked for readiness + * @ret #PXENV_EXIT_FAILURE File has not been checked for readiness + * @ret s_PXENV_FILE_SELECT::Status PXE status code + * @ret s_PXENV_FILE_SELECT::Ready Indication of readiness + * + */ +PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) { + fd_set fdset; + int ready; + + DBG ( "PXENV_FILE_SELECT %d", file_select->FileHandle ); + + FD_ZERO ( &fdset ); + FD_SET ( file_select->FileHandle, &fdset ); + if ( ( ready = select ( &fdset, 0 ) ) < 0 ) { + file_select->Status = PXENV_STATUS ( ready ); + return PXENV_EXIT_FAILURE; + } + + file_select->Ready = ( ready ? RDY_READ : 0 ); + file_select->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * FILE READ + * + * @v file_read Pointer to a struct s_PXENV_FILE_READ + * @v s_PXENV_FILE_READ::FileHandle File handle + * @v s_PXENV_FILE_READ::BufferSize Size of data buffer + * @v s_PXENV_FILE_READ::Buffer Data buffer + * @ret #PXENV_EXIT_SUCCESS Data has been read from file + * @ret #PXENV_EXIT_FAILURE Data has not been read from file + * @ret s_PXENV_FILE_READ::Status PXE status code + * @ret s_PXENV_FILE_READ::Ready Indication of readiness + * @ret s_PXENV_FILE_READ::BufferSize Length of data read + * + */ +PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ) { + userptr_t buffer; + ssize_t len; + + DBG ( "PXENV_FILE_READ %d to %04x:%04x+%04x", file_read->FileHandle, + file_read->Buffer.segment, file_read->Buffer.offset, + file_read->BufferSize ); + + buffer = real_to_user ( file_read->Buffer.segment, + file_read->Buffer.offset ); + if ( ( len = read_user ( file_read->FileHandle, buffer, 0, + file_read->BufferSize ) ) < 0 ) { + file_read->Status = PXENV_STATUS ( len ); + return PXENV_EXIT_FAILURE; + } + + DBG ( " read %04zx", ( ( size_t ) len ) ); + + file_read->BufferSize = len; + file_read->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** + * GET FILE SIZE + * + * @v get_file_size Pointer to a struct s_PXENV_GET_FILE_SIZE + * @v s_PXENV_GET_FILE_SIZE::FileHandle File handle + * @ret #PXENV_EXIT_SUCCESS File size has been determined + * @ret #PXENV_EXIT_FAILURE File size has not been determined + * @ret s_PXENV_GET_FILE_SIZE::Status PXE status code + * @ret s_PXENV_GET_FILE_SIZE::FileSize Size of file + */ +PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE + *get_file_size ) { + ssize_t filesize; + + DBG ( "PXENV_GET_FILE_SIZE %d", get_file_size->FileHandle ); + + filesize = fsize ( get_file_size->FileHandle ); + if ( filesize < 0 ) { + get_file_size->Status = PXENV_STATUS ( filesize ); + return PXENV_EXIT_FAILURE; + } + + DBG ( " is %zd", ( ( size_t ) filesize ) ); + + get_file_size->FileSize = filesize; + get_file_size->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} From cfcc41d407e99968c23c2402a600263401ee41b8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 7 Aug 2007 06:50:12 -0700 Subject: [PATCH 3/3] Set current working URI to be that of the executable image when executing any image, not just a script. (This will enable pxelinux to use relative URIs, should it wish to.) --- src/core/image.c | 15 ++++++++++++--- src/image/script.c | 10 +--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/core/image.c b/src/core/image.c index 63c2502b..440a68c9 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -237,6 +237,7 @@ int image_autoload ( struct image *image ) { * @ret rc Return status code */ int image_exec ( struct image *image ) { + struct uri *old_cwuri; int rc; /* Image must be loaded first */ @@ -252,15 +253,23 @@ int image_exec ( struct image *image ) { if ( ! image->type->exec ) return -ENOEXEC; + /* Switch current working directory to be that of the image itself */ + old_cwuri = uri_get ( cwuri ); + churi ( image->uri ); + /* Try executing the image */ if ( ( rc = image->type->exec ( image ) ) != 0 ) { DBGC ( image, "IMAGE %p could not execute: %s\n", image, strerror ( rc ) ); - return rc; + goto done; } - /* Well, some formats might return... */ - return 0; + done: + /* Reset current working directory */ + churi ( old_cwuri ); + uri_put ( old_cwuri ); + + return rc; } /** diff --git a/src/image/script.c b/src/image/script.c index 2f159c97..c8821522 100644 --- a/src/image/script.c +++ b/src/image/script.c @@ -27,7 +27,6 @@ #include #include #include -#include struct image_type script_image_type __image_type ( PROBE_NORMAL ); @@ -38,7 +37,6 @@ struct image_type script_image_type __image_type ( PROBE_NORMAL ); * @ret rc Return status code */ static int script_exec ( struct image *image ) { - struct uri *old_cwuri; char cmdbuf[256]; size_t offset = 0; size_t remaining; @@ -53,10 +51,6 @@ static int script_exec ( struct image *image ) { image_get ( image ); unregister_image ( image ); - /* Switch current working directory to be that of the script itself */ - old_cwuri = uri_get ( cwuri ); - churi ( image->uri ); - while ( offset < image->len ) { /* Read up to cmdbuf bytes from script into buffer */ @@ -93,9 +87,7 @@ static int script_exec ( struct image *image ) { rc = 0; done: - /* Reset current working directory, re-register image and return */ - churi ( old_cwuri ); - uri_put ( old_cwuri ); + /* Re-register image and return */ register_image ( image ); image_put ( image ); return rc;