static int run_as(enum run_as_cmd cmd, struct run_as_data *data, uid_t uid, gid_t gid) { int ret; if (use_clone()) { DBG("Using run_as worker"); pthread_mutex_lock(&worker_lock); assert(global_worker); ret = run_as_cmd(global_worker, cmd, data, uid, gid); pthread_mutex_unlock(&worker_lock); } else { DBG("Using run_as without worker"); ret = run_as_noworker(cmd, data, uid, gid); } return ret; }
static int run_as(enum run_as_cmd cmd, struct run_as_data *data, struct run_as_ret *ret_value, uid_t uid, gid_t gid) { int ret, saved_errno; pthread_mutex_lock(&worker_lock); if (use_clone()) { DBG("Using run_as worker"); assert(global_worker); ret = run_as_cmd(global_worker, cmd, data, ret_value, uid, gid); saved_errno = ret_value->_errno; /* * If the worker thread crashed the errno is set to EIO. we log * the error and start a new worker process. */ if (ret == -1 && saved_errno == EIO) { DBG("Socket closed unexpectedly... " "Restarting the worker process"); ret = run_as_restart_worker(global_worker); if (ret == -1) { ERR("Failed to restart worker process."); goto err; } } } else { DBG("Using run_as without worker"); ret = run_as_noworker(cmd, data, ret_value, uid, gid); } err: pthread_mutex_unlock(&worker_lock); return ret; }
static int run_as_create_worker_no_lock(const char *procname, post_fork_cleanup_cb clean_up_func, void *clean_up_user_data) { pid_t pid; int i, ret = 0; ssize_t readlen; struct run_as_ret recvret; struct run_as_worker *worker; assert(!global_worker); if (!use_clone()) { /* * Don't initialize a worker, all run_as tasks will be performed * in the current process. */ ret = 0; goto end; } worker = zmalloc(sizeof(*worker)); if (!worker) { ret = -ENOMEM; goto end; } worker->procname = strdup(procname); if (!worker->procname) { ret = -ENOMEM; goto error_procname_alloc; } /* Create unix socket. */ if (lttcomm_create_anon_unix_socketpair(worker->sockpair) < 0) { ret = -1; goto error_sock; } /* Fork worker. */ pid = fork(); if (pid < 0) { PERROR("fork"); ret = -1; goto error_fork; } else if (pid == 0) { /* Child */ reset_sighandler(); set_worker_sighandlers(); if (clean_up_func) { if (clean_up_func(clean_up_user_data) < 0) { ERR("Run-as post-fork clean-up failed, exiting."); exit(EXIT_FAILURE); } } /* Just close, no shutdown. */ if (close(worker->sockpair[0])) { PERROR("close"); exit(EXIT_FAILURE); } /* * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1] * Sockpair[1] is used as a control channel with the master */ for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) { if (i != worker->sockpair[1]) { (void) close(i); } } worker->sockpair[0] = -1; ret = run_as_worker(worker); if (lttcomm_close_unix_sock(worker->sockpair[1])) { PERROR("close"); ret = -1; } worker->sockpair[1] = -1; free(worker->procname); free(worker); LOG(ret ? PRINT_ERR : PRINT_DBG, "run_as worker exiting (ret = %d)", ret); exit(ret ? EXIT_FAILURE : EXIT_SUCCESS); } else { /* Parent */ /* Just close, no shutdown. */ if (close(worker->sockpair[1])) { PERROR("close"); ret = -1; goto error_fork; } worker->sockpair[1] = -1; worker->pid = pid; /* Wait for worker to become ready. */ readlen = lttcomm_recv_unix_sock(worker->sockpair[0], &recvret, sizeof(recvret)); if (readlen < sizeof(recvret)) { ERR("readlen: %zd", readlen); PERROR("Error reading response from run_as at creation"); ret = -1; goto error_fork; } global_worker = worker; } end: return ret; /* Error handling. */ error_fork: for (i = 0; i < 2; i++) { if (worker->sockpair[i] < 0) { continue; } if (lttcomm_close_unix_sock(worker->sockpair[i])) { PERROR("close"); } worker->sockpair[i] = -1; } error_sock: free(worker->procname); error_procname_alloc: free(worker); return ret; }
LTTNG_HIDDEN int run_as_create_worker(char *procname) { pid_t pid; int i, ret = 0; ssize_t readlen; struct run_as_ret recvret; struct run_as_worker *worker; pthread_mutex_lock(&worker_lock); assert(!global_worker); if (!use_clone()) { /* * Don't initialize a worker, all run_as tasks will be performed * in the current process. */ ret = 0; goto end; } worker = zmalloc(sizeof(*worker)); if (!worker) { ret = -ENOMEM; goto end; } worker->procname = procname; /* Create unix socket. */ if (lttcomm_create_anon_unix_socketpair(worker->sockpair) < 0) { ret = -1; goto error_sock; } /* Fork worker. */ pid = fork(); if (pid < 0) { PERROR("fork"); ret = -1; goto error_fork; } else if (pid == 0) { /* Child */ reset_sighandler(); set_worker_sighandlers(); /* The child has no use for this lock. */ pthread_mutex_unlock(&worker_lock); /* Just close, no shutdown. */ if (close(worker->sockpair[0])) { PERROR("close"); exit(EXIT_FAILURE); } worker->sockpair[0] = -1; ret = run_as_worker(worker); if (lttcomm_close_unix_sock(worker->sockpair[1])) { PERROR("close"); ret = -1; } worker->sockpair[1] = -1; LOG(ret ? PRINT_ERR : PRINT_DBG, "run_as worker exiting (ret = %d)", ret); exit(ret ? EXIT_FAILURE : EXIT_SUCCESS); } else { /* Parent */ /* Just close, no shutdown. */ if (close(worker->sockpair[1])) { PERROR("close"); ret = -1; goto error_fork; } worker->sockpair[1] = -1; worker->pid = pid; /* Wait for worker to become ready. */ readlen = lttcomm_recv_unix_sock(worker->sockpair[0], &recvret, sizeof(recvret)); if (readlen < sizeof(recvret)) { ERR("readlen: %zd", readlen); PERROR("Error reading response from run_as at creation"); ret = -1; goto error_fork; } global_worker = worker; } end: pthread_mutex_unlock(&worker_lock); return ret; /* Error handling. */ error_fork: for (i = 0; i < 2; i++) { if (worker->sockpair[i] < 0) { continue; } if (lttcomm_close_unix_sock(worker->sockpair[i])) { PERROR("close"); } worker->sockpair[i] = -1; } error_sock: free(worker); pthread_mutex_unlock(&worker_lock); return ret; }