From 7abfbdde4f169137340536098b99eec9cc76acfe Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 23 Oct 2021 11:10:30 -0500 Subject: [PATCH] Update: Improve terminal support in execute functions. The init program calling bash results in "not a tty" error: - "bash: cannot set terminal process group (-1): Not a tty" - "bash: no job control in this shell" This exposed me to the Process Group. I have learned that I may need to set the Controlling Terminal in this case. To that end, I have introduced FL_execute_parameter_option_session_d for setting this up. I have also added an initial setup for FL_execute_parameter_option_terminal_d, but more investigation and research needs to be done. I've added some basic execute terminal codes that I may or may not need. I would rather have them now and remove them now rather than not have them and have to add them later. The controller program needs to utilize this, at least when running as "init". However, I believe that I should pass control over this to the user as new settings, such as "session new" and "session same". Provide example to utilize "setsid" program for doing this same thing when directly calling bash. --- level_0/f_execute/c/execute-common.h | 5 +++ level_0/f_execute/c/execute.c | 40 ++++++++++++++++++++++ level_0/f_execute/c/execute.h | 3 ++ level_1/fl_execute/c/execute-common.h | 22 ++++++------ level_2/fll_execute/c/execute.c | 4 +++ level_2/fll_execute/c/execute.h | 2 ++ level_2/fll_execute/c/private-execute.c | 9 ++++- level_3/controller/c/private-controller.c | 7 +++- level_3/controller/c/private-rule.c | 19 ++++++++++ .../controller/data/settings/entries/default.entry | 3 +- .../data/settings/entries/maintenance.entry | 3 +- .../data/settings/rules/maintenance/console.rule | 1 + 12 files changed, 104 insertions(+), 14 deletions(-) diff --git a/level_0/f_execute/c/execute-common.h b/level_0/f_execute/c/execute-common.h index 8f42c4f..a2f774f 100644 --- a/level_0/f_execute/c/execute-common.h +++ b/level_0/f_execute/c/execute-common.h @@ -59,6 +59,11 @@ extern "C" { F_execute_prohibited, F_execute_resource_not, F_execute_schedule, + F_execute_terminal, + F_execute_terminal_known_not, + F_execute_terminal_not, + F_execute_terminal_prohibited, + F_execute_terminal_valid_not, F_execute_too_large, F_execute_user, F_execute_valid_not, diff --git a/level_0/f_execute/c/execute.c b/level_0/f_execute/c/execute.c index 1b03ad3..15f5fc1 100644 --- a/level_0/f_execute/c/execute.c +++ b/level_0/f_execute/c/execute.c @@ -115,6 +115,26 @@ extern "C" { return F_execute_schedule; } + if (F_status_set_fine(status) == F_terminal) { + return F_execute_terminal; + } + + if (F_status_set_fine(status) == F_terminal_known_not) { + return F_execute_terminal_known_not; + } + + if (F_status_set_fine(status) == F_terminal_not) { + return F_execute_terminal_not; + } + + if (F_status_set_fine(status) == F_terminal_prohibited) { + return F_execute_terminal_prohibited; + } + + if (F_status_set_fine(status) == F_terminal_valid_not) { + return F_execute_terminal_valid_not; + } + if (F_status_set_fine(status) == F_too_large) { return F_execute_too_large; } @@ -242,6 +262,26 @@ extern "C" { return F_schedule; } + if (status == F_execute_terminal) { + return F_terminal; + } + + if (status == F_execute_terminal_known_not) { + return F_terminal_known_not; + } + + if (status == F_execute_terminal_not) { + return F_terminal_not; + } + + if (status == F_execute_terminal_prohibited) { + return F_terminal_prohibited; + } + + if (status == F_execute_terminal_valid_not) { + return F_terminal_valid_not; + } + if (status == F_execute_too_large) { return F_too_large; } diff --git a/level_0/f_execute/c/execute.h b/level_0/f_execute/c/execute.h index 0b72146..cc6369b 100644 --- a/level_0/f_execute/c/execute.h +++ b/level_0/f_execute/c/execute.h @@ -15,6 +15,9 @@ // libc includes #include +#include +#include +#include // fll-0 includes #include diff --git a/level_1/fl_execute/c/execute-common.h b/level_1/fl_execute/c/execute-common.h index 5bbf7e9..7aa4975 100644 --- a/level_1/fl_execute/c/execute-common.h +++ b/level_1/fl_execute/c/execute-common.h @@ -20,12 +20,12 @@ extern "C" { * A structure for containing additional parameters for the execute functions that call the execv() family of functions. * * FL_execute_parameter_option_*: - * - exit: used to desginate to exit after calling child otherwise child process will return. - * - path: used to designate that the full path to the program is to be passed in argument[0] instead of the program name (such as '/bin/bash' instead of 'bash'). - * - threadsafe: used to designate that threadsafe functions are to be used (such as: f_thread_signal_mask instead of f_signal_mask). - * - return: used to designate that the parent process will immediately return instead of waiting for the child process to complete. - * - * If thread support is disabled in the library, then FL_execute_parameter_option_threadsafe_d will fallback to non-threadsafe. + * - exit: Used to desginate to exit after calling child otherwise child process will return. + * - path: Used to designate that the full path to the program is to be passed in argument[0] instead of the program name (such as '/bin/bash' instead of 'bash'). + * - return: Used to designate that the parent process will immediately return instead of waiting for the child process to complete. + * - session: Start a new session, set the process of the child as the controlling terminal. + * - terminal: (Not Implemented) open() a terminal (tty) before executing. @todo determine if and how to setup the terminal properly (this needs research and planning and may require further structural changes). + * - threadsafe: Used to designate that threadsafe functions are to be used (such as: f_thread_signal_mask instead of f_signal_mask). * * option: Accepts the bitwise options * wait: Represents options passed to waitpid(), such as WUNTRACED. @@ -34,10 +34,12 @@ extern "C" { * data: The data to pipe to the child process, set to 0 to not use. */ #ifndef _di_fl_execute_parameter_t_ - #define FL_execute_parameter_option_exit_d 0x1 - #define FL_execute_parameter_option_path_d 0x2 - #define FL_execute_parameter_option_threadsafe_d 0x4 - #define FL_execute_parameter_option_return_d 0x8 + #define FL_execute_parameter_option_exit_d 0x1 + #define FL_execute_parameter_option_path_d 0x2 + #define FL_execute_parameter_option_return_d 0x4 + #define FL_execute_parameter_option_session_d 0x8 + #define FL_execute_parameter_option_terminal_d 0x10 + #define FL_execute_parameter_option_threadsafe_d 0x20 typedef struct { uint8_t option; diff --git a/level_2/fll_execute/c/execute.c b/level_2/fll_execute/c/execute.c index 3c10731..1798fca 100644 --- a/level_2/fll_execute/c/execute.c +++ b/level_2/fll_execute/c/execute.c @@ -148,6 +148,10 @@ extern "C" { int code = 0; + if (option & FL_execute_parameter_option_session_d) { + setsid(); + } + // full path is explicitly requested. if (option & FL_execute_parameter_option_path_d) { f_string_dynamic_t path = f_string_dynamic_t_initialize; diff --git a/level_2/fll_execute/c/execute.h b/level_2/fll_execute/c/execute.h index 0419960..f82ce22 100644 --- a/level_2/fll_execute/c/execute.h +++ b/level_2/fll_execute/c/execute.h @@ -363,6 +363,7 @@ extern "C" { * A bitwise set of options, such as: FL_execute_parameter_option_exit_d and FL_execute_parameter_option_path_d. * If FL_execute_parameter_option_exit_d: this will call exit() at the end of execution (be it success or failure). * If FL_execute_parameter_option_path_d: use the whole program path (such as "/bin/bash" instead "bash" when populating argument[0]. + * If FL_execute_parameter_option_session_d: will start a new session, setting process group id. * @param environment * (optional) An map of strings representing the environment variable names and their respective values. * Completely clears the environment and then creates environment variables for each name and value pair in this map. @@ -479,6 +480,7 @@ extern "C" { * @see memcpy() * @see nice() * @see pipe() + * @see setsid() * @see sched_setaffinity() * @see sched_setscheduler() * @see setgid() diff --git a/level_2/fll_execute/c/private-execute.c b/level_2/fll_execute/c/private-execute.c index 3cb1f1d..957c2e4 100644 --- a/level_2/fll_execute/c/private-execute.c +++ b/level_2/fll_execute/c/private-execute.c @@ -272,7 +272,6 @@ extern "C" { } if (id_process) { - if (as) { // close the read pipe for the parent. @@ -329,6 +328,10 @@ extern "C" { return F_none; } + if (parameter && parameter->option & FL_execute_parameter_option_session_d) { + setsid(); + } + if (as) { // close the write pipe for the child. @@ -520,6 +523,10 @@ extern "C" { return F_none; } + if (parameter && parameter->option & FL_execute_parameter_option_session_d) { + setsid(); + } + // close the write pipe for the child. close(descriptors[1]); diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index d75368d..7ae82ba 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -1194,8 +1194,13 @@ extern "C" { controller_thread_process_cancel(is_entry, is_entry ? controller_thread_cancel_execute : controller_thread_cancel_exit_execute, global, process); int result = 0; + int option = FL_execute_parameter_option_path_d; - status = fll_execute_into(0, entry_action->parameters, FL_execute_parameter_option_path_d, 0, (void *) &result); + if (global->main->as_init) { + option |= FL_execute_parameter_option_session_d; // @todo need "session new" and "session same". + } + + status = fll_execute_into(0, entry_action->parameters, option, 0, (void *) &result); if (F_status_is_error(status)) { if (F_status_set_fine(status) == F_file_found_not) { diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index 795a453..bfc81b1 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -1198,6 +1198,21 @@ extern "C" { else if (code == F_execute_schedule) { fl_print_format("%[' failed to setup scheduler.%]%c", print->to.stream, print->context, print->context, f_string_eol_s[0]); } + else if (code == F_execute_terminal) { + fl_print_format("%[' failed while processing the terminal.%]%c", print->to.stream, print->context, print->context, f_string_eol_s[0]); + } + else if (code == F_execute_terminal_known_not) { + fl_print_format("%[' cannot process terminal, unknown terminal control command.%]%c", print->to.stream, print->context, print->context, f_string_eol_s[0]); + } + else if (code == F_execute_terminal_not) { + fl_print_format("%[' cannot process terminal, not a known terminal.%]%c", print->to.stream, print->context, print->context, f_string_eol_s[0]); + } + else if (code == F_execute_terminal_prohibited) { + fl_print_format("%[' insufficient permissions to process the terminal.%]%c", print->to.stream, print->context, print->context, f_string_eol_s[0]); + } + else if (code == F_execute_terminal_valid_not) { + fl_print_format("%[' invalid parameter while processing the terminal.%]%c", print->to.stream, print->context, print->context, f_string_eol_s[0]); + } else if (code == F_execute_too_large) { fl_print_format("%[' too many arguments or arguments are too large.%]%c", print->to.stream, print->context, print->context, f_string_eol_s[0]); } @@ -1352,6 +1367,10 @@ extern "C" { execute_set.parameter.option |= FL_execute_parameter_option_path_d; } + if (global.main->as_init) { + execute_set.parameter.option |= FL_execute_parameter_option_session_d; // @todo need "session new" and "session same". + } + if (process->rule.items.array[i].type == controller_rule_item_type_command) { for (;;) { diff --git a/level_3/controller/data/settings/entries/default.entry b/level_3/controller/data/settings/entries/default.entry index 34da674..d2dd9ea 100644 --- a/level_3/controller/data/settings/entries/default.entry +++ b/level_3/controller/data/settings/entries/default.entry @@ -51,5 +51,6 @@ console: maintenance: - #execute /bin/agetty -8 -i -J - linux + #execute /bin/agetty -8 -i -J tty1 linux + #execute /bin/setsid -c /bin/bash --login execute /bin/bash --login diff --git a/level_3/controller/data/settings/entries/maintenance.entry b/level_3/controller/data/settings/entries/maintenance.entry index ab0c489..15a948b 100644 --- a/level_3/controller/data/settings/entries/maintenance.entry +++ b/level_3/controller/data/settings/entries/maintenance.entry @@ -8,5 +8,6 @@ setting: show init main: - #execute /bin/agetty -8 -i -J - linux + #execute /bin/agetty -8 -i -J tty1 linux + #execute /bin/setsid -c /bin/bash --login execute /bin/bash --login diff --git a/level_3/controller/data/settings/rules/maintenance/console.rule b/level_3/controller/data/settings/rules/maintenance/console.rule index 52e7b82..d230821 100644 --- a/level_3/controller/data/settings/rules/maintenance/console.rule +++ b/level_3/controller/data/settings/rules/maintenance/console.rule @@ -7,4 +7,5 @@ setting: name "Maintenance Console" command: + #start setsid -c bash --login start bash --login -- 1.8.3.1