- AC_INIT([lttng-tools],[2.0.0-rc1],[dgoulet@efficios.com],[],[http://lttng.org])
+ AC_INIT([lttng-tools],[2.0.0-rc2],[dgoulet@efficios.com],[],[http://lttng.org])
AC_CONFIG_AUX_DIR([config])
AC_CANONICAL_TARGET
AC_CANONICAL_HOST
AC_CHECK_FUNCS([sched_getcpu sysconf])
+# check for dlopen
+AC_CHECK_LIB([dl], [dlopen],
+[
+ have_libdl=yes
+],
+[
+ #libdl not found, check for dlopen in libc.
+ AC_CHECK_LIB([c], [dlopen],
+ [
+ have_libc_dl=yes
+ ],
+ [
+ AC_MSG_ERROR([Cannot find dlopen in libdl nor libc. Use [LDFLAGS]=-Ldir to specify their location.])
+ ])
+])
+AM_CONDITIONAL([LTTNG_TOOLS_BUILD_WITH_LIBDL], [test "x$have_libdl" = "xyes"])
+AM_CONDITIONAL([LTTNG_TOOLS_BUILD_WITH_LIBC_DL], [test "x$have_libc_dl" = "xyes"])
+
# Option to only build the consumer daemon and its libraries
AC_ARG_WITH([consumerd-only],
AS_HELP_STRING([--with-consumerd-only],[Only build the consumer daemon [default=no]]),
*/
#define _GNU_SOURCE
-#include <fcntl.h>
#include <getopt.h>
#include <grp.h>
#include <limits.h>
#include <common/common.h>
#include <common/compat/poll.h>
+#include <common/compat/socket.h>
#include <common/defaults.h>
#include <common/kernel-consumer/kernel-consumer.h>
#include <common/ust-consumer/ust-consumer.h>
.type = LTTNG_CONSUMER_KERNEL,
.err_unix_sock_path = DEFAULT_KCONSUMERD_ERR_SOCK_PATH,
.cmd_unix_sock_path = DEFAULT_KCONSUMERD_CMD_SOCK_PATH,
+ .err_sock = -1,
+ .cmd_sock = -1,
};
static struct consumer_data ustconsumer64_data = {
.type = LTTNG_CONSUMER64_UST,
.err_unix_sock_path = DEFAULT_USTCONSUMERD64_ERR_SOCK_PATH,
.cmd_unix_sock_path = DEFAULT_USTCONSUMERD64_CMD_SOCK_PATH,
+ .err_sock = -1,
+ .cmd_sock = -1,
};
static struct consumer_data ustconsumer32_data = {
.type = LTTNG_CONSUMER32_UST,
.err_unix_sock_path = DEFAULT_USTCONSUMERD32_ERR_SOCK_PATH,
.cmd_unix_sock_path = DEFAULT_USTCONSUMERD32_CMD_SOCK_PATH,
+ .err_sock = -1,
+ .cmd_sock = -1,
};
static int dispatch_thread_exit;
*/
static int init_thread_quit_pipe(void)
{
- int ret;
+ int ret, i;
- ret = pipe2(thread_quit_pipe, O_CLOEXEC);
+ ret = pipe(thread_quit_pipe);
if (ret < 0) {
PERROR("thread quit pipe");
goto error;
}
+ for (i = 0; i < 2; i++) {
+ ret = fcntl(thread_quit_pipe[i], F_SETFD, FD_CLOEXEC);
+ if (ret < 0) {
+ PERROR("fcntl");
+ goto error;
+ }
+ }
+
error:
return ret;
}
* If a custom kernel consumer was registered, close the socket before
* tearing down the complete kernel session structure
*/
- if (session->kernel_session->consumer_fd != kconsumer_data.cmd_sock) {
+ if (kconsumer_data.cmd_sock >= 0 &&
+ session->kernel_session->consumer_fd != kconsumer_data.cmd_sock) {
lttcomm_close_unix_sock(session->kernel_session->consumer_fd);
}
DBG("Sending metadata stream fd");
- /* Extra protection. It's NOT supposed to be set to 0 at this point */
- if (session->consumer_fd == 0) {
+ /* Extra protection. It's NOT supposed to be set to -1 at this point */
+ if (session->consumer_fd < 0) {
session->consumer_fd = consumer_data->cmd_sock;
}
- if (session->metadata_stream_fd != 0) {
+ if (session->metadata_stream_fd >= 0) {
/* Send metadata channel fd */
lkm.cmd_type = LTTNG_CONSUMER_ADD_CHANNEL;
lkm.u.channel.channel_key = session->metadata->fd;
continue;
}
- /* This is not suppose to be 0 but this is an extra security check */
- if (session->kernel_session->consumer_fd == 0) {
+ /* This is not suppose to be -1 but this is an extra security check */
+ if (session->kernel_session->consumer_fd < 0) {
session->kernel_session->consumer_fd = consumer_data->cmd_sock;
}
}
ust_cmd->sock = sock;
+ sock = -1;
DBG("UST registration received with pid:%d ppid:%d uid:%d"
" gid:%d sock:%d name:%s (version %d.%d)",
error:
WARN("No kernel tracer available");
kernel_tracer_fd = -1;
- return LTTCOMM_KERN_NA;
+ if (!is_root) {
+ return LTTCOMM_NEED_ROOT_SESSIOND;
+ } else {
+ return LTTCOMM_KERN_NA;
+ }
}
/*
if (session->consumer_fds_sent == 0) {
/*
* Assign default kernel consumer socket if no consumer assigned to the
- * kernel session. At this point, it's NOT suppose to be 0 but this is
+ * kernel session. At this point, it's NOT supposed to be -1 but this is
* an extra security check.
*/
- if (session->consumer_fd == 0) {
+ if (session->consumer_fd < 0) {
session->consumer_fd = kconsumer_data.cmd_sock;
}
}
/* Set kernel consumer socket fd */
- if (kconsumer_data.cmd_sock) {
+ if (kconsumer_data.cmd_sock >= 0) {
session->kernel_session->consumer_fd = kconsumer_data.cmd_sock;
}
}
/* Open kernel metadata stream */
- if (ksession->metadata_stream_fd == 0) {
+ if (ksession->metadata_stream_fd < 0) {
ret = kernel_open_metadata_stream(ksession);
if (ret < 0) {
ERR("Kernel create metadata stream failed");
/*
* Command LTTNG_CREATE_SESSION processed by the client thread.
*/
-static int cmd_create_session(char *name, char *path, struct ucred *creds)
+static int cmd_create_session(char *name, char *path, lttng_sock_cred *creds)
{
int ret;
- ret = session_create(name, path, creds->uid, creds->gid);
+ ret = session_create(name, path, LTTNG_SOCK_GET_UID_CRED(creds),
+ LTTNG_SOCK_GET_GID_CRED(creds));
if (ret != LTTCOMM_OK) {
goto error;
}
if (opt_no_kernel && need_domain
&& cmd_ctx->lsm->domain.type == LTTNG_DOMAIN_KERNEL) {
- ret = LTTCOMM_KERN_NA;
+ if (!is_root) {
+ ret = LTTCOMM_NEED_ROOT_SESSIOND;
+ } else {
+ ret = LTTCOMM_KERN_NA;
+ }
goto error;
}
switch (cmd_ctx->lsm->domain.type) {
case LTTNG_DOMAIN_KERNEL:
if (!is_root) {
- ret = LTTCOMM_KERN_NA;
+ ret = LTTCOMM_NEED_ROOT_SESSIOND;
goto error;
}
*/
if (need_tracing_session) {
if (!session_access_ok(cmd_ctx->session,
- cmd_ctx->creds.uid, cmd_ctx->creds.gid)) {
+ LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds),
+ LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds))) {
ret = LTTCOMM_EPERM;
goto error;
}
unsigned int nr_sessions;
session_lock_list();
- nr_sessions = lttng_sessions_count(cmd_ctx->creds.uid, cmd_ctx->creds.gid);
+ nr_sessions = lttng_sessions_count(
+ LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds),
+ LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds));
ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_session) * nr_sessions);
if (ret < 0) {
/* Filled the session array */
list_lttng_sessions((struct lttng_session *)(cmd_ctx->llm->payload),
- cmd_ctx->creds.uid, cmd_ctx->creds.gid);
+ LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds),
+ LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds));
session_unlock_list();
*/
static int create_kernel_poll_pipe(void)
{
- return pipe2(kernel_poll_pipe, O_CLOEXEC);
+ int ret, i;
+
+ ret = pipe(kernel_poll_pipe);
+ if (ret < 0) {
+ PERROR("kernel poll pipe");
+ goto error;
+ }
+
+ for (i = 0; i < 2; i++) {
+ ret = fcntl(kernel_poll_pipe[i], F_SETFD, FD_CLOEXEC);
+ if (ret < 0) {
+ PERROR("fcntl kernel_poll_pipe");
+ goto error;
+ }
+ }
+
+error:
+ return ret;
}
/*
*/
static int create_apps_cmd_pipe(void)
{
- return pipe2(apps_cmd_pipe, O_CLOEXEC);
+ int ret, i;
+
+ ret = pipe(apps_cmd_pipe);
+ if (ret < 0) {
+ PERROR("apps cmd pipe");
+ goto error;
+ }
+
+ for (i = 0; i < 2; i++) {
+ ret = fcntl(apps_cmd_pipe[i], F_SETFD, FD_CLOEXEC);
+ if (ret < 0) {
+ PERROR("fcntl apps_cmd_pipe");
+ goto error;
+ }
+ }
+
+error:
+ return ret;
}
/*
#define _GNU_SOURCE
#include <assert.h>
-#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <stdlib.h>
{
struct lttng_consumer_stream *stream;
+ rcu_read_lock();
stream = consumer_find_stream(key);
- if (stream)
+ if (stream) {
stream->key = -1;
+ /*
+ * We don't want the lookup to match, but we still need
+ * to iterate on this stream when iterating over the hash table. Just
+ * change the node key.
+ */
+ stream->node.key = -1;
+ }
+ rcu_read_unlock();
}
static struct lttng_consumer_channel *consumer_find_channel(int key)
{
struct lttng_consumer_channel *channel;
+ rcu_read_lock();
channel = consumer_find_channel(key);
- if (channel)
+ if (channel) {
channel->key = -1;
+ /*
+ * We don't want the lookup to match, but we still need
+ * to iterate on this channel when iterating over the hash table. Just
+ * change the node key.
+ */
+ channel->node.key = -1;
+ }
+ rcu_read_unlock();
}
static
}
rcu_read_lock();
-
- /* Get stream node from hash table */
- lttng_ht_lookup(consumer_data.stream_ht,
- (void *)((unsigned long) stream->key), &iter);
- /*
- * Remove stream node from hash table. It can fail if it's been
- * replaced due to key reuse.
- */
- (void) lttng_ht_del(consumer_data.stream_ht, &iter);
+ iter.iter.node = &stream->node.node;
+ ret = lttng_ht_del(consumer_data.stream_ht, &iter);
+ assert(!ret);
rcu_read_unlock();
/* Steal stream identifier, for UST */
consumer_steal_stream_key(stream->key);
rcu_read_lock();
- /*
- * We simply remove the old channel from the hash table. It's
- * ok, since we know for sure the sessiond wants to replace it
- * with the new version, because the key has been reused.
- */
- (void) lttng_ht_add_replace_ulong(consumer_data.stream_ht, &stream->node);
+ lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
rcu_read_unlock();
consumer_data.stream_count++;
consumer_data.need_update = 1;
}
rcu_read_lock();
-
- lttng_ht_lookup(consumer_data.channel_ht,
- (void *)((unsigned long) channel->key), &iter);
-
- /*
- * Remove channel node from hash table. It can fail if it's been
- * replaced due to key reuse.
- */
- (void) lttng_ht_del(consumer_data.channel_ht, &iter);
-
+ iter.iter.node = &channel->node.node;
+ ret = lttng_ht_del(consumer_data.channel_ht, &iter);
+ assert(!ret);
rcu_read_unlock();
if (channel->mmap_base != NULL) {
/* Steal channel identifier, for UST */
consumer_steal_channel_key(channel->key);
rcu_read_lock();
- /*
- * We simply remove the old channel from the hash table. It's
- * ok, since we know for sure the sessiond wants to replace it
- * with the new version, because the key has been reused.
- */
- (void) lttng_ht_add_replace_ulong(consumer_data.channel_ht, &channel->node);
+ lttng_ht_add_unique_ulong(consumer_data.channel_ht, &channel->node);
rcu_read_unlock();
pthread_mutex_unlock(&consumer_data.lock);
struct lttng_consumer_stream *stream;
DBG("Updating poll fd array");
+ rcu_read_lock();
cds_lfht_for_each_entry(consumer_data.stream_ht->ht, &iter.iter, stream,
node.node) {
if (stream->state != LTTNG_CONSUMER_ACTIVE_STREAM) {
local_stream[i] = stream;
i++;
}
+ rcu_read_unlock();
/*
* Insert the consumer_poll_pipe at the end of the array and don't
if (orig_offset < stream->chan->max_sb_size) {
return;
}
- sync_file_range(outfd, orig_offset - stream->chan->max_sb_size,
+ lttng_sync_file_range(outfd, orig_offset - stream->chan->max_sb_size,
stream->chan->max_sb_size,
SYNC_FILE_RANGE_WAIT_BEFORE
| SYNC_FILE_RANGE_WRITE
ERR("Unknown consumer_data type");
assert(0);
}
+
+ return 0;
}
/*
local_stream[i]->hangup_flush_done) {
ssize_t len;
- assert(!(pollfd[i].revents & POLLERR));
- assert(!(pollfd[i].revents & POLLNVAL));
DBG("Normal read on fd %d", pollfd[i].fd);
len = ctx->on_buffer_ready(local_stream[i], ctx);
/* it's ok to have an unavailable sub-buffer */
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
[ LTTCOMM_ERR_INDEX(CONSUMERD_SPLICE_ENOMEM) ] = "consumerd splice ENOMEM",
[ LTTCOMM_ERR_INDEX(CONSUMERD_SPLICE_ESPIPE) ] = "consumerd splice ESPIPE",
[ LTTCOMM_ERR_INDEX(LTTCOMM_NO_EVENT) ] = "Event not found",
+ [ LTTCOMM_ERR_INDEX(LTTCOMM_NEED_ROOT_SESSIOND) ] = "A root lttng-sessiond needs to be running, and client user part of the \"tracing\" group, to interact with kernel tracing",
};
/*
ret = sendmsg(sock, &msg, 0);
if (ret < 0) {
- PERROR("sendmsg");
+ /*
+ * Only warn about EPIPE when quiet mode is deactivated.
+ * We consider EPIPE as expected.
+ */
+ if (errno != EPIPE || !opt_quiet) {
+ PERROR("sendmsg");
+ }
}
return ret;
ret = sendmsg(sock, &msg, 0);
if (ret < 0) {
- PERROR("sendmsg");
+ /*
+ * Only warn about EPIPE when quiet mode is deactivated.
+ * We consider EPIPE as expected.
+ */
+ if (errno != EPIPE || !opt_quiet) {
+ PERROR("sendmsg");
+ }
}
return ret;
}
}
if (cmsg->cmsg_len != CMSG_LEN(sizeof_fds)) {
fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n",
- cmsg->cmsg_len, CMSG_LEN(sizeof_fds));
+ (size_t) cmsg->cmsg_len, (size_t) CMSG_LEN(sizeof_fds));
ret = -1;
goto end;
}
ssize_t lttcomm_send_creds_unix_sock(int sock, void *buf, size_t len)
{
struct msghdr msg;
- struct cmsghdr *cmptr;
struct iovec iov[1];
ssize_t ret = -1;
- struct ucred *creds;
- size_t sizeof_cred = sizeof(struct ucred);
+#ifdef __linux__
+ struct cmsghdr *cmptr;
+ size_t sizeof_cred = sizeof(lttng_sock_cred);
char anc_buf[CMSG_SPACE(sizeof_cred)];
+ lttng_sock_cred *creds;
+#endif /* __linux__ */
memset(&msg, 0, sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = 1;
+#ifdef __linux__
msg.msg_control = (caddr_t) anc_buf;
msg.msg_controllen = CMSG_LEN(sizeof_cred);
cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_level = SOL_SOCKET;
- cmptr->cmsg_type = SCM_CREDENTIALS;
+ cmptr->cmsg_type = LTTNG_SOCK_CREDS;
cmptr->cmsg_len = CMSG_LEN(sizeof_cred);
- creds = (struct ucred *) CMSG_DATA(cmptr);
+ creds = (lttng_sock_cred*) CMSG_DATA(cmptr);
- creds->uid = geteuid();
- creds->gid = getegid();
- creds->pid = getpid();
+ LTTNG_SOCK_SET_UID_CRED(creds, geteuid());
+ LTTNG_SOCK_SET_GID_CRED(creds, getegid());
+ LTTNG_SOCK_SET_PID_CRED(creds, getpid());
+#endif /* __linux__ */
ret = sendmsg(sock, &msg, 0);
if (ret < 0) {
- PERROR("sendmsg");
+ /*
+ * Only warn about EPIPE when quiet mode is deactivated.
+ * We consider EPIPE as expected.
+ */
+ if (errno != EPIPE || !opt_quiet) {
+ PERROR("sendmsg");
+ }
}
-
return ret;
}
* Returns the size of received data, or negative error value.
*/
ssize_t lttcomm_recv_creds_unix_sock(int sock, void *buf, size_t len,
- struct ucred *creds)
+ lttng_sock_cred *creds)
{
struct msghdr msg;
- struct cmsghdr *cmptr;
struct iovec iov[1];
ssize_t ret;
- size_t sizeof_cred = sizeof(struct ucred);
+#ifdef __linux__
+ struct cmsghdr *cmptr;
+ size_t sizeof_cred = sizeof(lttng_sock_cred);
char anc_buf[CMSG_SPACE(sizeof_cred)];
+#endif /* __linux__ */
memset(&msg, 0, sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = 1;
+#ifdef __linux__
msg.msg_control = anc_buf;
msg.msg_controllen = sizeof(anc_buf);
+#endif /* __linux__ */
ret = recvmsg(sock, &msg, 0);
if (ret < 0) {
goto end;
}
+#ifdef __linux__
if (msg.msg_flags & MSG_CTRUNC) {
fprintf(stderr, "Error: Control message truncated.\n");
ret = -1;
}
if (cmptr->cmsg_level != SOL_SOCKET ||
- cmptr->cmsg_type != SCM_CREDENTIALS) {
+ cmptr->cmsg_type != LTTNG_SOCK_CREDS) {
fprintf(stderr, "Didn't received any credentials\n");
ret = -1;
goto end;
if (cmptr->cmsg_len != CMSG_LEN(sizeof_cred)) {
fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n",
- cmptr->cmsg_len, CMSG_LEN(sizeof_cred));
+ (size_t) cmptr->cmsg_len, (size_t) CMSG_LEN(sizeof_cred));
ret = -1;
goto end;
}
memcpy(creds, CMSG_DATA(cmptr), sizeof_cred);
+#elif defined(__FreeBSD__)
+ {
+ int peer_ret;
+
+ peer_ret = getpeereid(sock, &creds->uid, &creds->gid);
+ if (peer_ret != 0) {
+ return peer_ret;
+ }
+ }
+#else
+#error "Please implement credential support for your OS."
+#endif /* __linux__ */
end:
return ret;
/*
* Set socket option to use credentials passing.
*/
+#ifdef __linux__
int lttcomm_setsockopt_creds_unix_sock(int sock)
{
int ret, on = 1;
if (ret < 0) {
PERROR("setsockopt creds unix sock");
}
-
return ret;
}
+#elif defined(__FreeBSD__)
+int lttcomm_setsockopt_creds_unix_sock(int sock)
+{
+ return 0;
+}
+#else
+#error "Please implement credential support for your OS."
+#endif /* __linux__ */
#define _GNU_SOURCE
#include <limits.h>
#include <lttng/lttng.h>
-#include <sys/socket.h>
+#include <common/compat/socket.h>
/* Queue size of listen(2) */
#define LTTNG_SESSIOND_COMM_MAX_LISTEN 64
CONSUMERD_SPLICE_EINVAL, /* EINVAL from splice(2) */
CONSUMERD_SPLICE_ENOMEM, /* ENOMEM from splice(2) */
CONSUMERD_SPLICE_ESPIPE, /* ESPIPE from splice(2) */
+ LTTCOMM_NEED_ROOT_SESSIOND, /* root sessiond is needed */
/* MUST be last element */
LTTCOMM_NR, /* Last element */
};
extern ssize_t lttcomm_send_creds_unix_sock(int sock, void *buf, size_t len);
extern ssize_t lttcomm_recv_creds_unix_sock(int sock, void *buf, size_t len,
- struct ucred *creds);
+ lttng_sock_cred *creds);
extern const char *lttcomm_get_readable_code(enum lttcomm_return_code code);
extern int lttcomm_setsockopt_creds_unix_sock(int sock);