/*
- * Copyright (C) 2018 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright (C) 2018 Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License, version 2 only, as
- * published by the Free Software Foundation.
+ * SPDX-License-Identifier: GPL-2.0-only
*
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <common/error.h>
#include <common/fd-tracker/utils.h>
#include <common/utils.h>
+#include <lttng/constant.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
static
int open_pipe_cloexec(void *data, int *fds)
{
- int ret;
-
- ret = utils_create_pipe_cloexec(fds);
- if (ret < 0) {
- goto end;
- }
-end:
- return ret;
+ return utils_create_pipe_cloexec(fds);
}
static
return 0;
}
+LTTNG_HIDDEN
int fd_tracker_util_close_fd(void *unused, int *fd)
{
return close(*fd);
}
-int fd_tracker_util_pipe_open_cloexec(struct fd_tracker *tracker,
- const char *name, int *pipe)
+LTTNG_HIDDEN
+int fd_tracker_util_pipe_open_cloexec(
+ struct fd_tracker *tracker, const char *name, int *pipe)
{
int ret;
const char *name_prefix;
goto end;
}
- ret = fd_tracker_open_unsuspendable_fd(tracker, pipe,
+ ret = fd_tracker_open_unsuspendable_fd(tracker, pipe,
(const char **) names, 2, open_pipe_cloexec, NULL);
free(names[0]);
free(names[1]);
return ret;
}
+LTTNG_HIDDEN
int fd_tracker_util_pipe_close(struct fd_tracker *tracker, int *pipe)
{
- return fd_tracker_close_unsuspendable_fd(tracker,
- pipe, 2, close_pipe, NULL);
+ return fd_tracker_close_unsuspendable_fd(
+ tracker, pipe, 2, close_pipe, NULL);
+}
+
+struct open_directory_handle_args {
+ const struct lttng_directory_handle *in_handle;
+ struct lttng_directory_handle *ret_handle;
+ const char *path;
+};
+
+static
+int open_directory_handle(void *_args, int *out_fds)
+{
+ int ret = 0;
+ struct open_directory_handle_args *args = _args;
+ struct lttng_directory_handle *new_handle = NULL;
+
+ new_handle = args->in_handle ?
+ lttng_directory_handle_create_from_handle(
+ args->path, args->in_handle) :
+ lttng_directory_handle_create(args->path);
+ if (!new_handle) {
+ ret = -errno;
+ goto end;
+ }
+
+ args->ret_handle = new_handle;
+
+ /*
+ * Reserved to indicate that the handle does not use a handle; there is
+ * nothing to track. We want to indicate an error to the fd-tracker so
+ * that it doesn't attempt to track the file descriptor, but also want
+ * the caller to retrieve the newly-created handle.
+ *
+ * Calling this a hack is a fair assessment.
+ */
+ if (!lttng_directory_handle_uses_fd(new_handle)) {
+ ret = ENOTSUP;
+ } else {
+#ifdef COMPAT_DIRFD
+ *out_fds = new_handle->dirfd;
+#else
+ abort();
+#endif
+
+ }
+end:
+ return ret;
+}
+
+#ifdef COMPAT_DIRFD
+static
+int fd_close(void *unused, int *in_fds)
+{
+ const int ret = close(in_fds[0]);
+
+ in_fds[0] = -1;
+ return ret;
+}
+
+static
+void directory_handle_destroy(
+ struct lttng_directory_handle *handle, void *data)
+{
+ struct fd_tracker *tracker = data;
+ const int ret = fd_tracker_close_unsuspendable_fd(
+ tracker, &handle->dirfd, 1, fd_close, NULL);
+
+ if (ret) {
+ ERR("Failed to untrack directory handle file descriptor");
+ }
+}
+#endif
+
+LTTNG_HIDDEN
+struct lttng_directory_handle *fd_tracker_create_directory_handle(
+ struct fd_tracker *tracker, const char *path)
+{
+ return fd_tracker_create_directory_handle_from_handle(
+ tracker, NULL, path);
+}
+
+LTTNG_HIDDEN
+struct lttng_directory_handle *fd_tracker_create_directory_handle_from_handle(
+ struct fd_tracker *tracker,
+ struct lttng_directory_handle *in_handle,
+ const char *path)
+{
+ int ret;
+ int dirfd = -1;
+ char *handle_name = NULL;
+ char cwd_path[LTTNG_PATH_MAX] = "working directory";
+ struct lttng_directory_handle *new_handle = NULL;
+ struct open_directory_handle_args open_args = {
+ .in_handle = in_handle,
+ .path = path,
+ };
+
+ if (!path) {
+ if (!getcwd(cwd_path, sizeof(cwd_path))) {
+ PERROR("Failed to get current working directory to name directory handle");
+ goto end;
+ }
+ }
+
+ ret = asprintf(&handle_name, "Directory handle to %s",
+ path ? path : cwd_path);
+ if (ret < 0) {
+ PERROR("Failed to format directory handle name");
+ goto end;
+ }
+
+ ret = fd_tracker_open_unsuspendable_fd(tracker, &dirfd,
+ (const char **) &handle_name, 1, open_directory_handle,
+ &open_args);
+ if (ret && ret != ENOTSUP) {
+ ERR("Failed to open directory handle to %s through the fd tracker", path ? path : cwd_path);
+ }
+ new_handle = open_args.ret_handle;
+
+#ifdef COMPAT_DIRFD
+ new_handle->destroy_cb = directory_handle_destroy;
+ new_handle->destroy_cb_data = tracker;
+#endif
+end:
+ free(handle_name);
+ return new_handle;
}