Пример #1
0
void
daemon_t::_grandchild(
    pipe_t & c_pipe,
    pipe_t & g_pipe
) {

    try {

        c_pipe.writer().close();

        _init();

        // Initialization finished successfully -- let parent know everything is ok.
        g_pipe.writer().write( ok );
        g_pipe.writer().close();

    } catch ( std::exception const & ex ) {

        g_pipe.writer().write( string_t( ex.what() ) + "\n" );
        throw;

    } catch ( ... ) {

        g_pipe.writer().write( "Unknown exception occurred\n" );
        throw;

    }; // try

    _body();

}; // _grandchild
Пример #2
0
void
daemon_t::_child(
    pipe_t &    c_pipe,
    pipe_t &    g_pipe
) {

    try {

        int error = -1;

        c_pipe.reader().close();
        g_pipe.reader().close();

        // Reopen standard streams.
        // Associate all the standard streams with `/dev/null'.
        file_t null( * this );
        null.open( "/dev/null", O_RDONLY, 0 );
        error = dup2( null.fd(), STDIN_FILENO );
        SYSERR( error < 0, "dup2", "Reopening stdin" );
        null.close();
        null.open( "/dev/null", O_WRONLY, 0 );
        error = dup2( null.fd(), STDOUT_FILENO );
        SYSERR( error < 0, "dup2", "Reopening stdout" );
        error = dup2( null.fd(), STDERR_FILENO );
        SYSERR( error < 0, "dup2", "Reopening stderr" );
        null.close();

        pid_t sid = 0;

        ESYSCALL(
            "creating session",
            "setsid",
            sid = setsid(),
            sid > 0,
            "session " << sid << " created"
        );

        // Ignore unused signals.
        // We ignore signals in child so in grandchild these signals are fro the very beginning.
        // If daemon need any of these signals, it will handle them explicitly.
        thread_t::ignore_signal( SIGHUP   );
        thread_t::ignore_signal( SIGINT   );
        thread_t::ignore_signal( SIGQUIT  );
        thread_t::ignore_signal( SIGUSR1  );
        thread_t::ignore_signal( SIGUSR2  );
        thread_t::ignore_signal( SIGTERM  );
        thread_t::ignore_signal( SIGCHLD  );
        thread_t::ignore_signal( SIGTTIN  );
        thread_t::ignore_signal( SIGTTOU  );
        thread_t::ignore_signal( SIGWINCH );

        pid_t pid = 0;

        ESYSCALL(
            "forking grandchild process",
            "fork",
            pid = fork(),
            pid >= 0,
            "grandchild process forked " << ( pid == 0 ? "(i am grandchild)" : "(i am child)" )
        );

        if ( pid == 0 ) {
            _grandchild( c_pipe, g_pipe );
            return;         // TODO: or exit?
        }; // if

        g_pipe.writer().close();

        ESYSCALL(
            "anti-zombying grandchild",
            "waitpid",
            error = waitpid( pid, NULL, WNOHANG ),
            error != -1,
            "grandchild anti-zombied"
        );

        // We cannot just close pipe: on the parent end ir will be not clear if everything is ok
        // or child silently died. So let us write `ok' to the pipe -- parent will know that we
        // are really ok.
        c_pipe.writer().write( ok );

    } catch ( std::exception const & ex ) {

        c_pipe.writer().write( string_t( ex.what() ) + "\n" );

    } catch ( ... ) {

        c_pipe.writer().write( "Unknown exception occurred\n" );

    }; // try

    c_pipe.writer().close();

}; // _child