From 4e1c4967e652e4d929695661a252822c044d454b Mon Sep 17 00:00:00 2001 From: Olaf Barthel Date: Tue, 1 Aug 2006 14:27:52 +0000 Subject: [PATCH] - Added preliminary versions of the exec() family functions. git-svn-id: file:///Users/olsen/Code/migration-svn-zu-git/logical-line-staging/clib2/trunk@15110 87f5fb63-7c3d-0410-a384-fd976d0f7a62 --- library/unistd_execl.c | 98 ++++++++ library/unistd_execle.c | 111 +++++++++ library/unistd_execlp.c | 98 ++++++++ library/unistd_execv.c | 52 ++++ library/unistd_execve.c | 518 ++++++++++++++++++++++++++++++++++++++++ library/unistd_execvp.c | 216 +++++++++++++++++ 6 files changed, 1093 insertions(+) create mode 100644 library/unistd_execl.c create mode 100644 library/unistd_execle.c create mode 100644 library/unistd_execlp.c create mode 100644 library/unistd_execv.c create mode 100644 library/unistd_execve.c create mode 100644 library/unistd_execvp.c diff --git a/library/unistd_execl.c b/library/unistd_execl.c new file mode 100644 index 0000000..88bd057 --- /dev/null +++ b/library/unistd_execl.c @@ -0,0 +1,98 @@ +/* + * $Id: unistd_execl.c,v 1.1 2006-08-01 14:27:52 obarthel Exp $ + * + * :ts=4 + * + * Portable ISO 'C' (1994) runtime library for the Amiga computer + * Copyright (c) 2002-2006 by Olaf Barthel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of Olaf Barthel nor the names of contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _UNISTD_HEADERS_H +#include "unistd_headers.h" +#endif /* _UNISTD_HEADERS_H */ + +/****************************************************************************/ + +/* The following is not part of the ISO 'C' (1994) standard. */ + +/****************************************************************************/ + +int +execl(const char *path, const char *arg0, ...) +{ + char ** argv = NULL; + int result = -1; + size_t argc = 0; + va_list args; + + /* If there are any, count the number of arguments supplied */ + if(arg0 != NULL) + { + argc = 1; + + va_start(args,arg0); + + while(va_arg(args,const char *) != NULL) + argc++; + + va_end(args); + } + + /* Allocate enough memory for the entire argument list + plus the terminating NULL */ + argv = (char **)malloc(sizeof(*argv) * (argc + 1)); + if(argv == NULL) + { + __set_errno(ENOMEM); + goto out; + } + + if(argc > 0) + { + size_t i; + + argv[0] = arg0; + + va_start(args,arg0); + + for(i = 1 ; i < argc ; i++) + argv[i] = va_arg(args,const char *); + + va_end(args); + } + + argv[argc] = NULL; + + result = execve(path,(char * const *)argv, NULL /*environ*/ ); + + out: + + if(argv != NULL) + free(argv); + + return(result); +} diff --git a/library/unistd_execle.c b/library/unistd_execle.c new file mode 100644 index 0000000..e3c2820 --- /dev/null +++ b/library/unistd_execle.c @@ -0,0 +1,111 @@ +/* + * $Id: unistd_execle.c,v 1.1 2006-08-01 14:27:52 obarthel Exp $ + * + * :ts=4 + * + * Portable ISO 'C' (1994) runtime library for the Amiga computer + * Copyright (c) 2002-2006 by Olaf Barthel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of Olaf Barthel nor the names of contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _UNISTD_HEADERS_H +#include "unistd_headers.h" +#endif /* _UNISTD_HEADERS_H */ + +/****************************************************************************/ + +/* The following is not part of the ISO 'C' (1994) standard. */ + +/****************************************************************************/ + +int +execle(const char *path, const char *arg0, ...) +{ + char ** argv = NULL; + int result = -1; + size_t argc = 0; + va_list args; + char **envp; + + /* If there are any, count the number of arguments supplied */ + if(arg0 != NULL) + { + argc = 1; + + va_start(args,arg0); + + while(va_arg(args,const char *) != NULL) + argc++; + + va_end(args); + } + + /* Allocate enough memory for the entire argument list + plus the terminating NULL */ + argv = (char **)malloc(sizeof(*argv) * (argc + 1)); + if(argv == NULL) + { + __set_errno(ENOMEM); + goto out; + } + + if(argc > 0) + { + size_t i; + + argv[0] = arg0; + + va_start(args,arg0); + + for(i = 1 ; i < argc ; i++) + argv[i] = va_arg(args,const char *); + + /* Skip the NULL terminator */ + (void)va_arg(args, char **); + envp = va_arg(args, char **); + + va_end(args); + } + else + { + va_start(args,arg0); + + envp = va_arg(args, char **); + + va_end(args); + } + + argv[argc] = NULL; + + result = execve(path,(char * const *)argv, envp ); + + out: + + if(argv != NULL) + free(argv); + + return(result); +} diff --git a/library/unistd_execlp.c b/library/unistd_execlp.c new file mode 100644 index 0000000..f9228aa --- /dev/null +++ b/library/unistd_execlp.c @@ -0,0 +1,98 @@ +/* + * $Id: unistd_execlp.c,v 1.1 2006-08-01 14:27:52 obarthel Exp $ + * + * :ts=4 + * + * Portable ISO 'C' (1994) runtime library for the Amiga computer + * Copyright (c) 2002-2006 by Olaf Barthel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of Olaf Barthel nor the names of contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _UNISTD_HEADERS_H +#include "unistd_headers.h" +#endif /* _UNISTD_HEADERS_H */ + +/****************************************************************************/ + +/* The following is not part of the ISO 'C' (1994) standard. */ + +/****************************************************************************/ + +int +execlp(const char *path, const char *arg0, ...) +{ + char ** argv = NULL; + int result = -1; + size_t argc = 0; + va_list args; + + /* If there are any, count the number of arguments supplied */ + if(arg0 != NULL) + { + argc = 1; + + va_start(args,arg0); + + while(va_arg(args,const char *) != NULL) + argc++; + + va_end(args); + } + + /* Allocate enough memory for the entire argument list + plus the terminating NULL */ + argv = (char **)malloc(sizeof(*argv) * (argc + 1)); + if(argv == NULL) + { + __set_errno(ENOMEM); + goto out; + } + + if(argc > 0) + { + size_t i; + + argv[0] = arg0; + + va_start(args,arg0); + + for(i = 1 ; i < argc ; i++) + argv[i] = va_arg(args,const char *); + + va_end(args); + } + + argv[argc] = NULL; + + result = execvp(path,(char * const *)argv); + + out: + + if(argv != NULL) + free(argv); + + return(result); +} diff --git a/library/unistd_execv.c b/library/unistd_execv.c new file mode 100644 index 0000000..d834847 --- /dev/null +++ b/library/unistd_execv.c @@ -0,0 +1,52 @@ +/* + * $Id: unistd_execv.c,v 1.1 2006-08-01 14:27:52 obarthel Exp $ + * + * :ts=4 + * + * Portable ISO 'C' (1994) runtime library for the Amiga computer + * Copyright (c) 2002-2006 by Olaf Barthel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of Olaf Barthel nor the names of contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _UNISTD_HEADERS_H +#include "unistd_headers.h" +#endif /* _UNISTD_HEADERS_H */ + +/****************************************************************************/ + +/* The following is not part of the ISO 'C' (1994) standard. */ + +/****************************************************************************/ + +int +execv(const char *path,char * const argv[]) +{ + int result; + + result = execve(path,argv,environ); + + return(result); +} diff --git a/library/unistd_execve.c b/library/unistd_execve.c new file mode 100644 index 0000000..7b7a545 --- /dev/null +++ b/library/unistd_execve.c @@ -0,0 +1,518 @@ +/* + * $Id: unistd_execve.c,v 1.1 2006-08-01 14:27:52 obarthel Exp $ + * + * :ts=4 + * + * Portable ISO 'C' (1994) runtime library for the Amiga computer + * Copyright (c) 2002-2006 by Olaf Barthel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of Olaf Barthel nor the names of contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _UNISTD_HEADERS_H +#include "unistd_headers.h" +#endif /* _UNISTD_HEADERS_H */ + +/****************************************************************************/ + +/* The following is not part of the ISO 'C' (1994) standard. */ + +/****************************************************************************/ + +/* Try to find a file, given its full path name. Since it's possible that + the path name may reference volumes, devices or assignments which are + not currently valid we'll turn off DOS requesters while looking. */ +STATIC int +find_file_and_parent( + char * path, + BPTR * parent_lock_ptr, + struct FileInfoBlock * fib) +{ + struct name_translation_info nti; + APTR old_window_ptr; + BPTR file_lock = ZERO; + int result = -1; + int error; + + (*parent_lock_ptr) = ZERO; + + old_window_ptr = __set_process_window((APTR)-1); + + error = __translate_unix_to_amiga_path_name(&path,&nti); + if(error != 0) + { + __set_errno(error); + goto out; + } + + /* ZZZ we ought to walk down the assignment list all on our + own rather than trusting the Lock() to find the right + kind of file */ + file_lock = Lock(path,SHARED_LOCK); + if(file_lock == ZERO) + { + __set_errno(__translate_io_error_to_errno(IoErr())); + goto out; + } + + if(CANNOT Examine(file_lock,fib)) + { + __set_errno(__translate_io_error_to_errno(IoErr())); + goto out; + } + + /* This must be a file. */ + if(fib->fib_DirEntryType >= 0) + { + __set_errno(EISDIR); + goto out; + } + + /* And it should be executable. */ + if(fib->fib_Protection & FIBF_EXECUTE) + { + __set_errno(ENOEXEC); + goto out; + } + + (*parent_lock_ptr) = ParentDir(file_lock); + if((*parent_lock_ptr) == ZERO) + { + LONG io_error; + + io_error = IoErr(); + if(io_error == 0) + io_error = ERROR_OBJECT_WRONG_TYPE; + + __set_errno(__translate_io_error_to_errno(io_err)); + goto out; + } + + result = 0; + + out: + + if(file_lock != ZERO) + UnLock(file_lock); + + if(result != 0) + { + if((*parent_lock_ptr) != ZERO) + { + UnLock(*parent_lock_ptr); + (*parent_lock_ptr) = ZERO; + } + } + + __set_process_window(old_window_ptr); + + return(result); +} + +/****************************************************************************/ + +static size_t +count_extra_escape_chars(const char * string,size_t len) +{ + size_t count = 0; + size_t i; + char c; + + for(i = 0 ; i < len ; i++) + { + c = (*s++); + if(c == '\"' || c == '*' || c == '\n') + count++; + } + + return(count); +} + +/****************************************************************************/ + +STATIC BOOL +string_needs_escaping(const char * string,size_t len) +{ + BOOL result = FALSE; + size_t i; + char c; + + for(i = 0 ; i < len ; i++) + { + c = (*s++); + if(c == ' ' || ((unsigned char)c) == 0xA0 || c == '\t' || c == '\n' || c == '\"') + { + result = TRUE; + break; + } + } + + return(result); +} + +/****************************************************************************/ + +static size_t +get_arg_string_length(char *const argv[]) +{ + size_t result = 0; + size_t i,len; + char * s; + + for(i = 0 ; argv[i] != NULL ; i++) + { + s = (char *)argv[i]; + + len = strlen(s); + if(len > 0) + { + if((*s) != '\"') + { + if(string_needs_escaping(s,len)) + len += 1 + count_extra_escape_chars(s,len) + 1; + } + + if(result == 0) + result = len; + else + result = result + 1 + len; + } + } + + return(result); +} + +/****************************************************************************/ + +static void +build_arg_string(char *const argv[],char * arg_string) +{ + BOOL first_char = FALSE; + size_t i,j,len; + char * s; + + for(i = 0 ; argv[i] != NULL ; i++) + { + s = (char *)argv[i]; + + len = strlen(s); + if(len > 0) + { + if(first_char) + first_char = FALSE; + else + (*arg_string++) = ' '; + + if((*s) != '\"' && string_needs_escaping(s,len)) + { + (*arg_string++) = '\"'; + + for(j = 0 ; j < len ; j++) + { + if(s[j] == '\"' || s[j] == '*' || s[j] == '\n') + (*arg_string++) = '*'; + + (*arg_string++) = s[j]; + } + + (*arg_string++) = '\"'; + } + else + { + memcpy(arg_string,s,len); + arg_string += len; + } + } + } +} + +/****************************************************************************/ + +int +execve(const char *path, char *const argv[], char *const envp[]) +{ + struct Process * this_process = (struct Process *)FindTask(NULL); + D_S(struct FileInfoBlock,fib); + char old_program_name[256] + BPTR parent_dir = ZERO; + BPTR old_dir; + BPTR script_file = ZERO; + int result = -1; + char * interpreter_line = NULL; + size_t interpreter_line_size = 0; + size_t interpreter_line_length = 0; + char * interpreter_name = NULL; + char * interpreter_args = NULL; + char * arg_string = NULL; + size_t arg_string_len = 0; + size_t parameter_string_len; + BPTR segment_list = ZERO; + BOOL success = FALSE; + int error; + LONG rc; + LONG c; + + /* We begin by looking at the file or command to be run. */ + if(find_file_and_parent(path,&parent_dir,fib) != 0) + goto out; + + /* Now open that file again so that we can check if it's + a script file. */ + old_dir = CurrentDir(parent_dir); + script_file = Open(fib->fib_FileName,MODE_OLDFILE); + CurrentDir(old_dir); + + if(script_file == ZERO) + { + __set_errno(__translate_io_error_to_errno(IoErr())); + goto out; + } + + SetVBuf(script_file,NULL,BUF_LINE,1024); + + /* Check if the first line begins with "#!" and if so, + read what else can be found in that line. */ + c = FGetC(script_file); + if(c == '#') + { + c = FGetC(script_file); + if(c == '!') + { + /* Skip leading blank spaces. */ + do + { + c = FGetC(script_file); + if(c == -1) + break; + } + while(isspace(c)); + + if(c != -1) + { + /* Read everything that follows. */ + while((c = FGetC(script_file)) != -1) + { + /* Still enough room in the buffer? We always reserve + enough memory for the next character and a NUL + to terminate the string with. */ + if(interpreter_line_length + 2 > interpreter_line_size) + { + char * new_interpreter_line; + + /* Always reserve a little more memory than needed, + and one extra byte to allow us to to NUL-terminate + the string. */ + new_interpreter_line = realloc(interpreter_line,interpreter_line_length + 10); + if(new_interpreter_line == NULL) + { + __set_error(ENOMEM); + goto out; + } + + interpreter_line = new_interpreter_line; + interpreter_line_size = interpreter_line_length + 10; + } + + interpreter_line[interpreter_line_length++] = c; + if(c == '\n') + break; + } + + /* Provide for NUL-termination. */ + if(interpreter_line_size > 0) + { + /* Also strip all trailing blank spaces; that includes + line feed and carriage return characters. */ + while(interpreter_line_length > 0 && isspace(interpreter_line[interpreter_line_length-1])) + interpreter_line_length--; + + interpreter_line[interpreter_line_length] = '\0'; + } + } + } + } + + if(c == -1) + { + LONG io_error; + + /* Check if we just hit the end of the file or whethere + there was a genuine problem. */ + io_error = IoErr(); + if(io_error != 0) + { + __set_errno(__translate_io_error_to_errno(io_error)); + goto out; + } + } + + Close(script_file); + script_file = ZERO; + + if(interpreter_line_size > 0) + { + interpreter_name = interpreter_line; + + for(i = 0 ; i < interpreter_line_size ; i++) + { + if(isspace(interpreter_name[i])) + { + interpreter_name[i] = '\0'; + + interpreter_args = &interpreter_name[i+1]; + + while((*interpreter_args) != '\0' && isspace(*interpreter_args)) + interpreter_args++; + + if((*interpreter_args) == '\0') + interpreter_args = NULL; + + break; + } + } + } + + parameter_string_len = get_arg_string_length(argv); + + if(interpreter_name != NULL) + { + struct name_translation_info nti; + size_t interpreter_args_len; + size_t len; + + UnLock(parent_dir); + parent_dir = ZERO; + + if(find_file_and_parent(interpreter_name,&parent_dir,fib) != 0) + goto out; + + error = __translate_unix_to_amiga_path_name(&path,&nti); + if(error != 0) + { + __set_errno(error); + goto out; + } + + if(interpreter_args != NULL) + interpreter_args_len = strlen(interpreter_args); + else + interpreter_args_len = 0; + + len = strlen(path); + + arg_string = malloc(interpreter_args_len + 1 + len + parameter_string_len + 1 + 1); + if(arg_string == NULL) + { + __set_errno(ENOMEM); + goto out; + } + + if(interpreter_args_len > 0) + { + memcpy(arg_string,interpreter_args,interpreter_args_len); + arg_string_len += interpreter_args_len; + + arg_string[arg_string_len++] = ' '; + } + + memcpy(&arg_string[arg_string_len],path,len); + arg_string_len += len; + + if(parameter_string_len > 0) + arg_string[arg_string_len++] = ' '; + } + else + { + arg_string = malloc(parameter_string_len + 1 + 1); + if(arg_string == NULL) + { + __set_errno(ENOMEM); + goto out; + } + } + + if(parameter_string_len > 0) + { + build_arg_string(argv,&arg_string[arg_string_len]); + arg_string_len += parameter_string_len; + } + + arg_string[arg_string_len++] = '\n'; + arg_string[arg_string_len] = '\0'; + + old_dir = CurrentDir(parent_dir); + segment_list = LoadSeg(fib->fib_FileName); + CurrentDir(old_dir); + + if(segment_list == ZERO) + { + __set_errno(ENOENT); + goto out; + } + + GetProgramName(old_program_name,sizeof(old_program_name)); + SetProgramName(fib->fib_FileName); + + old_dir = ThisProcess->pr_HomeDir; + ThisProcess->pr_HomeDir = parent_dir; + + SetSignal(0,SIGBREAKF_CTRL_C); + + rc = RunCommand(segment_list,Cli()->cli_DefaultStack * sizeof(LONG),arg_string,arg_string_len); + + ThisProcess->pr_HomeDir = old_dir; + + if(rc == -1) + { + SetProgramName(old_program_name); + + __set_errno(__translate_io_error_to_errno(IoErr())); + goto out; + } + + success = TRUE; + + out: + + if(arg_string != NULL) + free(arg_string); + + if(parent_dir != ZERO) + UnLock(parent_dir); + + if(script_file != ZERO) + Close(script_file); + + if(interpreter_line != NULL) + free(interpreter_line); + + if(segment_list != ZERO) + UnLoadSeg(segment_list); + + if(success) + exit(result); + + return(result); +} diff --git a/library/unistd_execvp.c b/library/unistd_execvp.c new file mode 100644 index 0000000..539fb56 --- /dev/null +++ b/library/unistd_execvp.c @@ -0,0 +1,216 @@ +/* + * $Id: unistd_execvp.c,v 1.1 2006-08-01 14:27:52 obarthel Exp $ + * + * :ts=4 + * + * Portable ISO 'C' (1994) runtime library for the Amiga computer + * Copyright (c) 2002-2006 by Olaf Barthel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of Olaf Barthel nor the names of contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _UNISTD_HEADERS_H +#include "unistd_headers.h" +#endif /* _UNISTD_HEADERS_H */ + +/****************************************************************************/ + +/* The following is not part of the ISO 'C' (1994) standard. */ + +/****************************************************************************/ + +char ** __default_path_delimiter = ":"; +char ** __default_path = "/gcc/bin:/SDK/C:/SDK/Local/C:/C:."; + +/****************************************************************************/ + +/* A local version of the BSD strsep() function. */ +static char * +local_strsep(char ** string_ptr, const char * delimiter) +{ + char * result = NULL; + char * string; + + assert( string_ptr != NULL && delimiter != NULL ); + + string = (*string_ptr); + if(string != NULL) + { + char * token = string; + char c; + + while(TRUE) + { + c = (*string++); + + /* Reached the end of the string? */ + if(c == '\0') + { + /* No further string data available. */ + (*string_ptr) = NULL; + + result = token; + break; + } + + /* Is that character a delimiter? */ + if(strchr(delimiter,c) != NULL) + { + /* NUL-terminate the string, overwriting + the delimiter character */ + string[-1] = '\0'; + + /* Scanning can resume with the next following + character. */ + (*string_ptr) = string; + + result = token; + break; + } + } + } + + return(result); +} + +/****************************************************************************/ + +int +execvp(const char *command,char * const argv[]) +{ + char * command_buffer = NULL; + char * path_copy = NULL; + int result = -1; + char * bp; + + /* Do not allow null command */ + if(command == NULL || (*command) == '\0') + { + __set_errno(ENOENT); + goto out; + } + + /* If it's an absolute or relative path name, it's easy. */ + if(strchr(command,'/') != NULL || strchr(command,':') != NULL) + { + result = execve(command, argv, NULL /*environ*/); + } + else + { + size_t command_name_len = strlen(command); + size_t command_buffer_size = 0; + char * path_delimiter; + char * path; + char * search_prefix; + size_t search_prefix_len; + size_t complete_path_len; + int error; + + /* We first look up the PATH environment variable because + we will be making a copy of it. This avoids trouble + lateron when we will be calling getenv() again. */ + path = getenv("PATH"); + if(path == NULL) + path = __default_path; + + path_copy = strdup(path); + if(path_copy == NULL) + { + __set_errno(ENOMEM); + goto out; + } + + path = path_copy; + + path_delimiter = getenv("PATH_SEPARATOR"); + if(path_delimiter == NULL) + path_delimiter = __default_path_delimiter; + + while((search_prefix = local_strsep(&path,path_delimiter)) != NULL) + { + if((*search_prefix) == '\0') + search_prefix = "."; + + search_prefix_len = strlen(search_prefix); + + complete_path_len = search_prefix_len + 1 + command_name_len; + if(complete_path_len + 1 > command_buffer_size) + { + char * new_command_buffer; + + /* Allocate a little more memory than we + really need. */ + new_command_buffer = malloc(complete_path_len + 10); + if(new_command_buffer == NULL) + { + __set_errno(ENOMEM); + goto out; + } + + if(command_buffer != NULL) + free(command_buffer); + + command_buffer = new_command_buffer; + command_buffer_size = complete_path_len + 10; + } + + /* Combine the search prefix with the command name. */ + memcpy(command_buffer,search_prefix,search_prefix_len); + command_buffer[search_prefix_len] = '/'; + memcpy(&command_buffer[search_prefix_len+1],command,command_name_len); + command_buffer[complete_path_len] = '\0'; + + /* Now try to run that command. */ + result = execve(command_buffer, argv, NULL /*environ*/); + + /* Did it work? And if it didn't work, did it fail because + the command to be run could not be executed? */ + error = __get_errno(); + + if(result == 0 || + (error != EACCES && + error != EISDIR && + error != ENOENT && + error != ENOEXEC && + error != EPERM)) + { + break; + } + + /* Just in case somebody wants to quit... */ + __check_abort(); + } + } + + out: + + if(path_copy != NULL) + free(path_copy); + + if(command_buffer != NULL) + free(command_buffer); + + return(result); +}