From f3d817d512f0f0a33f3476c11da657f7bbe3c2f5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 8 Dec 2006 01:23:11 +0000 Subject: [PATCH] Added execv() and system(). --- src/core/exec.c | 139 +++++++++++++++++++++++++++++++++++++ src/include/gpxe/command.h | 22 ++++++ src/include/stdlib.h | 1 + src/include/unistd.h | 24 +++++++ 4 files changed, 186 insertions(+) create mode 100644 src/core/exec.c create mode 100644 src/include/gpxe/command.h create mode 100644 src/include/unistd.h diff --git a/src/core/exec.c b/src/core/exec.c new file mode 100644 index 00000000..a0f0b527 --- /dev/null +++ b/src/core/exec.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2006 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Command execution + * + */ + +static struct command commands[0] __table_start ( commands ); +static struct command commands_end[0] __table_end ( commands ); + +/** + * Execute command + * + * @v command Command name + * @v argv Argument list + * @ret rc Command exit status + * + * Execute the named command. Unlike a traditional POSIX execv(), + * this function returns the exit status of the command. + */ +int execv ( const char *command, char * const argv[] ) { + struct command *cmd; + int argc = 0; + + assert ( argv[0] != NULL ); + + /* Count number of arguments */ + do { + argc++; + } while ( argv[argc] != NULL ); + + /* Reset getopt() library ready for use by the command. This + * is an artefact of the POSIX getopt() API within the context + * of Etherboot; see the documentation for reset_getopt() for + * details. + */ + reset_getopt(); + + /* Hand off to command implementation */ + for ( cmd = commands ; cmd < commands_end ; cmd++ ) { + if ( strcmp ( command, cmd->name ) == 0 ) + return cmd->exec ( argc, ( char ** ) argv ); + } + + printf ( "%s: command not found\n", command ); + return -ENOEXEC; +} + +/** + * Split command line into argv array + * + * @v args Command line + * @v argv Argument array to populate, or NULL + * @ret argc Argument count + * + * Splits the command line into whitespace-delimited arguments. If @c + * argv is non-NULL, any whitespace in the command line will be + * replaced with NULs. + */ +static int split_args ( char *args, char * argv[] ) { + int argc = 0; + + while ( 1 ) { + /* Skip over any whitespace / convert to NUL */ + while ( *args == ' ' ) { + if ( argv ) + *args = '\0'; + args++; + } + /* Check for end of line */ + if ( ! *args ) + break; + /* We have found the start of the next argument */ + if ( argv ) + argv[argc] = args; + argc++; + /* Skip to start of next whitespace, if any */ + while ( *args && ( *args != ' ' ) ) { + args++; + } + } + return argc; +} + +/** + * Execute command line + * + * @v command Command line + * @ret rc Command exit status + * + * Execute the named command and arguments. + */ +int system ( const char *command ) { + char *args = strdup ( command ); + int argc; + + if ( ! args ) + return -ENOMEM; + + /* Count arguments */ + argc = split_args ( args, NULL ); + + /* Create argv array and execute command */ + { + char * argv[argc + 1]; + + split_args ( args, argv ); + argv[argc] = NULL; + return execv ( argv[0], argv ); + } +} diff --git a/src/include/gpxe/command.h b/src/include/gpxe/command.h new file mode 100644 index 00000000..95f6c5ed --- /dev/null +++ b/src/include/gpxe/command.h @@ -0,0 +1,22 @@ +#ifndef _GPXE_COMMAND_H +#define _GPXE_COMMAND_H + +#include + +/** A command-line command */ +struct command { + /** Name of the command */ + const char *name; + /** + * Function implementing the command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ + int ( * exec ) ( int argc, char **argv ); +}; + +#define __command __table ( commands, 01 ) + +#endif /* _GPXE_COMMAND_H */ diff --git a/src/include/stdlib.h b/src/include/stdlib.h index a7dd1d83..d71ee1ab 100644 --- a/src/include/stdlib.h +++ b/src/include/stdlib.h @@ -5,6 +5,7 @@ extern unsigned long strtoul ( const char *p, char **endp, int base ); extern void * realloc ( void *old_ptr, size_t new_size ); extern void * malloc ( size_t size ); extern void free ( void *ptr ); +extern int system ( const char *command ); /** * Allocate cleared memory diff --git a/src/include/unistd.h b/src/include/unistd.h new file mode 100644 index 00000000..9dd51dcd --- /dev/null +++ b/src/include/unistd.h @@ -0,0 +1,24 @@ +#ifndef _UNISTD_H +#define _UNISTD_H + +#include +#include + +extern int execv ( const char *command, char * const argv[] ); + +/** + * Execute command + * + * @v command Command name + * @v arg ... Argument list (starting with argv[0]) + * @ret rc Command exit status + * + * This is a front end to execv(). + */ +#define execl( command, arg, ... ) ( { \ + char * const argv[] = { (arg), ## __VA_ARGS__, NULL }; \ + int rc = execv ( (command), argv ); \ + rc; \ + } ) + +#endif /* _UNISTD_H */