+ ret_value->u.unlink.ret = unlink(data->u.unlink.path);
+ ret_value->_errno = errno;
+ ret_value->_error = (ret_value->u.unlink.ret) ? true : false;
+ return ret_value->u.unlink.ret;
+}
+
+static
+int _rmdir_recursive(struct run_as_data *data, struct run_as_ret *ret_value)
+{
+ ret_value->u.rmdir_recursive.ret = utils_recursive_rmdir(data->u.rmdir_recursive.path);
+ ret_value->_errno = errno;
+ ret_value->_error = (ret_value->u.rmdir_recursive.ret) ? true : false;
+ return ret_value->u.rmdir_recursive.ret;
+}
+
+#ifdef HAVE_ELF_H
+static
+int _extract_elf_symbol_offset(struct run_as_data *data,
+ struct run_as_ret *ret_value)
+{
+ int ret = 0;
+ ret_value->_error = false;
+
+ ret = lttng_elf_get_symbol_offset(data->fd,
+ data->u.extract_elf_symbol_offset.function,
+ &ret_value->u.extract_elf_symbol_offset.offset);
+ if (ret) {
+ DBG("Failed to extract ELF function offset");
+ ret_value->_error = true;
+ }
+
+ return ret;
+}
+
+static
+int _extract_sdt_probe_offsets(struct run_as_data *data,
+ struct run_as_ret *ret_value)
+{
+ int ret = 0;
+ uint64_t *offsets = NULL;
+ uint32_t num_offset;
+
+ ret_value->_error = false;
+
+ /* On success, this call allocates the offsets paramater. */
+ ret = lttng_elf_get_sdt_probe_offsets(data->fd,
+ data->u.extract_sdt_probe_offsets.provider_name,
+ data->u.extract_sdt_probe_offsets.probe_name,
+ &offsets, &num_offset);
+
+ if (ret) {
+ DBG("Failed to extract SDT probe offsets");
+ ret_value->_error = true;
+ goto end;
+ }
+
+ if (num_offset <= 0 || num_offset > LTTNG_KERNEL_MAX_UPROBE_NUM) {
+ DBG("Wrong number of probes.");
+ ret = -1;
+ ret_value->_error = true;
+ goto free_offset;
+ }
+
+ /* Copy the content of the offsets array to the ret struct. */
+ memcpy(ret_value->u.extract_sdt_probe_offsets.offsets,
+ offsets, num_offset * sizeof(uint64_t));
+
+ ret_value->u.extract_sdt_probe_offsets.num_offset = num_offset;
+
+free_offset:
+ free(offsets);
+end:
+ return ret;
+}
+#else
+static
+int _extract_elf_symbol_offset(struct run_as_data *data,
+ struct run_as_ret *ret_value)
+{
+ ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET");
+ return -1;
+}
+
+static
+int _extract_sdt_probe_offsets(struct run_as_data *data,
+ struct run_as_ret *ret_value)
+{
+ ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS");
+ return -1;
+}
+#endif
+
+static
+run_as_fct run_as_enum_to_fct(enum run_as_cmd cmd)
+{
+ switch (cmd) {
+ case RUN_AS_MKDIR:
+ return _mkdir;
+ case RUN_AS_OPEN:
+ return _open;
+ case RUN_AS_UNLINK:
+ return _unlink;
+ case RUN_AS_RMDIR_RECURSIVE:
+ return _rmdir_recursive;
+ case RUN_AS_MKDIR_RECURSIVE:
+ return _mkdir_recursive;
+ case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET:
+ return _extract_elf_symbol_offset;
+ case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS:
+ return _extract_sdt_probe_offsets;
+ default:
+ ERR("Unknown command %d", (int) cmd);
+ return NULL;
+ }
+}
+
+static
+int do_send_fd(int sock, int fd)
+{
+ ssize_t len;
+
+ if (fd < 0) {
+ ERR("Attempt to send invalid file descriptor to master (fd = %i)", fd);
+ /* Return 0 as this is not a fatal error. */
+ return 0;
+ }
+
+ len = lttcomm_send_fds_unix_sock(sock, &fd, 1);
+ if (len < 0) {
+ PERROR("lttcomm_send_fds_unix_sock");
+ return -1;
+ }
+ return 0;
+}
+
+static
+int do_recv_fd(int sock, int *fd)
+{
+ ssize_t len;
+
+ len = lttcomm_recv_fds_unix_sock(sock, fd, 1);
+
+ if (!len) {
+ return -1;
+ } else if (len < 0) {
+ PERROR("lttcomm_recv_fds_unix_sock");
+ return -1;
+ }
+ if (*fd < 0) {
+ ERR("Invalid file descriptor received from worker (fd = %i)", *fd);
+ /* Return 0 as this is not a fatal error. */
+ return 0;
+ }
+
+ return 0;
+}
+
+static
+int send_fd_to_worker(struct run_as_worker *worker, enum run_as_cmd cmd, int fd)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET:
+ case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS:
+ break;
+ default:
+ return 0;
+ }
+
+ if (fd < 0) {
+ ERR("Refusing to send invalid fd to worker (fd = %i)", fd);
+ return -1;
+ }
+
+ ret = do_send_fd(worker->sockpair[0], fd);
+ if (ret < 0) {
+ PERROR("do_send_fd");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static
+int send_fd_to_master(struct run_as_worker *worker, enum run_as_cmd cmd, int fd)
+{
+ int ret = 0, ret_close = 0;
+
+ switch (cmd) {
+ case RUN_AS_OPEN:
+ break;
+ default:
+ return 0;
+ }
+
+ if (fd < 0) {
+ DBG("Not sending file descriptor to master as it is invalid (fd = %i)", fd);
+ return 0;
+ }
+ ret = do_send_fd(worker->sockpair[1], fd);
+ if (ret < 0) {
+ PERROR("do_send_fd error");
+ ret = -1;
+ }
+
+ ret_close = close(fd);
+ if (ret_close < 0) {
+ PERROR("close");
+ }
+
+ return ret;
+}
+
+static
+int recv_fd_from_worker(struct run_as_worker *worker, enum run_as_cmd cmd, int *fd)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case RUN_AS_OPEN:
+ break;
+ default:
+ return 0;
+ }
+
+ ret = do_recv_fd(worker->sockpair[0], fd);
+ if (ret < 0) {
+ PERROR("do_recv_fd error");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static
+int recv_fd_from_master(struct run_as_worker *worker, enum run_as_cmd cmd, int *fd)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET:
+ case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS:
+ break;
+ default:
+ return 0;
+ }
+
+ ret = do_recv_fd(worker->sockpair[1], fd);
+ if (ret < 0) {
+ PERROR("do_recv_fd error");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static
+int cleanup_received_fd(enum run_as_cmd cmd, int fd)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET:
+ case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS:
+ break;
+ default:
+ return 0;
+ }
+
+ if (fd < 0) {
+ return 0;
+ }
+ ret = close(fd);
+ if (ret < 0) {
+ PERROR("close error");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/*
+ * Return < 0 on error, 0 if OK, 1 on hangup.
+ */
+static
+int handle_one_cmd(struct run_as_worker *worker)
+{
+ int ret = 0;
+ struct run_as_data data;
+ ssize_t readlen, writelen;
+ struct run_as_ret sendret;
+ run_as_fct cmd;
+ uid_t prev_euid;
+
+ memset(&sendret, 0, sizeof(sendret));
+ sendret.fd = -1;
+
+ /*
+ * Stage 1: Receive run_as_data struct from the master.
+ * The structure contains the command type and all the parameters needed for
+ * its execution
+ */
+ readlen = lttcomm_recv_unix_sock(worker->sockpair[1], &data,
+ sizeof(data));
+ if (readlen == 0) {
+ /* hang up */
+ ret = 1;
+ goto end;
+ }
+ if (readlen < sizeof(data)) {
+ PERROR("lttcomm_recv_unix_sock error");
+ ret = -1;
+ goto end;
+ }
+
+ cmd = run_as_enum_to_fct(data.cmd);
+ if (!cmd) {
+ ret = -1;
+ goto end;
+ }