+ (void) lttng_directory_handle_init_from_dirfd(&handle, data->fd);
+ /* Ownership of dirfd is transferred to the handle. */
+ data->fd = -1;
+ /* Safe to call as we have transitioned to the requested uid/gid. */
+ ret_value->u.mkdirat.ret =
+ lttng_directory_handle_create_subdirectory_recursive(
+ &handle, path, mode);
+ ret_value->_errno = errno;
+ ret_value->_error = (ret_value->u.mkdirat.ret) ? true : false;
+ lttng_directory_handle_fini(&handle);
+ return ret_value->u.mkdirat.ret;
+}
+
+static
+int _mkdirat(struct run_as_data *data, struct run_as_ret *ret_value)
+{
+ const char *path;
+ mode_t mode;
+ struct lttng_directory_handle handle;
+
+ path = data->u.mkdirat.path;
+ mode = data->u.mkdirat.mode;
+
+ (void) lttng_directory_handle_init_from_dirfd(&handle, data->fd);
+ /* Ownership of dirfd is transferred to the handle. */
+ data->fd = -1;
+ /* Safe to call as we have transitioned to the requested uid/gid. */
+ ret_value->u.mkdirat.ret =
+ lttng_directory_handle_create_subdirectory(
+ &handle, path, mode);
+ ret_value->_errno = errno;
+ ret_value->_error = (ret_value->u.mkdirat.ret) ? true : false;
+ lttng_directory_handle_fini(&handle);
+ return ret_value->u.mkdirat.ret;
+}
+
+static
+int _open(struct run_as_data *data, struct run_as_ret *ret_value)
+{
+ ret_value->u.open.ret = openat(data->fd, data->u.open.path,
+ data->u.open.flags, data->u.open.mode);
+ ret_value->fd = ret_value->u.open.ret;
+ ret_value->_errno = errno;
+ ret_value->_error = ret_value->u.open.ret < 0;
+ return ret_value->u.open.ret;
+}
+
+static
+int _unlink(struct run_as_data *data, struct run_as_ret *ret_value)
+{
+ ret_value->u.unlink.ret = unlinkat(data->fd, data->u.unlink.path, 0);
+ 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:
+ case RUN_AS_MKDIRAT:
+ return _mkdirat;
+ case RUN_AS_MKDIR_RECURSIVE:
+ case RUN_AS_MKDIRAT_RECURSIVE:
+ return _mkdirat_recursive;
+ case RUN_AS_OPEN:
+ case RUN_AS_OPENAT:
+ return _open;
+ case RUN_AS_UNLINK:
+ case RUN_AS_UNLINKAT:
+ return _unlink;
+ case RUN_AS_RMDIR_RECURSIVE:
+ return _rmdir_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:
+ case RUN_AS_MKDIRAT:
+ case RUN_AS_MKDIRAT_RECURSIVE:
+ case RUN_AS_OPENAT:
+ case RUN_AS_UNLINKAT:
+ 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);