[PATCH 1/1] init: disable init actions that failed to open the TTY

Denys Vlasenko vda.linux at googlemail.com
Thu Feb 10 10:41:35 UTC 2011


On Wed, Feb 9, 2011 at 1:27 PM, Carmelo AMOROSO <carmelo.amoroso at st.com> wrote:
> On 2/7/2011 9:49 AM, Carmelo Amoroso wrote:

I don't see your first email in my inbox. Google also doesn't.

>> Add a new configurable feature that allow the init to disable
>> actions of type ASKFIRST and RESPAWN that have failed to open
>> the TTY preventing to make them looping forever.
>> If a SIGHUP is sent to init to reload the inittab, the processes
>> linked to these action are enabled again to give them another chance
>> to run.
>> This feature can be enabled by switching on CONFIG_FEATURE_DESCHEDULE_ON_TTY_FAIL.
>>
>> Signed-off-by: Carmelo Amoroso <carmelo.amoroso at st.com>
>> ---
>> init/init.c | 38 ++++++++++++++++++++++++++++++++------
>> 1 files changed, 32 insertions(+), 6 deletions(-)
>>
>> diff --git a/init/init.c b/init/init.c
>> index 586e34a..2367939 100644
>> --- a/init/init.c
>> +++ b/init/init.c
>> @@ -37,6 +37,16 @@
>> //config: sent to init, this option will make init kill the processes
>> //config: that have been removed.
>> //config:
>> +//config:config FEATURE_DESCHEDULE_ON_TTY_FAIL
>> +//config: bool "Support descheduling processes that have failed in opening TTYs"
>> +//config: default n
>> +//config: depends on FEATURE_USE_INITTAB
>> +//config: help
>> +//config: When respawn entries failed at opening a TTY, this option will make init
>> +//config: to disable the processes preventing to loop forever.
>> +//config: If a SIGHUP is sent to init to reload the inittab, these processes
>> +//config: are enabled again to give them a new chance to run.
>> +//config:
>> //config:config FEATURE_KILL_DELAY
>> //config: int "How long to wait between TERM and KILL (0 - send TERM only)" if
>> FEATURE_KILL_REMOVED
>> //config: range 0 1024
>> @@ -182,6 +192,7 @@ struct init_action {
>> struct init_action *next;
>> pid_t pid;
>> uint8_t action_type;
>> + uint8_t disabled;
>> char terminal[CONSOLE_NAME_SIZE];
>> char command[COMMAND_SIZE];
>> };
>> @@ -568,10 +579,10 @@ static void run_actions(int action_type)
>> waitfor(pid);
>> }
>> if (a->action_type & (RESPAWN | ASKFIRST)) {
>> - /* Only run stuff with pid == 0. If pid != 0,
>> + /* Only run stuff with pid == 0 and enabled. If pid != 0,
>> * it is already running
>> */
>> - if (a->pid == 0)
>> + if (a->pid == 0 && !a->disabled)
>> a->pid = run(a);
>> }
>> }
>> @@ -884,9 +895,11 @@ static void reload_inittab(void)
>>
>> message(L_LOG, "reloading /etc/inittab");
>>
>> - /* Disable old entries */
>> - for (a = init_action_list; a; a = a->next)
>> + /* Disable old entries and reset enable status */
>> + for (a = init_action_list; a; a = a->next) {
>> a->action_type = 0;
>> + a->disabled = 0;
>> + }
>>
>> /* Append new entries, or modify existing entries
>> * (incl. setting a->action_type) if cmd and device name
>> @@ -1134,20 +1147,33 @@ int init_main(int argc UNUSED_PARAM, char **argv)
>> while (1) {
>> pid_t wpid;
>> struct init_action *a;
>> + int status;
>>
>> /* If signals happen _in_ the wait, they interrupt it,
>> * bb_signals_recursive_norestart set them up that way
>> */
>> - wpid = waitpid(-1, NULL, maybe_WNOHANG);
>> + wpid = waitpid(-1, &status, maybe_WNOHANG);
>> if (wpid <= 0)
>> break;
>>
>> a = mark_terminated(wpid);
>> - if (a) {
>> +#ifdef ENABLE_FEATURE_DESCHEDULE_ON_TTY_FAIL
>> + if(WIFEXITED(status) && (WEXITSTATUS(status) == EXIT_FAILURE))
>> + /* Mark the action as disabled, so they will not be restarted */
>> + a->disabled = 1;
>> +#endif

You don't check for death from signal, and for some reason
treat only exitcode of 1 as error, not any !0 exitcode.

But more generally, as I see it, non-zero exit does not mean
that there is a problem with opening of tty.
It may be the result of any number of errors.

A better solution would be to detect open_stdio_to_tty errors.
See run() function:

        if (BB_MMU && (a->action_type & ASKFIRST))
                pid = fork();
        else
                pid = vfork();
        if (pid < 0)
                message(L_LOG | L_CONSOLE, "can't fork");
        if (pid) {
                sigprocmask_allsigs(SIG_UNBLOCK);
                return pid; /* Parent or error */
        }

        /* Child */

        /* Reset signal handlers that were set by the parent process */
        reset_sighandlers_and_unblock_sigs();

        /* Create a new session and make ourself the process group leader */
        setsid();

        /* Open the new terminal device */
        if (!open_stdio_to_tty(a->terminal))
                _exit(EXIT_FAILURE);
        ...

If open_stdio_to_tty's error path would set a volatile on-stack error flag
variable and exit, and parent would check it, then parent can
reliably detect tty open errors and decide to disable this inittab entry.

-- 
vda


More information about the busybox mailing list