Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af3a9cad authored by Rom Lemarchand's avatar Rom Lemarchand Committed by Android (Google) Code Review
Browse files

Merge "liblogwrap: use POLLHUP flag to check when a child dies" into jb-mr2-dev

parents 9feea559 6ad53df6
Loading
Loading
Loading
Loading
+49 −102
Original line number Original line Diff line number Diff line
@@ -17,7 +17,6 @@
#include <string.h>
#include <string.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <signal.h>
#include <poll.h>
#include <poll.h>
#include <sys/wait.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdio.h>
@@ -35,7 +34,6 @@


#define ARRAY_SIZE(x)   (sizeof(x) / sizeof(*(x)))
#define ARRAY_SIZE(x)   (sizeof(x) / sizeof(*(x)))


static int signal_fd_write;
static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;


#define ERROR(fmt, args...)                                                   \
#define ERROR(fmt, args...)                                                   \
@@ -50,45 +48,34 @@ do { \
    _exit(-1);                                                                \
    _exit(-1);                                                                \
} while(0)
} while(0)


static int parent(const char *tag, int parent_read, int signal_fd, pid_t pid,
static int parent(const char *tag, int parent_read, pid_t pid, int *chld_sts,
        int *chld_sts, bool logwrap) {
        bool logwrap) {
    int status = 0;
    int status = 0;
    char buffer[4096];
    char buffer[4096];
    struct pollfd poll_fds[] = {
    struct pollfd poll_fds[] = {
        [0] = {
        [0] = {
            .fd = signal_fd,
            .events = POLLIN,
        },
        [1] = {
            .fd = parent_read,
            .fd = parent_read,
            .events = POLLIN,
            .events = POLLIN,
        },
        },
    };
    };
    int rc = 0;
    int rc = 0;
    sigset_t chldset;


    int a = 0;  // start index of unprocessed data
    int a = 0;  // start index of unprocessed data
    int b = 0;  // end index of unprocessed data
    int b = 0;  // end index of unprocessed data
    int sz;
    int sz;
    bool remote_hung = false;
    bool found_child = false;
    bool found_child = false;


    char *btag = basename(tag);
    char *btag = basename(tag);
    if (!btag) btag = (char*) tag;
    if (!btag) btag = (char*) tag;


    sigemptyset(&chldset);
    sigaddset(&chldset, SIGCHLD);
    pthread_sigmask(SIG_UNBLOCK, &chldset, NULL);

    while (!found_child) {
    while (!found_child) {
        if (TEMP_FAILURE_RETRY(poll(poll_fds, remote_hung ? 1 : 2, -1)) < 0) {
        if (TEMP_FAILURE_RETRY(poll(poll_fds, ARRAY_SIZE(poll_fds), -1)) < 0) {
            ERROR("poll failed\n");
            ERROR("poll failed\n");
            rc = -1;
            rc = -1;
            goto err_poll;
            goto err_poll;
        }
        }


        if (!remote_hung) {
        if (poll_fds[0].revents & POLLIN) {
            if (poll_fds[1].revents & POLLIN) {
            sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b);
            sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b);


            sz += b;
            sz += b;
@@ -121,23 +108,17 @@ static int parent(const char *tag, int parent_read, int signal_fd, pid_t pid,
            }
            }
        }
        }


            if (poll_fds[1].revents & POLLHUP) {
        if (poll_fds[0].revents & POLLHUP) {
                remote_hung = true;
            }
        }

        if (poll_fds[0].revents & POLLIN) {
            char tmp[32];
            int ret;
            int ret;


            read(signal_fd, tmp, sizeof(tmp));
            ret = waitpid(pid, &status, WNOHANG);
            while (!found_child) {
            if (ret < 0) {
                ret = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
                rc = errno;

                ALOG(LOG_ERROR, "logwrap", "waitpid failed with %s\n", strerror(errno));
                if (ret <= 0)
                goto err_waitpid;
                    break;
            }

            if (ret > 0) {
                found_child = (pid == ret);
                found_child = true;
            }
            }
        }
        }
    }
    }
@@ -171,6 +152,7 @@ static int parent(const char *tag, int parent_read, int signal_fd, pid_t pid,
      }
      }
    }
    }


err_waitpid:
err_poll:
err_poll:
    return rc;
    return rc;
}
}
@@ -187,23 +169,16 @@ static void child(int argc, char* argv[], bool logwrap) {
    }
    }
}
}


static void sigchld_handler(int sig) {
    write(signal_fd_write, &sig, 1);
}

int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_quit,
int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_quit,
        bool logwrap) {
        bool logwrap) {
    pid_t pid;
    pid_t pid;
    int parent_ptty;
    int parent_ptty;
    int child_ptty;
    int child_ptty;
    char *child_devname = NULL;
    char *child_devname = NULL;
    struct sigaction chldact;
    struct sigaction oldchldact;
    struct sigaction intact;
    struct sigaction intact;
    struct sigaction quitact;
    struct sigaction quitact;
    sigset_t blockset;
    sigset_t blockset;
    sigset_t oldset;
    sigset_t oldset;
    int sockets[2];
    int rc = 0;
    int rc = 0;


    rc = pthread_mutex_lock(&fd_mutex);
    rc = pthread_mutex_lock(&fd_mutex);
@@ -227,14 +202,21 @@ int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_qui
        goto err_ptty;
        goto err_ptty;
    }
    }


    child_ptty = open(child_devname, O_RDWR);
    if (child_ptty < 0) {
        ERROR("Cannot open child_ptty\n");
        rc = -1;
        goto err_child_ptty;
    }

    sigemptyset(&blockset);
    sigemptyset(&blockset);
    sigaddset(&blockset, SIGINT);
    sigaddset(&blockset, SIGINT);
    sigaddset(&blockset, SIGQUIT);
    sigaddset(&blockset, SIGQUIT);
    sigaddset(&blockset, SIGCHLD);
    pthread_sigmask(SIG_BLOCK, &blockset, &oldset);
    pthread_sigmask(SIG_BLOCK, &blockset, &oldset);


    pid = fork();
    pid = fork();
    if (pid < 0) {
    if (pid < 0) {
        close(child_ptty);
        ERROR("Failed to fork\n");
        ERROR("Failed to fork\n");
        rc = -1;
        rc = -1;
        goto err_fork;
        goto err_fork;
@@ -243,12 +225,6 @@ int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_qui
        pthread_sigmask(SIG_SETMASK, &oldset, NULL);
        pthread_sigmask(SIG_SETMASK, &oldset, NULL);
        close(parent_ptty);
        close(parent_ptty);


        child_ptty = open(child_devname, O_RDWR);
        if (child_ptty < 0) {
            FATAL_CHILD("Problem with child ptty\n");
            return -1;
        }

        // redirect stdout and stderr
        // redirect stdout and stderr
        dup2(child_ptty, 1);
        dup2(child_ptty, 1);
        dup2(child_ptty, 2);
        dup2(child_ptty, 2);
@@ -256,55 +232,26 @@ int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_qui


        child(argc, argv, logwrap);
        child(argc, argv, logwrap);
    } else {
    } else {
        close(child_ptty);
        if (ignore_int_quit) {
            struct sigaction ignact;
            struct sigaction ignact;


        memset(&chldact, 0, sizeof(chldact));
        chldact.sa_handler = sigchld_handler;
        chldact.sa_flags = SA_NOCLDSTOP;

        sigaction(SIGCHLD, &chldact, &oldchldact);
        if ((!(oldchldact.sa_flags & SA_SIGINFO) &&
                oldchldact.sa_handler != SIG_DFL &&
                oldchldact.sa_handler != SIG_IGN) ||
                ((oldchldact.sa_flags & SA_SIGINFO) &&
                oldchldact.sa_sigaction != NULL)) {
            ALOG(LOG_WARN, "logwrapper", "logwrap replaced the SIGCHLD "
                    "handler and might cause interaction issues");
        }

        if (ignore_int_quit) {
            memset(&ignact, 0, sizeof(ignact));
            memset(&ignact, 0, sizeof(ignact));
            ignact.sa_handler = SIG_IGN;
            ignact.sa_handler = SIG_IGN;
            sigaction(SIGINT, &ignact, &intact);
            sigaction(SIGINT, &ignact, &intact);
            sigaction(SIGQUIT, &ignact, &quitact);
            sigaction(SIGQUIT, &ignact, &quitact);
        }
        }


        rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
        rc = parent(argv[0], parent_ptty, pid, status, logwrap);
        if (rc == -1) {
            ERROR("socketpair failed: %s\n", strerror(errno));
            goto err_socketpair;
        }

        fcntl(sockets[0], F_SETFD, FD_CLOEXEC);
        fcntl(sockets[0], F_SETFL, O_NONBLOCK);
        fcntl(sockets[1], F_SETFD, FD_CLOEXEC);
        fcntl(sockets[1], F_SETFL, O_NONBLOCK);

        signal_fd_write = sockets[0];

        rc = parent(argv[0], parent_ptty, sockets[1], pid, status, logwrap);
    }
    }


    close(sockets[0]);
    close(sockets[1]);
err_socketpair:
    if (ignore_int_quit) {
    if (ignore_int_quit) {
        sigaction(SIGINT, &intact, NULL);
        sigaction(SIGINT, &intact, NULL);
        sigaction(SIGQUIT, &quitact, NULL);
        sigaction(SIGQUIT, &quitact, NULL);
    }
    }
    sigaction(SIGCHLD, &oldchldact, NULL);
err_fork:
err_fork:
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
err_child_ptty:
err_ptty:
err_ptty:
    close(parent_ptty);
    close(parent_ptty);
err_open:
err_open: