I have been tossing around how exactly I want to implement the execute with piped data.
I have decided that I should clean up the parameters and redesign it to accept a few specialized structures.
Before I do that, I wanted to confirm that the pipe to shell (such as bash) works as I expect it to.
This tweaks the code to a temporary state where I can automatically execute some bash script with some string piped to it.
This seems to work as expected and errors out as expected.
I also need to write some asynchronous functions to help with managing asynchronous processes.
This might require a new series of projects (f_asynchronous, fl_asynchronous, etc..).
Note: "bash" was used as the default script, but I really need to provide some sort of configuration to change this.
#endif
/**
- * A set containing the standard descriptors for use in pipes during the execution process.
+ * A structure for use in processing asynchronous execute behavior.
*
* Future versions may suppot stdwarn and stddebug if there ever is such a thing.
*
* Descriptors always use -1 to designate not used because 0 represent a valid descriptor.
+ * The process ID always uses -1 to designate no valid process ID is set.
*
- * input: the input file descriptor.
- * output: the output file descriptor.
- * error: the error file descriptor.
+ * input: the input file descriptor.
+ * output: the output file descriptor.
+ * error: the error file descriptor.
+ * process: the process ID whereas 0 represents a parent and anything greater than 0 represents a child.
*/
-#ifndef _di_f_execute_pipe_t_
+#ifndef _di_f_execute_asynchronous_t_
typedef struct {
int input;
int output;
int error;
- } f_execute_pipe_t;
+ int process;
+ } f_execute_asynchronous_t;
- #define f_execute_pipe_t_initialize { -1, -1, -1 }
+ #define f_execute_asynchronous_t_initialize { -1, -1, -1, -1 }
- #define f_execute_pipe_t_clear(set) \
+ #define f_execute_asynchronous_t_clear(set) \
set.input = -1; \
set.output = -1; \
- set.error = -1;
-#endif // _di_f_execute_pipe_t_
+ set.error = -1; \
+ set.process = -1;
+#endif // _di_f_execute_asynchronous_t_
#ifdef __cplusplus
} // extern "C"
#endif // _di_fll_execute_arguments_dynamic_add_set_
#ifndef _di_fll_execute_path_
- f_return_status fll_execute_path(const f_string_t program_path, const f_string_statics_t arguments, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result) {
+ f_return_status fll_execute_path(const f_string_t program_path, const f_string_statics_t arguments, const f_signal_how_t *signals, f_string_static_t * const pipe, int *result) {
#ifndef _di_level_2_parameter_checking_
if (!result) return F_status_set_error(F_parameter);
#endif // _di_level_2_parameter_checking_
#endif // _di_fll_execute_path_
#ifndef _di_fll_execute_path_environment_
- f_return_status fll_execute_path_environment(const f_string_t program_path, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result) {
+ f_return_status fll_execute_path_environment(const f_string_t program_path, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_string_static_t * const pipe, int *result) {
#ifndef _di_level_2_parameter_checking_
if (!result) return F_status_set_error(F_parameter);
#endif // _di_level_2_parameter_checking_
#endif // _di_fll_execute_path_environment_
#ifndef _di_fll_execute_program_
- f_return_status fll_execute_program(const f_string_t program_name, const f_string_statics_t arguments, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result) {
+ f_return_status fll_execute_program(const f_string_t program_name, const f_string_statics_t arguments, const f_signal_how_t *signals, f_string_static_t * const pipe, int *result) {
#ifndef _di_level_2_parameter_checking_
if (!result) return F_status_set_error(F_parameter);
#endif // _di_level_2_parameter_checking_
#endif // _di_fll_execute_program_
#ifndef _di_fll_execute_program_environment_
- f_return_status fll_execute_program_environment(const f_string_t program_name, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result) {
+ f_return_status fll_execute_program_environment(const f_string_t program_name, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_string_static_t * const pipe, int *result) {
#ifndef _di_level_2_parameter_checking_
if (!result) return F_status_set_error(F_parameter);
#endif // _di_level_2_parameter_checking_
* This does validate that the program path exists.
*
* This does not call exit() when the child process exits.
- * Instead, this returns F_child and assigns the child's return code to result.
- * The caller is expected to handle the appropriate exit procedures and memory deallocation.
- *
- * When the passed pipe parameter is not NULL, this function is effectively asynchronous and will not block.
- * The caller is then expected to handle all read/write operations to/from the pipe.
- * The caller is expected to appropriately call waitpid() or similar as needed.
- * The caller is expected to handle both parent and child process (status is F_parent for parent and F_child for child.).
- * When the passed paremeter is NULL, then this function is effectively synchronous and blocks until child exits.
+ * Instead, this returns F_child and assigns the child's return code to result for the child process.
+ * The caller is expected to handle the appropriate exit procedures and memory deallocation for the child process.
*
* @param program_path
* The entire path to the program.
* (optional) A pointer to the set of signals.
* Set to 0 to disable.
* @param pipe
- * (optional) A pointer to the set of pipe desciptors (I/O) to be used by the child process.
- * When a non-zero address, the child process will assign these as the standard I/O file descriptors for piping to/from the parent/child.
- * For each pipe, setting a value of -1 means to use the default pipe.
+ * (optional) A pointer to a string to pipe as standard input to the child process.
* Set to 0 to disable.
* @param result
* The code returned after finishing execution of program_path.
* @return
* F_none on success.
* F_child on success but this is the child thread.
- * F_parent on success but this is the parent thread and pipe is non-zero (function is not blocking).
* F_failure (with error bit) on execution failure.
* F_fork (with error bit) on fork failure.
+ * F_pipe (with error bit) on pipe failure.
*
* Errors (with error bit) from: f_file_exists().
* Errors (with error bit) from: f_signal_set_handle().
*
+ * @see close()
* @see dup2()
* @see execv()
- * @see exit()
+ * @see execvp()
* @see fork()
- * @see memcpy()
- * @see strnlen()
+ * @see pipe()
* @see waitpid()
*
* @see f_file_exists()
* @see f_signal_set_handle()
*/
#ifndef _di_fll_execute_path_
- extern f_return_status fll_execute_path(const f_string_t program_path, const f_string_statics_t arguments, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result);
+ extern f_return_status fll_execute_path(const f_string_t program_path, const f_string_statics_t arguments, const f_signal_how_t *signals, f_string_static_t * const pipe, int *result);
#endif // _di_fll_execute_path_
/**
* Execute a program given some path + program name (such as "/bin/bash").
*
- * This does validate that the program path exists.
- *
+ * Uses the provided environment array to designate the environment for the program being executed.
* The environment is defined by the names and values pair.
*
- * This does not call exit() when the child process exits.
- * Instead, this returns F_child and assigns the child's return code to result.
- * The caller is expected to handle the appropriate exit procedures and memory deallocation.
+ * This does validate that the program path exists.
*
- * When the passed pipe parameter is not NULL, this function is effectively asynchronous and will not block.
- * The caller is then expected to handle all read/write operations to/from the pipe.
- * The caller is expected to appropriately call waitpid() or similar as needed.
- * The caller is expected to handle both parent and child process (status is F_parent for parent and F_child for child.).
- * When the passed paremeter is NULL, then this function is effectively synchronous and blocks until child exits.
+ * This does not call exit() when the child process exits.
+ * Instead, this returns F_child and assigns the child's return code to result for the child process.
+ * The caller is expected to handle the appropriate exit procedures and memory deallocation for the child process.
*
* @param program_path
* The entire path to the program.
* (optional) A pointer to the set of signals.
* Set to 0 to disable.
* @param pipe
- * (optional) A pointer to the set of pipe desciptors (I/O) to be used by the child process.
- * When a non-zero address, the child process will assign these as the standard I/O file descriptors for piping to/from the parent/child.
- * For each pipe, setting a value of -1 means to use the default pipe.
+ * (optional) A pointer to a string to pipe as standard input to the child process.
* Set to 0 to disable.
* @param result
* The code returned after finishing execution of program_path.
* @return
* F_none on success.
* F_child on success but this is the child thread.
- * F_parent on success but this is the parent thread and pipe is non-zero (function is not blocking).
* F_failure (with error bit) on execution failure.
* F_fork (with error bit) on fork failure.
+ * F_pipe (with error bit) on pipe failure.
*
* Errors (with error bit) from: f_environment_set_dynamic().
* Errors (with error bit) from: f_file_exists().
* Errors (with error bit) from: f_signal_set_handle().
*
+ * @see close()
* @see clearenv()
* @see dup2()
- * @see execv()
+ * @see execvp()
* @see fork()
* @see memcpy()
+ * @see pipe()
* @see strnlen()
* @see waitpid()
*
* @see f_signal_set_handle()
*/
#ifndef _di_fll_execute_path_environment_
- extern f_return_status fll_execute_path_environment(const f_string_t program_path, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result);
+ extern f_return_status fll_execute_path_environment(const f_string_t program_path, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_string_static_t * const pipe, int *result);
#endif // _di_fll_execute_path_environment_
/**
* This does not validate the path to the program.
*
* This does not call exit() when the child process exits.
- * Instead, this returns F_child and assigns the child's return code to result.
- * The caller is expected to handle the appropriate exit procedures and memory deallocation.
- *
- * When the passed pipe parameter is not NULL, this function is effectively asynchronous and will not block.
- * The caller is then expected to handle all read/write operations to/from the pipe.
- * The caller is expected to appropriately call waitpid() or similar as needed.
- * The caller is expected to handle both parent and child process (status is F_parent for parent and F_child for child.).
- * When the passed paremeter is NULL, then this function is effectively synchronous and blocks until child exits.
+ * Instead, this returns F_child and assigns the child's return code to result for the child process.
+ * The caller is expected to handle the appropriate exit procedures and memory deallocation for the child process.
*
* @param program_name
* The name of the program.
* (optional) A pointer to the set of signals.
* Set to 0 to disable.
* @param pipe
- * (optional) A pointer to the set of pipe desciptors (I/O) to be used by the child process.
- * When a non-zero address, the child process will assign these as the standard I/O file descriptors for piping to/from the parent/child.
- * For each pipe, setting a value of -1 means to use the default pipe.
+ * (optional) A pointer to a string to pipe as standard input to the child process.
* Set to 0 to disable.
* @param result
* The code returned after finishing execution of program.
* @return
* F_none on success.
* F_child on success but this is the child thread.
- * F_parent on success but this is the parent thread and pipe is non-zero (function is not blocking).
* F_failure (with error bit) on execution failure.
* F_fork (with error bit) on fork failure.
+ * F_pipe (with error bit) on pipe failure.
*
* Errors (with error bit) from: f_file_exists().
* Errors (with error bit) from: f_signal_set_handle().
*
+ * @see close()
* @see dup2()
+ * @see execv()
* @see execvp()
* @see fork()
- * @see strnlen()
+ * @see pipe()
* @see waitpid()
*
* @see f_file_exists()
* @see f_signal_set_handle()
*/
#ifndef _di_fll_execute_program_
- extern f_return_status fll_execute_program(const f_string_t program_name, const f_string_statics_t arguments, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result);
+ extern f_return_status fll_execute_program(const f_string_t program_name, const f_string_statics_t arguments, const f_signal_how_t *signals, f_string_static_t * const pipe, int *result);
#endif // _di_fll_execute_program_
/**
* Execute a program given by name found in the PATH environment (such as "bash").
*
- * Uses the provided environment array to designate the environment for the called program.
- *
- * This does validate the path to the program because it completes the path to the program.
- * This is done because the PATH environment will get cleared or may be set differently.
- * Execution of program_name is done using the PATH environment prior to clearing and reassigning the environment variables.
+ * Uses the provided environment array to designate the environment for the program being executed.
+ * The environment is defined by the names and values pair.
*
- * Unlike the execv() family of functions, this does not call exit() when the child process exits.
- * Instead, this returns F_child and assigns the child's return code to result.
- * The caller is expected to handle the appropriate exit procedures and memory deallocation.
+ * This does not validate the path to the program.
*
- * When the passed pipe parameter is not NULL, this function is effectively asynchronous and will not block.
- * The caller is then expected to handle all read/write operations to/from the pipe.
- * The caller is expected to appropriately call waitpid() or similar as needed.
- * The caller is expected to handle both parent and child process (status is F_parent for parent and F_child for child.).
- * When the passed paremeter is NULL, then this function is effectively synchronous and blocks until child exits.
+ * This does not call exit() when the child process exits.
+ * Instead, this returns F_child and assigns the child's return code to result for the child process.
+ * The caller is expected to handle the appropriate exit procedures and memory deallocation for the child process.
*
* @param program_name
* The name of the program.
* (optional) A pointer to the set of signals.
* Set to 0 to disable.
* @param pipe
- * (optional) A pointer to the set of pipe desciptors (I/O) to be used by the child process.
- * When a non-zero address, the child process will assign these as the standard I/O file descriptors for piping to/from the parent/child.
- * For each pipe, setting a value of -1 means to use the default pipe.
+ * (optional) A pointer to a string to pipe as standard input to the child process.
* Set to 0 to disable.
* @param result
* The code returned after finishing execution of program.
* @return
* F_none on success.
* F_child on success but this is the child thread.
- * F_parent on success but this is the parent thread and pipe is non-zero (function is not blocking).
* F_failure (with error bit) on execution failure.
* F_fork (with error bit) on fork failure.
+ * F_pipe (with error bit) on pipe failure.
*
* Errors (with error bit) from: f_environment_get().
* Errors (with error bit) from: f_file_exists().
* Errors (with error bit) from: fl_string_append().
* Errors (with error bit) from: fl_string_dynamic_terminate().
*
+ * @see close()
* @see clearenv()
* @see dup2()
* @see execvp()
* @see fork()
* @see memcpy()
+ * @see pipe()
* @see strnlen()
* @see waitpid()
*
* @see fl_string_dynamic_terminate()
*/
#ifndef _di_fll_execute_program_environment_
- extern f_return_status fll_execute_program_environment(const f_string_t program_name, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result);
+ extern f_return_status fll_execute_program_environment(const f_string_t program_name, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_string_static_t * const pipe, int *result);
#endif // _di_fll_execute_program_environment_
#ifdef __cplusplus
#endif // !defined(_di_fll_execute_arguments_add_parameter_) || !defined(_di_fll_execute_arguments_add_parameter_set_) || !defined(_di_fll_execute_arguments_dynamic_add_parameter_) || !defined(_di_fll_execute_arguments_dynamic_add_parameter_set_)
#if !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_program_)
- f_return_status private_fll_execute_fork(const f_string_t program_path, const f_string_t fixed_arguments[], const bool program_is, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result) {
+ f_return_status private_fll_execute_fork(const f_string_t program_path, const f_string_t fixed_arguments[], const bool program_is, const f_signal_how_t *signals, f_string_static_t * const pipe_data, int *result) {
+
+ int descriptors[2] = { -1, -1 };
+
+ if (pipe_data) {
+ if (pipe(descriptors) == -1) {
+ return F_status_set_error(F_pipe);
+ }
+ }
const pid_t process_id = fork();
if (process_id < 0) {
+
+ if (pipe_data) {
+ close(descriptors[0]);
+ close(descriptors[1]);
+ }
+
return F_status_set_error(F_fork);
}
if (process_id) {
- if (pipe) {
- return F_parent;
- }
+
+ // close the read pipe for the parent.
+ close(descriptors[0]);
}
else {
+ // close the write pipe for the child.
+ close(descriptors[1]);
+
if (signals) {
f_signal_set_handle(SIG_BLOCK, &signals->block);
f_signal_set_handle(SIG_UNBLOCK, &signals->block_not);
}
- if (pipe) {
- if (pipe->input != -1) {
- dup2(pipe->input, f_type_descriptor_input);
- }
-
- if (pipe->output != -1) {
- dup2(pipe->input, f_type_descriptor_output);
- }
-
- if (pipe->error != -1) {
- dup2(pipe->error, f_type_descriptor_error);
- }
+ if (pipe_data) {
+ dup2(descriptors[0], f_type_descriptor_input);
}
const int code = program_is ? execvp(program_path, fixed_arguments) : execv(program_path, fixed_arguments);
+ // close the write pipe for the child when done.
+ if (pipe_data) {
+ close(descriptors[0]);
+ }
+
if (result) {
*result = code;
}
return F_child;
}
+ // write all data, if child doesn't read this could block until child closes the pipe.
+ if (pipe_data) {
+ const f_file_t file = f_macro_file_t_initialize(0, descriptors[1], f_file_flag_write_only);
+
+ f_file_write(file, *pipe_data, 0);
+
+ // close the write pipe for the parent when finished writing.
+ close(descriptors[1]);
+ }
+
// have the parent wait for the child process to finish.
waitpid(process_id, result, WUNTRACED | WCONTINUED);
#endif // !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_program_)
#if !defined(_di_fll_execute_path_environment_) || !defined(_di_fll_execute_program_environment_)
- f_return_status private_fll_execute_fork_environment(const f_string_t program_path, const f_string_t fixed_arguments[], const bool program_is, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result) {
+ f_return_status private_fll_execute_fork_environment(const f_string_t program_path, const f_string_t fixed_arguments[], const bool program_is, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_string_static_t * const pipe_data, int *result) {
+
+ int descriptors[2] = { -1, -1 };
+
+ if (pipe_data) {
+ if (pipe(descriptors) == -1) {
+ return F_status_set_error(F_pipe);
+ }
+ }
const pid_t process_id = fork();
if (process_id < 0) {
+
+ if (pipe_data) {
+ close(descriptors[0]);
+ close(descriptors[1]);
+ }
+
return F_status_set_error(F_fork);
}
if (process_id) {
- if (pipe) {
- return F_parent;
- }
+
+ // close the read pipe for the parent.
+ close(descriptors[0]);
}
else {
+
+ // close the write pipe for the child.
+ close(descriptors[1]);
+
if (signals) {
f_signal_set_handle(SIG_BLOCK, &signals->block);
f_signal_set_handle(SIG_UNBLOCK, &signals->block_not);
f_environment_set_dynamic(names.array[i], values.array[i], F_true);
} // for
- if (pipe) {
- if (pipe->input != -1) {
- dup2(pipe->input, f_type_descriptor_input);
- }
-
- if (pipe->output != -1) {
- dup2(pipe->input, f_type_descriptor_output);
- }
-
- if (pipe->error != -1) {
- dup2(pipe->error, f_type_descriptor_error);
- }
+ if (pipe_data) {
+ dup2(descriptors[0], f_type_descriptor_input);
}
const int code = program_is ? execvp(program_path, fixed_arguments) : execv(program_path, fixed_arguments);
+ // close the write pipe for the child when done.
+ if (pipe_data) {
+ close(descriptors[0]);
+ }
+
if (result) {
*result = code;
}
return F_child;
}
+ // write all data, if child doesn't read this could block until child closes the pipe.
+ if (pipe_data) {
+ const f_file_t file = f_macro_file_t_initialize(0, descriptors[1], f_file_flag_write_only);
+
+ f_file_write(file, *pipe_data, 0);
+
+ // close the write pipe for the parent when finished writing.
+ close(descriptors[1]);
+ }
+
// have the parent wait for the child process to finish.
waitpid(process_id, result, WUNTRACED | WCONTINUED);
* @param set_signal
* (optional) A pointer to the set of signals.
* Set to 0 to disable.
- * @param pipe
- * (optional) A pointer to the set of pipe desciptors (I/O) to be used by the child process.
- * When a non-zero address, the child process will assign these as the standard I/O file descriptors for piping to/from the parent/child.
- * For each pipe, setting a value of -1 means to use the default pipe.
+ * @param pipe_data
+ * (optional) A pointer to a string to pipe as standard input to the child process.
* Set to 0 to disable.
* @param result
* The code returned after finishing execution of program_path.
* @return
* F_none on success.
* F_child on success but this is the child thread.
- * F_parent on success but this is the parent thread and pipe is non-zero (function is not blocking).
* F_failure (with error bit) on execution failure.
* F_fork (with error bit) on fork failure.
+ * F_pipe (with error bit) on pipe failure.
*
+ * @see close()
+ * @see dup2()
* @see execv()
* @see execvp()
+ * @see fork()
+ * @see pipe()
+ * @see waitpid()
+ *
* @see fll_execute_path()
* @see fll_execute_program()
*/
#if !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_program_)
- extern f_return_status private_fll_execute_fork(const f_string_t program_path, const f_string_t fixed_arguments[], const bool program_is, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result) f_gcc_attribute_visibility_internal;
+ extern f_return_status private_fll_execute_fork(const f_string_t program_path, const f_string_t fixed_arguments[], const bool program_is, const f_signal_how_t *signals, f_string_static_t * const pipe_data, int *result) f_gcc_attribute_visibility_internal;
#endif // !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_program_)
/**
* @param signals
* (optional) A pointer to the set of signals.
* Set to 0 to disable.
- * @param pipe
- * (optional) A pointer to the set of pipe desciptors (I/O) to be used by the child process.
- * When a non-zero address, the child process will assign these as the standard I/O file descriptors for piping to/from the parent/child.
- * For each pipe, setting a value of -1 means to use the default pipe.
+ * @param pipe_data
+ * (optional) A pointer to a string to pipe as standard input to the child process.
* Set to 0 to disable.
* @param result
* The code returned after finishing execution of program_path.
* @return
* F_none on success.
* F_child on success but this is the child thread.
- * F_parent on success but this is the parent thread and pipe is non-zero (function is not blocking).
* F_failure (with error bit) on execution failure.
* F_fork (with error bit) on fork failure.
+ * F_pipe (with error bit) on pipe failure.
+ *
+ * @see close()
+ * @see clearenv()
+ * @see dup2()
+ * @see execvp()
+ * @see fork()
+ * @see memcpy()
+ * @see pipe()
+ * @see strnlen()
+ * @see waitpid()
*
- * @see execv()
- * @see execvpe()
* @see fll_execute_path_environment()
* @see fll_execute_program_environment()
*/
#if !defined(_di_fll_execute_path_environment_) || !defined(_di_fll_execute_program_environment_)
- extern f_return_status private_fll_execute_fork_environment(const f_string_t program_path, const f_string_t fixed_arguments[], const bool program_is, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_execute_pipe_t * const pipe, int *result) f_gcc_attribute_visibility_internal;
+ extern f_return_status private_fll_execute_fork_environment(const f_string_t program_path, const f_string_t fixed_arguments[], const bool program_is, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, f_string_static_t * const pipe_data, int *result) f_gcc_attribute_visibility_internal;
#endif // !defined(_di_fll_execute_path_environment_) || !defined(_di_fll_execute_program_environment_)
/**
// fll-2 includes
#include <level_2/error.h>
+#include <level_2/execute.h>
#include <level_2/fss.h>
#include <level_2/fss_basic_list.h>
#include <level_2/fss_extended.h>
#define controller_string_action "action"
#define controller_string_actions "actions"
#define controller_string_asynchronous "asynchronous"
+ #define controller_string_bash "bash"
#define controller_string_create "create"
#define controller_string_command "command"
#define controller_string_consider "consider"
#define controller_string_action_length 6
#define controller_string_actions_length 7
#define controller_string_asynchronous_length 12
+ #define controller_string_bash_length 4
#define controller_string_create_length 6
#define controller_string_command_length 7
#define controller_string_consider_length 8
#endif // _di_controller_rule_error_need_want_wish_print_
#ifndef _di_controller_rule_execute_
- f_return_status controller_rule_execute(const controller_cache_t cache, const f_array_length_t index, const uint8_t action, controller_data_t *data, controller_setting_t *setting) {
+ f_return_status controller_rule_execute(const controller_cache_t cache, const f_array_length_t index, const uint8_t type, controller_data_t *data, controller_setting_t *setting) {
+ f_status_t status = F_none;
f_array_length_t i = 0;
f_array_length_t j = 0;
f_array_length_t k = 0;
- controller_rule_item_t *rule_item = 0;
- controller_rule_action_t *rule_action = 0;
+ controller_rule_item_t *item = 0;
+ controller_rule_action_t *action = 0;
for (i = 0; i < setting->rules.array[index].items.used; ++i) {
if (setting->rules.array[index].items.array[i].type == controller_rule_item_type_setting) continue;
- rule_item = &setting->rules.array[index].items.array[i];
+ item = &setting->rules.array[index].items.array[i];
- for (j = 0; j < rule_item->actions.used; ++j) {
+ for (j = 0; j < item->actions.used; ++j) {
- if (rule_item->actions.array[j].type != action) continue;
+ if (item->actions.array[j].type != type) continue;
- rule_action = &rule_item->actions.array[j];
+ action = &item->actions.array[j];
+ status = F_none;
- if (rule_item->type == controller_rule_item_type_command) {
- if (rule_action->method == controller_rule_action_method_extended) {
+ if (item->type == controller_rule_item_type_command) {
+ if (action->method == controller_rule_action_method_extended) {
// @todo
}
else {
// @todo extended list execution.
}
}
- else if (rule_item->type == controller_rule_item_type_script) {
- if (rule_action->method == controller_rule_action_method_extended) {
- // @todo
- }
- else {
- // @todo extended list execution.
- }
+ else if (item->type == controller_rule_item_type_script) {
+ status = controller_rule_execute_script(*action, 0, data);
+ if (F_status_is_error(status)) break;
}
- else if (rule_item->type == controller_rule_item_type_service) {
- if (rule_action->method == controller_rule_action_method_extended) {
+ else if (item->type == controller_rule_item_type_service) {
+ if (action->method == controller_rule_action_method_extended) {
// @todo
}
else {
// unknown, just ignore for now. (@todo print a warning when in debug mode.)
continue;
}
+
+ if (status == F_child || status == F_signal) break;
} // for
+
+ if (status == F_child || status == F_signal) break;
} // for
- return F_none;
+ return status;
}
#endif // _di_controller_rule_execute_
#ifndef _di_controller_rule_execute_script_
- f_return_status controller_rule_execute_script(const controller_rule_action_t action, controller_data_t *data) {
+ f_return_status controller_rule_execute_script(const controller_rule_action_t action, const uint8_t options, controller_data_t *data) {
// child processes should receive all signals, without blocking.
f_signal_how_t signals = f_signal_how_t_initialize;
f_signal_set_empty(&signals.block);
f_signal_set_fill(&signals.block_not);
- f_execute_pipe_t pipe = f_execute_pipe_t_initialize;
+ int result = 0;
- f_status_t status = F_none;
- //f_status_t status = fll_execute_program_environment(program.string, arguments, environment.names, environment.values, &signals, &pipe, &data->child);
+ const f_string_dynamics_t arguments = f_string_dynamics_t_initialize;
+
+ // @todo script program (such as: "bash") should be configurable somehow (a new entry setting? a new rule setting? both?).
+ // @todo have the environment variables built before executing the script and then instead call fll_execute_program_environment() for all execute functions (with environment.names, environment.values).
+ f_status_t status = fll_execute_program(controller_string_bash, arguments, &signals, action.parameters.used ? &action.parameters.array[0] : 0, &result);
if (status == F_child) {
- // @todo wait for parent pipe.
- // @todo how do I get status code? there will likely need to be more changes to fll_execute_program_environment()...
+ data->child = result;
+
return F_child;
}
- // parent process should print to the pipe.
-
// @todo handle errors, print messages, etc..
- if (data->child != 0) {
+ if (result != 0) {
status = F_status_set_error(F_failure);
}
else if (F_status_is_error(status)) {
+ fll_error_print(data->error, F_status_set_fine(status), "fll_execute_program_environment", F_true);
+ return status;
}
data->child = 0;
if (F_status_is_error(status)) {
fll_error_print(data->error, F_status_set_fine(status), "controller_rule_execute", F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
}
if (status == F_child) {
* A structure for containing and caching relevant data.
* @param index
* The position in the setting.rules array representing the rule to simulate.
- * @param action
+ * @param type
* The action to perform based on the action type codes.
*
* Only subset of the action type codes are supported:
* On failure, the individual status for the rule is set to an appropriate error status.
*/
#ifndef _di_controller_rule_execute_
- extern f_return_status controller_rule_execute(const controller_cache_t cache, const f_array_length_t index, const uint8_t action, controller_data_t *data, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
+ extern f_return_status controller_rule_execute(const controller_cache_t cache, const f_array_length_t index, const uint8_t type, controller_data_t *data, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
#endif // _di_controller_rule_execute_
/**
+ * Perform an execution of the given rule for the script execution type.
+ *
+ * @param action
+ * The action to perform based on the action type codes.
+ *
+ * Only subset of the action type codes are supported:
+ * - controller_rule_action_type_kill
+ * - controller_rule_action_type_reload
+ * - controller_rule_action_type_restart
+ * - controller_rule_action_type_start
+ * - controller_rule_action_type_stop
+ * @param options
+ * The execute options.
+ * @param data
+ * The program data.
+ *
+ * @return
+ * F_none on success.
+ * F_child on child process exiting.
+ * F_signal on (exit) signal received.
+ *
+ * Errors (with error bit) from: fll_execute_program().
+ *
+ * @see fll_execute_program()
+ */
+#ifndef _di_controller_rule_execute_script_
+ extern f_return_status controller_rule_execute_script(const controller_rule_action_t action, const uint8_t options, controller_data_t *data) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_execute_script_
+
+/**
* Search the already loaded rules to see if one is found.
*
* @param data
fl_string
fl_type
fll_error
+fll_execute
fll_fss
fll_path
fll_program
build_indexer ar
build_language c
build_libraries -lc
-build_libraries-individual -lfll_error -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_conversion -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_type -lf_console -lf_conversion -lf_directory -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf
+build_libraries-individual -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_conversion -lfl_environment -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_type -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf
build_libraries-level -lfll_2 -lfll_1 -lfll_0
build_libraries-monolithic -lfll
build_sources_library controller.c private-control.c private-controller.c private-entry.c private-rule.c