From 3682b009b84ff4aae2f370a6e1b650767509eb3e Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Thu, 8 Mar 2012 19:27:55 -0600 Subject: [PATCH] Update: implement fll_execute_program and fix fll_execute_path This adds fll_execute_program and changes how fll_execute_path works to function properly. Prior to this change, fll_execute_path did not set the first argument which would cause the programs argv[0] to not be equivalent to the program name. This also corrects a few mistakes where level_1 syntax and comments were not changed to level_2. --- level_2/fll_execute/c/execute.c | 109 ++++++++++++++++++++++++++++++++++++---- level_2/fll_execute/c/execute.h | 5 +- 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/level_2/fll_execute/c/execute.c b/level_2/fll_execute/c/execute.c index 76a297e..8d941a2 100644 --- a/level_2/fll_execute/c/execute.c +++ b/level_2/fll_execute/c/execute.c @@ -1,12 +1,11 @@ -/* FLL - Level 1 +/* FLL - Level 2 * Project: Execute * Version: 0.3.x * Licenses: lgplv2.1 * Programmers: Kevin Day * Documentation: * - * Provides program execution operations similart to system() - * TODO: I should implement a function that will find the program based on PATH so that static paths do not have to be used + * Provides program execution operations similart to system(). */ #include @@ -16,30 +15,59 @@ extern "C"{ #ifndef _di_fll_execute_path_ f_return_status fll_execute_path(const f_string program_path, const f_dynamic_strings arguments, f_s_int *results){ - #ifndef _di_level_1_parameter_checking_ + #ifndef _di_level_2_parameter_checking_ if (results == f_null) return f_invalid_parameter; - if (arguments.used <= 0) return f_invalid_parameter; - if (arguments.used > arguments.size) return f_invalid_parameter; - #endif // _di_level_1_parameter_checking_ + if (arguments.used < 0) return f_invalid_parameter; + if (arguments.used > arguments.size) return f_invalid_parameter; + #endif // _di_level_2_parameter_checking_ // create a string array that is compatible with execv() calls f_status status = f_status_initialize; f_autochar **arguments_array = 0; - status = f_new_array((void **) & arguments_array, sizeof(f_autochar **), arguments.used + 1); + f_string last_slash = f_string_initialize; + f_string program_name = f_string_initialize; + f_string_length name_size = program_path; - if (f_macro_test_for_allocation_errors(status)) return status; + last_slash = strrchr(program_path, '/'); + + if (last_slash != f_null){ + name_size = strnlen(last_slash, PATH_MAX); + + if (name_size > 1){ + f_new_string(status, program_name, name_size + 1); + + if (f_macro_test_for_allocation_errors(status)) return status; + + memcpy(program_name, last_slash + 1, name_size); + memset(program_name, name_size, 0); + } else { + name_size = 0; + } + } + + status = f_new_array((void **) & arguments_array, sizeof(f_autochar **), arguments.used + 2); + + if (f_macro_test_for_allocation_errors(status)){ + f_status tmp_status = f_status_initialize; + + f_delete_string(tmp_status, program_name, name_size); + return status; + } { f_string_length counter = f_string_length_initialize; + arguments_array[0] = program_name; + counter++; + for (; counter < arguments.used; counter++){ arguments_array[counter] = arguments.array[counter].string; } // insert the required array terminated - arguments_array[arguments.used] = 0; + arguments_array[arguments.used + 1] = 0; } // TODO: validate that the file at program_path actually exists before attempting to fork and execute @@ -61,7 +89,8 @@ extern "C"{ // have the parent wait for the child process to finish waitpid(process_id, results, 0); - f_delete((void **) & arguments_array, sizeof(f_autochar), arguments.used + 1); + if (name_size > 0) f_delete_string(status, program_name, name_size); + f_delete((void **) & arguments_array, sizeof(f_autochar), arguments.used + 2); if (*results != 0) return f_failure; @@ -69,6 +98,64 @@ extern "C"{ } #endif // _di_fll_execute_path_ +#ifndef _di_fll_execute_program_ + f_return_status fll_execute_program(const f_string program_name, const f_dynamic_strings arguments, f_s_int *results){ + #ifndef _di_level_2_parameter_checking_ + if (results == f_null) return f_invalid_parameter; + + if (arguments.used < 0) return f_invalid_parameter; + if (arguments.used > arguments.size) return f_invalid_parameter; + #endif // _di_level_2_parameter_checking_ + + // create a string array that is compatible with execv() calls + f_status status = f_status_initialize; + f_autochar **arguments_array = 0; + + status = f_new_array((void **) & arguments_array, sizeof(f_autochar **), arguments.used + 2); + + if (f_macro_test_for_allocation_errors(status)) return status; + + { + f_string_length counter = f_string_length_initialize; + + arguments_array[0] = program_name; + counter++; + + for (; counter < arguments.used; counter++){ + arguments_array[counter] = arguments.array[counter].string; + } + + // insert the required array terminated + arguments_array[arguments.used + 1] = 0; + } + + // TODO: validate that the file at program_path actually exists before attempting to fork and execute + f_s_int process_id = 0; + + process_id = vfork(); + + if (process_id < 0){ + return f_fork_failed; + } + + if (process_id == 0){ // child + execvp(program_name, arguments_array); + + // according to manpages, calling _exit() is safer and should be called here instead of exit() + _exit(-1); + } + + // have the parent wait for the child process to finish + waitpid(process_id, results, 0); + + f_delete((void **) & arguments_array, sizeof(f_autochar), arguments.used + 2); + + if (*results != 0) return f_failure; + + return f_none; + } +#endif // _di_fll_execute_program_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_2/fll_execute/c/execute.h b/level_2/fll_execute/c/execute.h index 7011956..988f81e 100644 --- a/level_2/fll_execute/c/execute.h +++ b/level_2/fll_execute/c/execute.h @@ -14,6 +14,9 @@ #include #include #include +#include // defines PATH_MAX +#include +#include // fll-0 includes #include @@ -34,7 +37,7 @@ extern "C"{ #ifndef _di_fll_execute_program_ // This will find the program based on PATH environment so that static paths do not have to be used as with f_execute_path - extern f_return_status fll_execute_program(const f_string program_name, const f_string arguments[], f_s_int *results); + extern f_return_status fll_execute_program(const f_string program_name, const f_dynamic_strings arguments, f_s_int *results); #endif // _di_fll_execute_program_ #ifdef __cplusplus -- 1.8.3.1