diff --git a/src/arch/i386/interface/pxe/pxe_call.c b/src/arch/i386/interface/pxe/pxe_call.c index 8f1dd0a2..b9c21ce5 100644 --- a/src/arch/i386/interface/pxe/pxe_call.c +++ b/src/arch/i386/interface/pxe/pxe_call.c @@ -96,6 +96,7 @@ union pxenv_call { 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 * ); + PXENV_EXIT_t ( * file_exec ) ( struct s_PXENV_FILE_EXEC * ); }; /** @@ -294,6 +295,10 @@ __cdecl void pxe_api_call ( struct i386_all_regs *ix86 ) { pxenv_call.get_file_size = pxenv_get_file_size; param_len = sizeof ( pxenv_any.get_file_size ); break; + case PXENV_FILE_EXEC: + pxenv_call.file_exec = pxenv_file_exec; + param_len = sizeof ( pxenv_any.file_exec ); + 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 f17d8f77..8b3ca14c 100644 --- a/src/include/pxe.h +++ b/src/include/pxe.h @@ -63,6 +63,7 @@ union u_PXENV_ANY { struct s_PXENV_FILE_SELECT file_select; struct s_PXENV_FILE_READ file_read; struct s_PXENV_GET_FILE_SIZE get_file_size; + struct s_PXENV_FILE_EXEC file_exec; }; typedef union u_PXENV_ANY PXENV_ANY_t; diff --git a/src/include/pxe_api.h b/src/include/pxe_api.h index 8dc1607a..53708ed4 100644 --- a/src/include/pxe_api.h +++ b/src/include/pxe_api.h @@ -1684,6 +1684,28 @@ extern PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE /** @} */ /* pxenv_get_file_size */ +/** @defgroup pxenv_file_exec PXENV_FILE_EXEC + * + * FILE EXEC + * + * @{ + */ + +/** PXE API function code for pxenv_file_exec() */ +#define PXENV_FILE_EXEC 0x00e5 + +/** Parameter block for pxenv_file_exec() */ +struct s_PXENV_FILE_EXEC { + PXENV_STATUS_t Status; /**< PXE status code */ + SEGOFF16_t Command; /**< Command to execute */ +} PACKED; + +typedef struct s_PXENV_FILE_EXEC PXENV_FILE_EXEC_t; + +extern PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ); + +/** @} */ /* pxenv_file_exec */ + /** @} */ /* pxe_file_api */ /** @defgroup pxe_loader_api PXE Loader API diff --git a/src/interface/pxe/pxe_file.c b/src/interface/pxe/pxe_file.c index 01dac8f7..718f5e38 100644 --- a/src/interface/pxe/pxe_file.c +++ b/src/interface/pxe/pxe_file.c @@ -31,7 +31,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 1 ); +FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 2 ); /** * FILE OPEN @@ -189,3 +189,41 @@ PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE get_file_size->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; } + +/** + * FILE EXEC + * + * @v file_exec Pointer to a struct s_PXENV_FILE_EXEC + * @v s_PXENV_FILE_EXEC::Command Command to execute + * @ret #PXENV_EXIT_SUCCESS Command was executed successfully + * @ret #PXENV_EXIT_FAILURE Command was not executed successfully + * @ret s_PXENV_FILE_EXEC::Status PXE status code + * + */ +PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) { + userptr_t command; + size_t command_len; + int rc; + + DBG ( "PXENV_FILE_EXEC" ); + + /* Copy name from external program, and exec it */ + command = real_to_user ( file_exec->Command.segment, + file_exec->Command.offset ); + command_len = strlen_user ( command, 0 ); + { + char command_string[ command_len + 1 ]; + + copy_from_user ( command_string, command, 0, + sizeof ( command_string ) ); + DBG ( " %s", command_string ); + + if ( ( rc = system ( command_string ) ) != 0 ) { + file_exec->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + } + + file_exec->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +}