+2012-03-02 lttng-tools 2.0.0-rc2
+ * Fix: meaningful error message
+ * Fix: UST consumer need to iterate on streams, just change their key
+ * Fix: add missing rcu read lock across RCU HT iteration
+ * Fix: kernel session closes fd 0 after create
+ * Fix: sendmsg EPIPE should be quiet by default (expected)
+ * Fix: thread_registration_apps should set its local sock to -1 when passing it
+ * Fix: clock -> sock typo
+ * Fix: consumer race: should allow reuse of FD key
+ * Fix: Use PERROR all across lttng-tools, never make it quiet
+ * Fix: test all close return values in sessiond
+ * Fix: All perror turned into PERROR to show file and line number
+ * Fix: large audit of close() use in sessiond main.c
+ * Fix: main.c client/apps sockets and kernel_trace_fd close(0)
+ * Fix: incorrect close of fd 0 for syscall kernel event destroy
+ * Fix: sessiond has incorrect missing 0 value in FD check
+ * Fix: sessiond app listening: use posix-compliant poll flags
+ * Fix: consumer printf type should match ssize_t (%zd)
+ * Fix: make ust consumer posix compliant for poll flags
+ * Fix security permission on lttng run directory
+ * Fix: Display right loglevel_type in error message
+ * Fix documentation in lttng.h
+ * Fix: lttng UST and kernel consumer: fix ret vs errno mixup
+ * Fix: restart consumerd and sessiond when interrupted in poll()
+ * Fix: handling bad channel when sending to consumer
+ * Fix useless variable
+ * Fix add-context returned error
+ * fix: add missing break in command handling
+ * fix: command handling: do not check domain for commands not requiring domain
+ * fix: if tracing group does not exist, do not report a client error
+ * Fix: run_as error handling
+ * Fix usage note on -a
+ * Revert FreeBSD compatibility layer
+ * Fix: documented number of subbuffers is incorrect
+ * Document that num-subbuf and subbuf-size need to be power of 2
+ * Merge branch 'master' of git://git.lttng.org/lttng-tools
+
2012-02-20 lttng-tools 2.0.0-rc1
* Fix lttcomm_close_unix_sock to actually close the socket
* lttng-sessiond: Set group permissions explicitly
-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]]),
.IP "LTTNG_CONSUMERD64_LIBDIR"
Allow to specifiy the 32-bit library path containing libconsumer.so.
\fB--consumerd64-libdir\fP override this variable.
+.IP "LTTNG_DEBUG_NOCLONE"
+Debug-mode disabling use of clone/fork. Insecure, but required to allow
+debuggers to work with sessiond on some operating systems.
.SH "SEE ALSO"
.PP
const char *channel_name);
/*
- * Create or enable a kernel event (or events) for a channel.
+ * Create or enable an event (or events) for a channel.
*
* If the event you are trying to enable does not exist, it will be created,
* else it is enabled.
struct lttng_event *ev, const char *channel_name);
/*
- * Create or enable a kernel channel.
+ * Create or enable a channel.
* The channel name cannot be NULL.
*/
extern int lttng_enable_channel(struct lttng_handle *handle,
struct lttng_channel *chan);
/*
- * Disable kernel event(s) of a channel and domain.
+ * Disable event(s) of a channel and domain.
*
* If event_name is NULL, all events are disabled.
* If channel_name is NULL, the default channel is used (channel0).
const char *name, const char *channel_name);
/*
- * Disable kernel channel.
+ * Disable channel.
*
* The channel name cannot be NULL.
*/
static int sigintcount = 0;
/* Argument variables */
-int opt_quiet;
-int opt_verbose;
+int lttng_opt_quiet; /* not static in error.h */
+int lttng_opt_verbose; /* not static in error.h */
static int opt_daemon;
static const char *progname;
static char command_sock_path[PATH_MAX]; /* Global command socket path */
usage(stdout);
exit(EXIT_SUCCESS);
case 'q':
- opt_quiet = 1;
+ lttng_opt_quiet = 1;
break;
case 'v':
- opt_verbose = 1;
+ lttng_opt_verbose = 1;
break;
case 'V':
fprintf(stdout, "%s\n", VERSION);
attr = defattr;
}
+ /*
+ * Validate UST buffer size and number of buffers: must both be
+ * power of 2 and nonzero. We validate right here for UST,
+ * because applications will not report the error to the user
+ * (unlike kernel tracing).
+ */
+ if (!attr->attr.subbuf_size || (attr->attr.subbuf_size & (attr->attr.subbuf_size - 1))) {
+ ret = LTTCOMM_INVALID;
+ goto error;
+ }
+ if (!attr->attr.num_subbuf || (attr->attr.num_subbuf & (attr->attr.num_subbuf - 1))) {
+ ret = LTTCOMM_INVALID;
+ goto error;
+ }
+
/* Create UST channel */
uchan = trace_ust_create_channel(attr, usess->pathname);
if (uchan == NULL) {
ret = kernctl_add_context(chan->fd, ctx);
if (ret < 0) {
if (errno != EEXIST) {
- perror("add context ioctl");
+ PERROR("add context ioctl");
} else {
/* If EEXIST, we just ignore the error */
ret = 0;
chan->ctx = zmalloc(sizeof(struct lttng_kernel_context));
if (chan->ctx == NULL) {
- perror("zmalloc event context");
+ PERROR("zmalloc event context");
goto error;
}
DBG("Adding context to event %s", event->event->name);
ret = kernctl_add_context(event->fd, ctx);
if (ret < 0) {
- perror("add context ioctl");
+ PERROR("add context ioctl");
goto error;
}
event->ctx = zmalloc(sizeof(struct lttng_kernel_context));
if (event->ctx == NULL) {
- perror("zmalloc event context");
+ PERROR("zmalloc event context");
goto error;
}
/* Kernel tracer session creation */
ret = kernctl_create_session(tracer_fd);
if (ret < 0) {
- perror("ioctl kernel create session");
+ PERROR("ioctl kernel create session");
goto error;
}
/* Prevent fd duplication after execlp() */
ret = fcntl(lks->fd, F_SETFD, FD_CLOEXEC);
if (ret < 0) {
- perror("fcntl session fd");
+ PERROR("fcntl session fd");
}
lks->consumer_fds_sent = 0;
/* Kernel tracer channel creation */
ret = kernctl_create_channel(session->fd, &lkc->channel->attr);
if (ret < 0) {
- perror("ioctl kernel create channel");
+ PERROR("ioctl kernel create channel");
goto error;
}
/* Prevent fd duplication after execlp() */
ret = fcntl(lkc->fd, F_SETFD, FD_CLOEXEC);
if (ret < 0) {
- perror("fcntl session fd");
+ PERROR("fcntl session fd");
}
/* Add channel to session */
*/
if (ret == 0 && event->event->instrumentation == LTTNG_KERNEL_SYSCALL) {
DBG2("Kernel event syscall creation success");
+ /*
+ * We use fd == -1 to ensure that we never trigger a close of fd
+ * 0.
+ */
+ event->fd = -1;
goto add_list;
}
/* Prevent fd duplication after execlp() */
ret = fcntl(event->fd, F_SETFD, FD_CLOEXEC);
if (ret < 0) {
- perror("fcntl session fd");
+ PERROR("fcntl session fd");
}
add_list:
ret = kernctl_disable(chan->fd);
if (ret < 0) {
- perror("disable chan ioctl");
+ PERROR("disable chan ioctl");
ret = errno;
goto error;
}
ret = kernctl_enable(chan->fd);
if (ret < 0 && errno != EEXIST) {
- perror("Enable kernel chan");
+ PERROR("Enable kernel chan");
goto error;
}
ret = kernctl_enable(event->fd);
if (ret < 0 && errno != EEXIST) {
- perror("enable kernel event");
+ PERROR("enable kernel event");
goto error;
}
ret = kernctl_disable(event->fd);
if (ret < 0 && errno != EEXIST) {
- perror("disable kernel event");
+ PERROR("disable kernel event");
goto error;
}
/* Prevent fd duplication after execlp() */
ret = fcntl(lkm->fd, F_SETFD, FD_CLOEXEC);
if (ret < 0) {
- perror("fcntl session fd");
+ PERROR("fcntl session fd");
}
session->metadata = lkm;
ret = kernctl_start_session(session->fd);
if (ret < 0) {
- perror("ioctl start session");
+ PERROR("ioctl start session");
goto error;
}
ret = kernctl_wait_quiescent(fd);
if (ret < 0) {
- perror("wait quiescent ioctl");
+ PERROR("wait quiescent ioctl");
ERR("Kernel quiescent wait failed");
}
}
ret = kernctl_calibrate(fd, calibrate);
if (ret < 0) {
- perror("calibrate ioctl");
+ PERROR("calibrate ioctl");
return -1;
}
DBG("Flushing channel stream %d", stream->fd);
ret = kernctl_buffer_flush(stream->fd);
if (ret < 0) {
- perror("ioctl");
+ PERROR("ioctl");
ERR("Fail to flush buffer for stream %d (ret: %d)",
stream->fd, ret);
}
int ret;
struct ltt_kernel_stream *lks;
- while ((ret = kernctl_create_stream(channel->fd)) > 0) {
+ while ((ret = kernctl_create_stream(channel->fd)) >= 0) {
lks = trace_kernel_create_stream();
if (lks == NULL) {
- close(ret);
+ ret = close(ret);
+ if (ret) {
+ PERROR("close");
+ }
goto error;
}
/* Prevent fd duplication after execlp() */
ret = fcntl(lks->fd, F_SETFD, FD_CLOEXEC);
if (ret < 0) {
- perror("fcntl session fd");
+ PERROR("fcntl session fd");
}
ret = asprintf(&lks->pathname, "%s/%s_%d",
channel->pathname, channel->channel->name, channel->stream_count);
if (ret < 0) {
- perror("asprintf kernel create stream");
+ PERROR("asprintf kernel create stream");
goto error;
}
ret = kernctl_create_stream(session->metadata->fd);
if (ret < 0) {
- perror("kernel create metadata stream");
+ PERROR("kernel create metadata stream");
goto error;
}
/* Prevent fd duplication after execlp() */
ret = fcntl(session->metadata_stream_fd, F_SETFD, FD_CLOEXEC);
if (ret < 0) {
- perror("fcntl session fd");
+ PERROR("fcntl session fd");
}
return 0;
*/
ssize_t kernel_list_events(int tracer_fd, struct lttng_event **events)
{
- int fd, pos;
+ int fd, pos, ret;
char *event;
size_t nbmem, count = 0;
ssize_t size;
fd = kernctl_tracepoint_list(tracer_fd);
if (fd < 0) {
- perror("kernel tracepoint list");
+ PERROR("kernel tracepoint list");
goto error;
}
fp = fdopen(fd, "r");
if (fp == NULL) {
- perror("kernel tracepoint list fdopen");
+ PERROR("kernel tracepoint list fdopen");
goto error_fp;
}
nbmem <<= 1;
elist = realloc(elist, nbmem * sizeof(struct lttng_event));
if (elist == NULL) {
- perror("realloc list events");
+ PERROR("realloc list events");
count = -ENOMEM;
goto end;
}
*events = elist;
DBG("Kernel list events done (%zu events)", count);
end:
- fclose(fp); /* closes both fp and fd */
+ ret = fclose(fp); /* closes both fp and fd */
+ if (ret) {
+ PERROR("fclose");
+ }
return count;
error_fp:
- close(fd);
+ ret = close(fd);
+ if (ret) {
+ PERROR("close");
+ }
error:
return -1;
}
/* Ignore error, we don't really care */
}
}
- fclose(fp);
+ ret = fclose(fp);
+ if (ret) {
+ PERROR("fclose");
+ }
end_boot_id:
-
return 0;
}
#include <urcu/wfqueue.h>
#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/compat/socket.h>
#include "session.h"
#include "ust-app.h"
struct command_ctx {
int ust_sock;
unsigned int lttng_msg_size;
- struct ucred creds;
struct ltt_session *session;
struct lttcomm_lttng_msg *llm;
struct lttcomm_session_msg *lsm;
+ lttng_sock_cred creds;
};
struct ust_command {
*/
#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>
const char default_ust_sock_dir[] = DEFAULT_UST_SOCK_DIR;
const char default_global_apps_pipe[] = DEFAULT_GLOBAL_APPS_PIPE;
-/* Variables */
-int opt_verbose; /* Not static for lttngerr.h */
-int opt_verbose_consumer; /* Not static for lttngerr.h */
-int opt_quiet; /* Not static for lttngerr.h */
-
const char *progname;
const char *opt_tracing_group;
static int opt_sig_parent;
+static int opt_verbose_consumer;
static int opt_daemon;
static int opt_no_kernel;
static int is_root; /* Set to 1 if the daemon is running as root */
.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 char wait_shm_path[PATH_MAX];
/* Sockets and FDs */
-static int client_sock;
-static int apps_sock;
-static int kernel_tracer_fd;
-static int kernel_poll_pipe[2];
+static int client_sock = -1;
+static int apps_sock = -1;
+static int kernel_tracer_fd = -1;
+static int kernel_poll_pipe[2] = { -1, -1 };
/*
* Quit pipe for all threads. This permits a single cancellation point
* for all threads when receiving an event on the pipe.
*/
-static int thread_quit_pipe[2];
+static int thread_quit_pipe[2] = { -1, -1 };
/*
* This pipe is used to inform the thread managing application communication
* that a command is queued and ready to be processed.
*/
-static int apps_cmd_pipe[2];
+static int apps_cmd_pipe[2] = { -1, -1 };
/* Pthread, Mutexes and Semaphores */
static pthread_t apps_thread;
*/
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");
+ 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);
}
*/
static void cleanup(void)
{
- int ret;
+ int ret, i;
char *cmd;
struct ltt_session *sess, *stmp;
if (is_root && !opt_no_kernel) {
DBG2("Closing kernel fd");
- close(kernel_tracer_fd);
+ if (kernel_tracer_fd >= 0) {
+ ret = close(kernel_tracer_fd);
+ if (ret) {
+ PERROR("close");
+ }
+ }
DBG("Unloading kernel modules");
modprobe_remove_lttng_all();
}
- close(thread_quit_pipe[0]);
- close(thread_quit_pipe[1]);
+ /*
+ * Closing all pipes used for communication between threads.
+ */
+ for (i = 0; i < 2; i++) {
+ if (kernel_poll_pipe[i] >= 0) {
+ ret = close(kernel_poll_pipe[i]);
+ if (ret) {
+ PERROR("close");
+ }
+
+ }
+ }
+ for (i = 0; i < 2; i++) {
+ if (thread_quit_pipe[i] >= 0) {
+ ret = close(thread_quit_pipe[i]);
+ if (ret) {
+ PERROR("close");
+ }
+ }
+ }
+ for (i = 0; i < 2; i++) {
+ if (apps_cmd_pipe[i] >= 0) {
+ ret = close(apps_cmd_pipe[i]);
+ if (ret) {
+ PERROR("close");
+ }
+ }
+ }
/* OUTPUT BENCHMARK RESULTS */
bench_init();
DBG("Sending channel %d to consumer", lkm.u.channel.channel_key);
ret = lttcomm_send_unix_sock(sock, &lkm, sizeof(lkm));
if (ret < 0) {
- perror("send consumer channel");
+ PERROR("send consumer channel");
goto error;
}
DBG("Sending stream %d to consumer", lkm.u.stream.stream_key);
ret = lttcomm_send_unix_sock(sock, &lkm, sizeof(lkm));
if (ret < 0) {
- perror("send consumer stream");
+ PERROR("send consumer stream");
goto error;
}
ret = lttcomm_send_fds_unix_sock(sock, &stream->fd, 1);
if (ret < 0) {
- perror("send consumer stream ancillary data");
+ PERROR("send consumer stream ancillary data");
goto error;
}
}
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;
DBG("Sending metadata channel %d to consumer", lkm.u.stream.stream_key);
ret = lttcomm_send_unix_sock(sock, &lkm, sizeof(lkm));
if (ret < 0) {
- perror("send consumer channel");
+ PERROR("send consumer channel");
goto error;
}
DBG("Sending metadata stream %d to consumer", lkm.u.stream.stream_key);
ret = lttcomm_send_unix_sock(sock, &lkm, sizeof(lkm));
if (ret < 0) {
- perror("send consumer stream");
+ PERROR("send consumer stream");
goto error;
}
ret = lttcomm_send_fds_unix_sock(sock, &session->metadata_stream_fd, 1);
if (ret < 0) {
- perror("send consumer stream");
+ PERROR("send consumer stream");
goto error;
}
}
cmd_ctx->llm = zmalloc(sizeof(struct lttcomm_lttng_msg) + buf_size);
if (cmd_ctx->llm == NULL) {
- perror("zmalloc");
+ PERROR("zmalloc");
ret = -ENOMEM;
goto error;
}
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;
}
ret = create_thread_poll_set(&events, 2);
if (ret < 0) {
- goto error;
+ goto error_poll_create;
}
ret = lttng_poll_add(&events, kernel_poll_pipe[0], LPOLLIN);
}
error:
- DBG("Kernel thread dying");
- close(kernel_poll_pipe[0]);
- close(kernel_poll_pipe[1]);
-
lttng_poll_clean(&events);
-
+error_poll_create:
+ DBG("Kernel thread dying");
return NULL;
}
*/
static void *thread_manage_consumer(void *data)
{
- int sock = 0, i, ret, pollfd;
+ int sock = -1, i, ret, pollfd;
uint32_t revents, nb_fd;
enum lttcomm_return_code code;
struct lttng_poll_event events;
ret = lttcomm_listen_unix_sock(consumer_data->err_sock);
if (ret < 0) {
- goto error;
+ goto error_listen;
}
/*
*/
ret = create_thread_poll_set(&events, 2);
if (ret < 0) {
- goto error;
+ goto error_poll;
}
ret = lttng_poll_add(&events, consumer_data->err_sock, LPOLLIN | LPOLLRDHUP);
ERR("consumer return code : %s", lttcomm_get_readable_code(-code));
error:
- DBG("consumer thread dying");
- close(consumer_data->err_sock);
- close(consumer_data->cmd_sock);
- close(sock);
+ if (consumer_data->err_sock >= 0) {
+ ret = close(consumer_data->err_sock);
+ if (ret) {
+ PERROR("close");
+ }
+ }
+ if (consumer_data->cmd_sock >= 0) {
+ ret = close(consumer_data->cmd_sock);
+ if (ret) {
+ PERROR("close");
+ }
+ }
+ if (sock >= 0) {
+ ret = close(sock);
+ if (ret) {
+ PERROR("close");
+ }
+ }
unlink(consumer_data->err_unix_sock_path);
unlink(consumer_data->cmd_unix_sock_path);
consumer_data->pid = 0;
lttng_poll_clean(&events);
+error_poll:
+error_listen:
+ DBG("consumer thread cleanup completed");
return NULL;
}
ret = create_thread_poll_set(&events, 2);
if (ret < 0) {
- goto error;
+ goto error_poll_create;
}
ret = lttng_poll_add(&events, apps_cmd_pipe[0], LPOLLIN | LPOLLRDHUP);
/* Empty pipe */
ret = read(apps_cmd_pipe[0], &ust_cmd, sizeof(ust_cmd));
if (ret < 0 || ret < sizeof(ust_cmd)) {
- perror("read apps cmd pipe");
+ PERROR("read apps cmd pipe");
goto error;
}
tracepoint(ust_register_read_stop);
/*
* We just need here to monitor the close of the UST
* socket and poll set monitor those by default.
+ * Listen on POLLIN (even if we never expect any
+ * data) to ensure that hangup wakes us.
*/
- ret = lttng_poll_add(&events, ust_cmd.sock, 0);
+ ret = lttng_poll_add(&events, ust_cmd.sock, LPOLLIN);
if (ret < 0) {
goto error;
}
}
error:
- DBG("Application communication apps dying");
- close(apps_cmd_pipe[0]);
- close(apps_cmd_pipe[1]);
-
lttng_poll_clean(&events);
-
+error_poll_create:
+ DBG("Application communication apps thread cleanup complete");
rcu_thread_offline();
rcu_unregister_thread();
return NULL;
ret = write(apps_cmd_pipe[1], ust_cmd,
sizeof(struct ust_command));
if (ret < 0) {
- perror("write apps cmd pipe");
+ PERROR("write apps cmd pipe");
if (errno == EBADF) {
/*
* We can't inform the application thread to process
*/
static void *thread_registration_apps(void *data)
{
- int sock = 0, i, ret, pollfd;
+ int sock = -1, i, ret, pollfd;
uint32_t revents, nb_fd;
struct lttng_poll_event events;
/*
ret = lttcomm_listen_unix_sock(apps_sock);
if (ret < 0) {
- goto error;
+ goto error_listen;
}
/*
*/
ret = create_thread_poll_set(&events, 2);
if (ret < 0) {
- goto error;
+ goto error_create_poll;
}
/* Add the application registration socket */
ret = lttng_poll_add(&events, apps_sock, LPOLLIN | LPOLLRDHUP);
if (ret < 0) {
- goto error;
+ goto error_poll_add;
}
/* Notify all applications to register */
/* Create UST registration command for enqueuing */
ust_cmd = zmalloc(sizeof(struct ust_command));
if (ust_cmd == NULL) {
- perror("ust command zmalloc");
+ PERROR("ust command zmalloc");
goto error;
}
sizeof(struct ust_register_msg));
if (ret < 0 || ret < sizeof(struct ust_register_msg)) {
if (ret < 0) {
- perror("lttcomm_recv_unix_sock register apps");
+ PERROR("lttcomm_recv_unix_sock register apps");
} else {
ERR("Wrong size received on apps register");
}
free(ust_cmd);
- close(sock);
+ ret = close(sock);
+ if (ret) {
+ PERROR("close");
+ }
+ sock = -1;
continue;
}
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:
- DBG("UST Registration thread dying");
-
/* Notify that the registration thread is gone */
notify_ust_apps(0);
- close(apps_sock);
- close(sock);
+ if (apps_sock >= 0) {
+ ret = close(apps_sock);
+ if (ret) {
+ PERROR("close");
+ }
+ }
+ if (sock >= 0) {
+ ret = close(sock);
+ if (ret) {
+ PERROR("close");
+ }
+ }
unlink(apps_unix_sock_path);
+error_poll_add:
lttng_poll_clean(&events);
+error_listen:
+error_create_poll:
+ DBG("UST Registration thread cleanup complete");
return NULL;
}
break;
}
default:
- perror("unknown consumer type");
+ PERROR("unknown consumer type");
exit(EXIT_FAILURE);
}
if (errno != 0) {
- perror("kernel start consumer exec");
+ PERROR("kernel start consumer exec");
}
exit(EXIT_FAILURE);
} else if (pid > 0) {
ret = pid;
} else {
- perror("start consumer fork");
+ PERROR("start consumer fork");
ret = -errno;
}
error:
error_version:
modprobe_remove_lttng_control();
- close(kernel_tracer_fd);
- kernel_tracer_fd = 0;
+ ret = close(kernel_tracer_fd);
+ if (ret) {
+ PERROR("close");
+ }
+ kernel_tracer_fd = -1;
return LTTCOMM_KERN_VERSION;
error_modules:
- close(kernel_tracer_fd);
+ ret = close(kernel_tracer_fd);
+ if (ret) {
+ PERROR("close");
+ }
error_open:
modprobe_remove_lttng_control();
error:
WARN("No kernel tracer available");
- kernel_tracer_fd = 0;
- return LTTCOMM_KERN_NA;
+ kernel_tracer_fd = -1;
+ 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;
}
usess = session->ust_session;
if (session->enabled) {
- ret = LTTCOMM_UST_START_FAIL;
+ /* Already started. */
+ ret = LTTCOMM_TRACE_ALREADY_STARTED;
goto error;
}
}
/* 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");
usess = session->ust_session;
if (!session->enabled) {
- ret = LTTCOMM_UST_STOP_FAIL;
+ ret = LTTCOMM_TRACE_ALREADY_STOPPED;
goto error;
}
/*
* 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;
}
*/
ret = notify_thread_pipe(kernel_poll_pipe[1]);
if (ret < 0) {
- perror("write kernel poll pipe");
+ PERROR("write kernel poll pipe");
}
ret = session_destroy(session);
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;
}
/* Kernel tracer check */
- if (kernel_tracer_fd == 0) {
+ if (kernel_tracer_fd == -1) {
/* Basically, load kernel tracer modules */
ret = init_kernel_tracer();
if (ret != 0) {
*/
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 void *thread_manage_clients(void *data)
{
- int sock = 0, ret, i, pollfd;
+ int sock = -1, ret, i, pollfd;
uint32_t revents, nb_fd;
struct command_ctx *cmd_ctx = NULL;
struct lttng_poll_event events;
/* Allocate context command to process the client request */
cmd_ctx = zmalloc(sizeof(struct command_ctx));
if (cmd_ctx == NULL) {
- perror("zmalloc cmd_ctx");
+ PERROR("zmalloc cmd_ctx");
goto error;
}
/* Allocate data buffer for reception */
cmd_ctx->lsm = zmalloc(sizeof(struct lttcomm_session_msg));
if (cmd_ctx->lsm == NULL) {
- perror("zmalloc cmd_ctx->lsm");
+ PERROR("zmalloc cmd_ctx->lsm");
goto error;
}
sizeof(struct lttcomm_session_msg), &cmd_ctx->creds);
if (ret <= 0) {
DBG("Nothing recv() from client... continuing");
- close(sock);
+ ret = close(sock);
+ if (ret) {
+ PERROR("close");
+ }
+ sock = -1;
free(cmd_ctx);
continue;
}
}
/* End of transmission */
- close(sock);
+ ret = close(sock);
+ if (ret) {
+ PERROR("close");
+ }
+ sock = -1;
clean_command_ctx(&cmd_ctx);
}
error:
DBG("Client thread dying");
unlink(client_unix_sock_path);
- close(client_sock);
- close(sock);
+ if (client_sock >= 0) {
+ ret = close(client_sock);
+ if (ret) {
+ PERROR("close");
+ }
+ }
+ if (sock >= 0) {
+ ret = close(sock);
+ if (ret) {
+ PERROR("close");
+ }
+ }
lttng_poll_clean(&events);
clean_command_ctx(&cmd_ctx);
opt_no_kernel = 1;
break;
case 'q':
- opt_quiet = 1;
+ lttng_opt_quiet = 1;
break;
case 'v':
/* Verbose level can increase using multiple -v */
- opt_verbose += 1;
+ lttng_opt_verbose += 1;
break;
case 'Z':
opt_verbose_consumer += 1;
ret = chmod(client_unix_sock_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (ret < 0) {
ERR("Set file permissions failed: %s", client_unix_sock_path);
- perror("chmod");
+ PERROR("chmod");
goto end;
}
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (ret < 0) {
ERR("Set file permissions failed: %s", apps_unix_sock_path);
- perror("chmod");
+ PERROR("chmod");
goto end;
}
ret = chown(rundir, 0, gid);
if (ret < 0) {
ERR("Unable to set group on %s", rundir);
- perror("chown");
+ PERROR("chown");
}
/* Ensure tracing group can search the run dir */
- ret = chmod(rundir, S_IRWXU | S_IXGRP);
+ ret = chmod(rundir, S_IRWXU | S_IXGRP | S_IXOTH);
if (ret < 0) {
ERR("Unable to set permissions on %s", rundir);
- perror("chmod");
+ PERROR("chmod");
}
/* lttng client socket path */
ret = chown(client_unix_sock_path, 0, gid);
if (ret < 0) {
ERR("Unable to set group on %s", client_unix_sock_path);
- perror("chown");
+ PERROR("chown");
}
/* kconsumer error socket path */
ret = chown(kconsumer_data.err_unix_sock_path, 0, gid);
if (ret < 0) {
ERR("Unable to set group on %s", kconsumer_data.err_unix_sock_path);
- perror("chown");
+ PERROR("chown");
}
/* 64-bit ustconsumer error socket path */
ret = chown(ustconsumer64_data.err_unix_sock_path, 0, gid);
if (ret < 0) {
ERR("Unable to set group on %s", ustconsumer64_data.err_unix_sock_path);
- perror("chown");
+ PERROR("chown");
}
/* 32-bit ustconsumer compat32 error socket path */
ret = chown(ustconsumer32_data.err_unix_sock_path, 0, gid);
if (ret < 0) {
ERR("Unable to set group on %s", ustconsumer32_data.err_unix_sock_path);
- perror("chown");
+ PERROR("chown");
}
DBG("All permissions are set");
/*
* Create the pipe used to wake up the kernel thread.
+ * Closed in cleanup().
*/
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;
}
/*
* Create the application command pipe to wake thread_manage_apps.
+ * Closed in cleanup().
*/
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;
}
/*
ret = mkdir(path, S_IRWXU);
if (ret < 0) {
if (errno != EEXIST) {
+ PERROR("mkdir");
ERR("Failed to create %s", path);
goto error;
}
- ret = 0;
+ ret = -1;
}
/* Create the kconsumerd error unix socket */
sigset_t sigset;
if ((ret = sigemptyset(&sigset)) < 0) {
- perror("sigemptyset");
+ PERROR("sigemptyset");
return ret;
}
sa.sa_mask = sigset;
sa.sa_flags = 0;
if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
- perror("sigaction");
+ PERROR("sigaction");
return ret;
}
if ((ret = sigaction(SIGINT, &sa, NULL)) < 0) {
- perror("sigaction");
+ PERROR("sigaction");
return ret;
}
if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) {
- perror("sigaction");
+ PERROR("sigaction");
return ret;
}
ret = setrlimit(RLIMIT_NOFILE, &lim);
if (ret < 0) {
- perror("failed to set open files limit");
+ PERROR("failed to set open files limit");
}
}
if (opt_daemon) {
ret = daemon(0, 0);
if (ret < 0) {
- perror("daemon");
+ PERROR("daemon");
goto error;
}
}
ret = pthread_create(&client_thread, NULL,
thread_manage_clients, (void *) NULL);
if (ret != 0) {
- perror("pthread_create clients");
+ PERROR("pthread_create clients");
goto exit_client;
}
ret = pthread_create(&dispatch_thread, NULL,
thread_dispatch_ust_registration, (void *) NULL);
if (ret != 0) {
- perror("pthread_create dispatch");
+ PERROR("pthread_create dispatch");
goto exit_dispatch;
}
ret = pthread_create(®_apps_thread, NULL,
thread_registration_apps, (void *) NULL);
if (ret != 0) {
- perror("pthread_create registration");
+ PERROR("pthread_create registration");
goto exit_reg_apps;
}
ret = pthread_create(&apps_thread, NULL,
thread_manage_apps, (void *) NULL);
if (ret != 0) {
- perror("pthread_create apps");
+ PERROR("pthread_create apps");
goto exit_apps;
}
ret = pthread_create(&kernel_thread, NULL,
thread_manage_kernel, (void *) NULL);
if (ret != 0) {
- perror("pthread_create kernel");
+ PERROR("pthread_create kernel");
goto exit_kernel;
}
ret = pthread_join(kernel_thread, &status);
if (ret != 0) {
- perror("pthread_join");
+ PERROR("pthread_join");
goto error; /* join error, exit without cleanup */
}
exit_kernel:
ret = pthread_join(apps_thread, &status);
if (ret != 0) {
- perror("pthread_join");
+ PERROR("pthread_join");
goto error; /* join error, exit without cleanup */
}
exit_apps:
ret = pthread_join(reg_apps_thread, &status);
if (ret != 0) {
- perror("pthread_join");
+ PERROR("pthread_join");
goto error; /* join error, exit without cleanup */
}
exit_reg_apps:
ret = pthread_join(dispatch_thread, &status);
if (ret != 0) {
- perror("pthread_join");
+ PERROR("pthread_join");
goto error; /* join error, exit without cleanup */
}
exit_dispatch:
ret = pthread_join(client_thread, &status);
if (ret != 0) {
- perror("pthread_join");
+ PERROR("pthread_join");
goto error; /* join error, exit without cleanup */
}
ret = join_consumer_thread(&kconsumer_data);
if (ret != 0) {
- perror("join_consumer");
+ PERROR("join_consumer");
goto error; /* join error, exit without cleanup */
}
"/sbin/modprobe -r -q %s",
kern_modules_list[i].name);
if (ret < 0) {
- perror("snprintf modprobe -r");
+ PERROR("snprintf modprobe -r");
goto error;
}
modprobe[sizeof(modprobe) - 1] = '\0';
kern_modules_list[i].required ? "" : "-q ",
kern_modules_list[i].name);
if (ret < 0) {
- perror("snprintf modprobe");
+ PERROR("snprintf modprobe");
goto error;
}
modprobe[sizeof(modprobe) - 1] = '\0';
/* Allocate session data structure */
new_session = zmalloc(sizeof(struct ltt_session));
if (new_session == NULL) {
- perror("zmalloc");
+ PERROR("zmalloc");
ret = LTTCOMM_FATAL;
goto error_malloc;
}
ret = chown(shm_path, 0, 0);
if (ret < 0) {
if (errno != ENOENT) {
- perror("chown wait shm");
+ PERROR("chown wait shm");
goto error;
}
}
ret = chown(shm_path, getuid(), getgid());
if (ret < 0) {
if (errno != ENOENT) {
- perror("chown wait shm");
+ PERROR("chown wait shm");
goto error;
}
}
ret = chmod(shm_path, mode);
if (ret < 0) {
if (errno != ENOENT) {
- perror("chmod wait shm");
+ PERROR("chmod wait shm");
goto error;
}
}
*/
wait_shm_fd = shm_open(shm_path, O_RDWR | O_CREAT, mode);
if (wait_shm_fd < 0) {
- perror("shm_open wait shm");
+ PERROR("shm_open wait shm");
goto error;
}
ret = ftruncate(wait_shm_fd, mmap_size);
if (ret < 0) {
- perror("ftruncate wait shm");
+ PERROR("ftruncate wait shm");
exit(EXIT_FAILURE);
}
+#ifndef __FreeBSD__
ret = fchmod(wait_shm_fd, mode);
if (ret < 0) {
- perror("fchmod");
+ PERROR("fchmod");
exit(EXIT_FAILURE);
}
+#else
+#warning "FreeBSD does not support setting file mode on shm FD. Remember that for secure use, lttng-sessiond should be started before applications linked on lttng-ust."
+#endif
tracepoint(ust_notify_shm_stop);
/* close shm fd immediately after taking the mmap reference */
ret = close(wait_shm_fd);
if (ret) {
- perror("Error closing fd");
+ PERROR("Error closing fd");
}
if (wait_shm_mmap == MAP_FAILED) {
/* Allocate a new ltt kernel session */
lks = zmalloc(sizeof(struct ltt_kernel_session));
if (lks == NULL) {
- perror("create kernel session zmalloc");
+ PERROR("create kernel session zmalloc");
goto error;
}
/* Init data structure */
- lks->fd = 0;
- lks->metadata_stream_fd = 0;
+ lks->fd = -1;
+ lks->metadata_stream_fd = -1;
lks->channel_count = 0;
lks->stream_count_global = 0;
lks->metadata = NULL;
- lks->consumer_fd = 0;
+ lks->consumer_fd = -1;
CDS_INIT_LIST_HEAD(&lks->channel_list.head);
/* Set session path */
ret = asprintf(&lks->trace_path, "%s/kernel", path);
if (ret < 0) {
- perror("asprintf kernel traces path");
+ PERROR("asprintf kernel traces path");
goto error;
}
lkc = zmalloc(sizeof(struct ltt_kernel_channel));
if (lkc == NULL) {
- perror("ltt_kernel_channel zmalloc");
+ PERROR("ltt_kernel_channel zmalloc");
goto error;
}
lkc->channel = zmalloc(sizeof(struct lttng_channel));
if (lkc->channel == NULL) {
- perror("lttng_channel zmalloc");
+ PERROR("lttng_channel zmalloc");
goto error;
}
memcpy(lkc->channel, chan, sizeof(struct lttng_channel));
- lkc->fd = 0;
+ lkc->fd = -1;
lkc->stream_count = 0;
lkc->event_count = 0;
lkc->enabled = 1;
/* Set default trace output path */
ret = asprintf(&lkc->pathname, "%s", path);
if (ret < 0) {
- perror("asprintf kernel create channel");
+ PERROR("asprintf kernel create channel");
goto error;
}
lke = zmalloc(sizeof(struct ltt_kernel_event));
attr = zmalloc(sizeof(struct lttng_kernel_event));
if (lke == NULL || attr == NULL) {
- perror("kernel event zmalloc");
+ PERROR("kernel event zmalloc");
goto error;
}
attr->name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
/* Setting up a kernel event */
- lke->fd = 0;
+ lke->fd = -1;
lke->event = attr;
lke->enabled = 1;
lke->ctx = NULL;
lkm = zmalloc(sizeof(struct ltt_kernel_metadata));
chan = zmalloc(sizeof(struct lttng_channel));
if (lkm == NULL || chan == NULL) {
- perror("kernel metadata zmalloc");
+ PERROR("kernel metadata zmalloc");
goto error;
}
chan->attr.output = DEFAULT_KERNEL_CHANNEL_OUTPUT;
/* Init metadata */
- lkm->fd = 0;
+ lkm->fd = -1;
lkm->conf = chan;
/* Set default metadata path */
ret = asprintf(&lkm->pathname, "%s/metadata", path);
if (ret < 0) {
- perror("asprintf kernel metadata");
+ PERROR("asprintf kernel metadata");
goto error;
}
lks = zmalloc(sizeof(struct ltt_kernel_stream));
if (lks == NULL) {
- perror("kernel stream zmalloc");
+ PERROR("kernel stream zmalloc");
goto error;
}
/* Init stream */
- lks->fd = 0;
+ lks->fd = -1;
lks->pathname = NULL;
lks->state = 0;
*/
void trace_kernel_destroy_stream(struct ltt_kernel_stream *stream)
{
+ int ret;
+
DBG("[trace] Closing stream fd %d", stream->fd);
/* Close kernel fd */
- close(stream->fd);
+ if (stream->fd >= 0) {
+ ret = close(stream->fd);
+ if (ret) {
+ PERROR("close");
+ }
+ }
/* Remove from stream list */
cds_list_del(&stream->list);
*/
void trace_kernel_destroy_event(struct ltt_kernel_event *event)
{
- DBG("[trace] Closing event fd %d", event->fd);
- /* Close kernel fd */
- close(event->fd);
+ int ret;
+
+ if (event->fd >= 0) {
+ DBG("[trace] Closing event fd %d", event->fd);
+ /* Close kernel fd */
+ ret = close(event->fd);
+ if (ret) {
+ PERROR("close");
+ }
+ } else {
+ DBG("[trace] Tearing down event (no associated fd)");
+ }
/* Remove from event list */
cds_list_del(&event->list);
{
struct ltt_kernel_stream *stream, *stmp;
struct ltt_kernel_event *event, *etmp;
+ int ret;
DBG("[trace] Closing channel fd %d", channel->fd);
/* Close kernel fd */
- close(channel->fd);
+ if (channel->fd >= 0) {
+ ret = close(channel->fd);
+ if (ret) {
+ PERROR("close");
+ }
+ }
/* For each stream in the channel list */
cds_list_for_each_entry_safe(stream, stmp, &channel->stream_list.head, list) {
*/
void trace_kernel_destroy_metadata(struct ltt_kernel_metadata *metadata)
{
+ int ret;
+
DBG("[trace] Closing metadata fd %d", metadata->fd);
/* Close kernel fd */
- close(metadata->fd);
+ if (metadata->fd >= 0) {
+ ret = close(metadata->fd);
+ if (ret) {
+ PERROR("close");
+ }
+ }
free(metadata->conf);
free(metadata->pathname);
void trace_kernel_destroy_session(struct ltt_kernel_session *session)
{
struct ltt_kernel_channel *channel, *ctmp;
+ int ret;
DBG("[trace] Closing session fd %d", session->fd);
/* Close kernel fds */
- close(session->fd);
+ if (session->fd >= 0) {
+ ret = close(session->fd);
+ if (ret) {
+ PERROR("close");
+ }
+ }
- if (session->metadata_stream_fd != 0) {
+ if (session->metadata_stream_fd >= 0) {
DBG("[trace] Closing metadata stream fd %d", session->metadata_stream_fd);
- close(session->metadata_stream_fd);
+ ret = close(session->metadata_stream_fd);
+ if (ret) {
+ PERROR("close");
+ }
}
if (session->metadata != NULL) {
luc = zmalloc(sizeof(struct ltt_ust_channel));
if (luc == NULL) {
- perror("ltt_ust_channel zmalloc");
+ PERROR("ltt_ust_channel zmalloc");
goto error;
}
/* Set trace output path */
ret = snprintf(luc->pathname, PATH_MAX, "%s", path);
if (ret < 0) {
- perror("asprintf ust create channel");
+ PERROR("asprintf ust create channel");
goto error_free_channel;
}
lue->attr.loglevel = ev->loglevel;
break;
default:
- ERR("Unknown ust loglevel type (%d)", ev->type);
+ ERR("Unknown ust loglevel type (%d)", ev->loglevel_type);
goto error_free_event;
}
lum = zmalloc(sizeof(struct ltt_ust_metadata));
if (lum == NULL) {
- perror("ust metadata zmalloc");
+ PERROR("ust metadata zmalloc");
goto error;
}
/* Set metadata trace path */
ret = snprintf(lum->pathname, PATH_MAX, "%s/metadata", path);
if (ret < 0) {
- perror("asprintf ust metadata");
+ PERROR("asprintf ust metadata");
goto error_free_metadata;
}
* closing this socket, otherwise an application could re-use the socket ID
* and race with the teardown, using the same hash table entry.
*/
- close(sock);
+ ret = close(sock);
+ if (ret) {
+ PERROR("close");
+ }
DBG2("UST app pid %d deleted", app->key.pid);
free(app);
int ust_app_register(struct ust_register_msg *msg, int sock)
{
struct ust_app *lta;
+ int ret;
if ((msg->bits_per_long == 64 && ust_consumerd64_fd == -EINVAL)
|| (msg->bits_per_long == 32 && ust_consumerd32_fd == -EINVAL)) {
ERR("Registration failed: application \"%s\" (pid: %d) has "
"%d-bit long, but no consumerd for this long size is available.\n",
msg->name, msg->pid, msg->bits_per_long);
- close(sock);
+ ret = close(sock);
+ if (ret) {
+ PERROR("close");
+ }
return -EINVAL;
}
if (msg->major != LTTNG_UST_COMM_MAJOR) {
ERR("Registration failed: application \"%s\" (pid: %d) has "
"communication protocol version %u.%u, but sessiond supports 2.x.\n",
msg->name, msg->pid, msg->major, msg->minor);
- close(sock);
+ ret = close(sock);
+ if (ret) {
+ PERROR("close");
+ }
return -EINVAL;
}
lta = zmalloc(sizeof(struct ust_app));
DBG("Sending channel %d to consumer", lum.u.channel.channel_key);
ret = lttcomm_send_unix_sock(sock, &lum, sizeof(lum));
if (ret < 0) {
- perror("send consumer channel");
+ PERROR("send consumer channel");
goto error;
}
fd = uchan->obj->shm_fd;
ret = lttcomm_send_fds_unix_sock(sock, &fd, 1);
if (ret < 0) {
- perror("send consumer channel ancillary data");
+ PERROR("send consumer channel ancillary data");
goto error;
}
DBG("Sending stream %d to consumer", lum.u.stream.stream_key);
ret = lttcomm_send_unix_sock(sock, &lum, sizeof(lum));
if (ret < 0) {
- perror("send consumer stream");
+ PERROR("send consumer stream");
goto error;
}
fds[1] = stream->obj->wait_fd;
ret = lttcomm_send_fds_unix_sock(sock, fds, 2);
if (ret < 0) {
- perror("send consumer stream ancillary data");
+ PERROR("send consumer stream ancillary data");
goto error;
}
}
DBG("Sending metadata channel %d to consumer", lum.u.channel.channel_key);
ret = lttcomm_send_unix_sock(sock, &lum, sizeof(lum));
if (ret < 0) {
- perror("send consumer channel");
+ PERROR("send consumer channel");
goto error;
}
fd = usess->metadata->obj->shm_fd;
ret = lttcomm_send_fds_unix_sock(sock, &fd, 1);
if (ret < 0) {
- perror("send consumer metadata channel");
+ PERROR("send consumer metadata channel");
goto error;
}
DBG("Sending metadata stream %d to consumer", lum.u.stream.stream_key);
ret = lttcomm_send_unix_sock(sock, &lum, sizeof(lum));
if (ret < 0) {
- perror("send consumer metadata stream");
+ PERROR("send consumer metadata stream");
goto error;
}
fds[0] = usess->metadata->stream_obj->shm_fd;
fds[1] = usess->metadata->stream_obj->wait_fd;
ret = lttcomm_send_fds_unix_sock(sock, fds, 2);
if (ret < 0) {
- perror("send consumer stream");
+ PERROR("send consumer stream");
goto error;
}
}
#include <sys/wait.h>
#include <unistd.h>
#include <config.h>
+#include <ctype.h>
#include <lttng/lttng.h>
#include <common/error.h>
/* Variables */
static char *progname;
-
-int opt_quiet;
-int opt_verbose;
static int opt_no_sessiond;
static char *opt_sessiond_path;
static pid_t sessiond_pid;
ret = 0;
goto end;
case 'v':
- opt_verbose += 1;
+ lttng_opt_verbose += 1;
break;
case 'q':
- opt_quiet = 1;
+ lttng_opt_quiet = 1;
break;
case 'g':
lttng_set_tracing_group(optarg);
}
/* If both options are specified, quiet wins */
- if (opt_verbose && opt_quiet) {
- opt_verbose = 0;
+ if (lttng_opt_verbose && lttng_opt_quiet) {
+ lttng_opt_verbose = 0;
}
/* Spawn session daemon if needed */
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#define _GNU_SOURCE
#include <stdlib.h>
#include <ctype.h>
libcommon_la_SOURCES = runas.c runas.h common.h
+if COMPAT_EPOLL
+COMPAT=compat/compat-epoll.c
+else
+COMPAT=compat/compat-poll.c
+endif
+
+noinst_LTLIBRARIES += libcompat.la
+
+libcompat_la_SOURCES = compat/poll.h compat/fcntl.h compat/splice.h compat/endian.h \
+ compat/socket.h compat/compat-fcntl.c $(COMPAT)
+
# Consumer library
noinst_LTLIBRARIES += libconsumer.la
libconsumer_la_LIBADD = \
$(top_builddir)/src/common/sessiond-comm/libsessiond-comm.la \
$(top_builddir)/src/common/kernel-consumer/libkernel-consumer.la \
- $(top_builddir)/src/common/hashtable/libhashtable.la
+ $(top_builddir)/src/common/hashtable/libhashtable.la \
+ $(top_builddir)/src/common/libcompat.la
if HAVE_LIBLTTNG_UST_CTL
libconsumer_la_LIBADD += \
$(top_builddir)/src/common/ust-consumer/libust-consumer.la
endif
-
-if COMPAT_EPOLL
-COMPAT=compat/compat-epoll.c
-else
-COMPAT=compat/compat-poll.c
-endif
-
-noinst_LTLIBRARIES += libcompat.la
-
-libcompat_la_SOURCES = compat/poll.h $(COMPAT)
--- /dev/null
+/*
+ * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; only version 2 of the License.
+ *
+ * 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _COMPAT_CLONE_H
+#define _COMPAT_CLONE_H
+
+#ifdef __linux__
+
+#include <sched.h>
+
+static inline
+pid_t lttng_clone_files(int (*fn)(void *), void *child_stack, void *arg)
+{
+ return clone(fn, child_stack, CLONE_FILES | SIGCHLD, arg);
+}
+
+#elif defined(__FreeBSD__)
+
+#include <unistd.h>
+
+static inline
+pid_t lttng_clone_files(int (*fn)(void *), void *child_stack, void *arg)
+{
+ pid_t pid;
+
+ pid = rfork(RFPROC | RFTHREAD);
+ if (pid == 0) {
+ /* child */
+ int ret;
+
+ ret = fn(arg);
+ exit(ret);
+ } else if (pid > 0) {
+ /* parent */
+ /*
+ * Just return, the caller will wait for the child.
+ */
+ return pid;
+ } else {
+ /* Error */
+ return pid;
+ }
+}
+
+#else
+#error "Please add support for your OS."
+#endif /* __linux__ , __FreeBSD__ */
+
+#endif /* _COMPAT_CLONE_H */
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#define _GNU_SOURCE
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
ret = epoll_create1(flags);
if (ret < 0) {
/* At this point, every error is fatal */
- perror("epoll_create1");
+ PERROR("epoll_create1");
goto error;
}
/* This *must* be freed by using lttng_poll_free() */
events->events = zmalloc(size * sizeof(struct epoll_event));
if (events->events == NULL) {
- perror("zmalloc epoll set");
+ PERROR("zmalloc epoll set");
goto error_close;
}
return 0;
error_close:
- close(events->epfd);
+ ret = close(events->epfd);
+ if (ret) {
+ PERROR("close");
+ }
error:
return -1;
}
goto end;
case ENOSPC:
case EPERM:
- /* Print perror and goto end not failing. Show must go on. */
- perror("epoll_ctl ADD");
+ /* Print PERROR and goto end not failing. Show must go on. */
+ PERROR("epoll_ctl ADD");
goto end;
default:
- perror("epoll_ctl ADD fatal");
+ PERROR("epoll_ctl ADD fatal");
goto error;
}
}
new_size = 2 * events->events_size;
ptr = realloc(events->events, new_size * sizeof(struct epoll_event));
if (ptr == NULL) {
- perror("realloc epoll add");
+ PERROR("realloc epoll add");
goto error;
}
events->events = ptr;
switch (errno) {
case ENOENT:
case EPERM:
- /* Print perror and goto end not failing. Show must go on. */
- perror("epoll_ctl DEL");
+ /* Print PERROR and goto end not failing. Show must go on. */
+ PERROR("epoll_ctl DEL");
goto end;
default:
- perror("epoll_ctl DEL fatal");
+ PERROR("epoll_ctl DEL fatal");
goto error;
}
- perror("epoll_ctl del");
+ PERROR("epoll_ctl del");
goto error;
}
} while (ret == -1 && errno == EINTR);
if (ret < 0) {
/* At this point, every error is fatal */
- perror("epoll_wait");
+ PERROR("epoll_wait");
goto error;
}
ret = read(fd, buf, sizeof(buf));
if (ret < 0) {
- perror("read set max size");
+ PERROR("read set max size");
goto error;
}
DBG("epoll set max size is %d", poll_max_size);
error:
- close(fd);
+ ret = close(fd);
+ if (ret) {
+ PERROR("close");
+ }
}
--- /dev/null
+/*
+ * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; only version 2 of the License.
+ *
+ * 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#include <common/compat/fcntl.h>
+
+#ifdef __linux__
+
+int compat_sync_file_range(int fd, off64_t offset, off64_t nbytes,
+ unsigned int flags)
+{
+ return sync_file_range(fd, offset, nbytes, flags);
+}
+
+#endif /* __linux__ */
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#define _GNU_SOURCE
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/time.h>
--- /dev/null
+/*
+ * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; only version 2 of the License.
+ *
+ * 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef _COMPAT_ENDIAN_H
+#define _COMPAT_ENDIAN_H
+
+#ifdef __linux__
+#include <endian.h>
+#elif defined(__FreeBSD__)
+#include <machine/endian.h>
+#else
+#error "Please add support for your OS."
+#endif
+
+#endif /* _COMPAT_ENDIAN_H */
--- /dev/null
+/*
+ * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; only version 2 of the License.
+ *
+ * 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _COMPAT_FCNTL_H
+#define _COMPAT_FCNTL_H
+
+#include <fcntl.h>
+#include <sys/types.h>
+
+#ifdef __linux__
+
+extern int compat_sync_file_range(int fd, off64_t offset, off64_t nbytes,
+ unsigned int flags);
+#define lttng_sync_file_range(fd, offset, nbytes, flags) \
+ compat_sync_file_range(fd, offset, nbytes, flags)
+
+#elif defined(__FreeBSD__)
+
+typedef long int off64_t;
+typedef off64_t loff_t;
+
+#include <sys/errno.h>
+
+/*
+ * Possible flags under Linux. Simply nullify them and avoid wrapper.
+ */
+#define SYNC_FILE_RANGE_WAIT_AFTER 0
+#define SYNC_FILE_RANGE_WAIT_BEFORE 0
+#define SYNC_FILE_RANGE_WRITE 0
+
+/*
+ * Possible flags under Linux. Simply nullify them and avoid wrappers.
+ */
+#define SPLICE_F_MOVE 0
+#define SPLICE_F_NONBLOCK 0
+#define SPLICE_F_MORE 0
+#define SPLICE_F_GIFT 0
+
+#define POSIX_FADV_DONTNEED 0
+
+static inline int lttng_sync_file_range(int fd, off64_t offset,
+ off64_t nbytes, unsigned int flags)
+{
+ return -ENOSYS;
+}
+
+static inline ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out,
+ size_t len, unsigned int flags)
+{
+ return -ENOSYS;
+}
+
+static inline int posix_fadvise(int fd, off_t offset, off_t len, int advice)
+{
+ return -ENOSYS;
+}
+
+#else
+#error "Please add support for your OS."
+#endif /* __linux__ , __FreeBSD__ */
+
+#endif /* _COMPAT_FCNTL_H */
--- /dev/null
+/*
+ * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; only version 2 of the License.
+ *
+ * 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _COMPAT_MMAN_H
+#define _COMPAT_MMAN_H
+
+#include <sys/mman.h>
+
+#ifdef __linux__
+
+#elif defined(__FreeBSD__)
+
+#define MAP_GROWSDOWN 0
+#define MAP_ANONYMOUS MAP_ANON
+
+#else
+#error "Please add support for your OS."
+#endif /* __linux__ , __FreeBSD__ */
+
+#endif /* _COMPAT_MMAN_H */
*/
#ifdef HAVE_EPOLL
#include <sys/epoll.h>
+#include <stdio.h>
/* See man epoll(7) for this define path */
#define COMPAT_EPOLL_PROC_PATH "/proc/sys/fs/epoll/max_user_watches"
*/
static inline void lttng_poll_clean(struct lttng_poll_event *events)
{
+ int ret;
+
if (events) {
- close(events->epfd);
+ ret = close(events->epfd);
+ if (ret) {
+ perror("close");
+ }
__lttng_poll_free((void *) events->events);
}
}
LPOLLRDBAND = POLLRDBAND,
LPOLLWRNORM = POLLWRNORM,
LPOLLWRBAND = POLLWRBAND,
+#if __linux__
LPOLLMSG = POLLMSG,
+ LPOLLRDHUP = POLLRDHUP,
+#elif defined(__FreeBSD__)
+ LPOLLMSG = 0,
+ LPOLLRDHUP = 0,
+#else
+#error "Please add support for your OS."
+#endif /* __linux__ */
LPOLLERR = POLLERR,
LPOLLHUP = POLLHUP | POLLNVAL,
- LPOLLRDHUP = POLLRDHUP,
/* Close on exec feature does not exist for poll(2) */
LTTNG_CLOEXEC = 0xdead,
};
--- /dev/null
+/*
+ * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; only version 2 of the License.
+ *
+ * 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _COMPAT_SOCKET_H
+#define _COMPAT_SOCKET_H
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <common/macros.h>
+
+#ifdef __linux__
+
+#define LTTNG_SOCK_CREDS SCM_CREDENTIALS
+
+typedef struct ucred lttng_sock_cred;
+
+#define LTTNG_SOCK_SET_UID_CRED(c, u) LTTNG_REF(c)->uid = u
+#define LTTNG_SOCK_SET_GID_CRED(c, g) LTTNG_REF(c)->gid = g
+#define LTTNG_SOCK_SET_PID_CRED(c, p) LTTNG_REF(c)->pid = p
+
+#define LTTNG_SOCK_GET_UID_CRED(c) LTTNG_REF(c)->uid
+#define LTTNG_SOCK_GET_GID_CRED(c) LTTNG_REF(c)->gid
+#define LTTNG_SOCK_GET_PID_CRED(c) LTTNG_REF(c)->pid
+
+#elif defined(__FreeBSD__)
+
+struct lttng_sock_cred {
+ uid_t uid;
+ gid_t gid;
+};
+
+typedef struct lttng_sock_cred lttng_sock_cred;
+
+#define LTTNG_SOCK_GET_UID_CRED(c) LTTNG_REF(c)->uid
+#define LTTNG_SOCK_GET_GID_CRED(c) LTTNG_REF(c)->gid
+#define LTTNG_SOCK_GET_PID_CRED(c) -1
+
+#else
+#error "Please add support for your OS."
+#endif /* __linux__ , __FreeBSD__ */
+
+#endif /* _COMPAT_SOCKET_H */
#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
+void consumer_free_stream(struct rcu_head *head)
+{
+ struct lttng_ht_node_ulong *node =
+ caa_container_of(head, struct lttng_ht_node_ulong, head);
+ struct lttng_consumer_stream *stream =
+ caa_container_of(node, struct lttng_consumer_stream, node);
+
+ free(stream);
}
/*
}
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 */
+ iter.iter.node = &stream->node.node;
ret = lttng_ht_del(consumer_data.stream_ht, &iter);
assert(!ret);
goto end;
}
if (stream->out_fd >= 0) {
- close(stream->out_fd);
+ ret = close(stream->out_fd);
+ if (ret) {
+ PERROR("close");
+ }
}
if (stream->wait_fd >= 0 && !stream->wait_fd_is_copy) {
- close(stream->wait_fd);
+ ret = close(stream->wait_fd);
+ if (ret) {
+ PERROR("close");
+ }
}
if (stream->shm_fd >= 0 && stream->wait_fd != stream->shm_fd) {
- close(stream->shm_fd);
+ ret = close(stream->shm_fd);
+ if (ret) {
+ PERROR("close");
+ }
}
if (!--stream->chan->refcount)
free_chan = stream->chan;
- free(stream);
+
+ call_rcu(&stream->node.head, consumer_free_stream);
end:
consumer_data.need_update = 1;
pthread_mutex_unlock(&consumer_data.lock);
consumer_del_channel(free_chan);
}
-static void consumer_del_stream_rcu(struct rcu_head *head)
-{
- struct lttng_ht_node_ulong *node =
- caa_container_of(head, struct lttng_ht_node_ulong, head);
- struct lttng_consumer_stream *stream =
- caa_container_of(node, struct lttng_consumer_stream, node);
-
- consumer_del_stream(stream);
-}
-
struct lttng_consumer_stream *consumer_allocate_stream(
int channel_key, int stream_key,
int shm_fd, int wait_fd,
end:
pthread_mutex_unlock(&consumer_data.lock);
+
return ret;
}
pthread_mutex_unlock(&consumer_data.lock);
}
+static
+void consumer_free_channel(struct rcu_head *head)
+{
+ struct lttng_ht_node_ulong *node =
+ caa_container_of(head, struct lttng_ht_node_ulong, head);
+ struct lttng_consumer_channel *channel =
+ caa_container_of(node, struct lttng_consumer_channel, node);
+
+ free(channel);
+}
+
/*
* Remove a channel from the global list protected by a mutex. This
* function is also responsible for freeing its data structures.
}
rcu_read_lock();
-
- lttng_ht_lookup(consumer_data.channel_ht,
- (void *)((unsigned long) channel->key), &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) {
}
}
if (channel->wait_fd >= 0 && !channel->wait_fd_is_copy) {
- close(channel->wait_fd);
+ ret = close(channel->wait_fd);
+ if (ret) {
+ PERROR("close");
+ }
}
if (channel->shm_fd >= 0 && channel->wait_fd != channel->shm_fd) {
- close(channel->shm_fd);
+ ret = close(channel->shm_fd);
+ if (ret) {
+ PERROR("close");
+ }
}
- free(channel);
+
+ call_rcu(&channel->node.head, consumer_free_channel);
end:
pthread_mutex_unlock(&consumer_data.lock);
}
-static void consumer_del_channel_rcu(struct rcu_head *head)
-{
- struct lttng_ht_node_ulong *node =
- caa_container_of(head, struct lttng_ht_node_ulong, head);
- struct lttng_consumer_channel *channel=
- caa_container_of(node, struct lttng_consumer_channel, node);
-
- consumer_del_channel(channel);
-}
-
struct lttng_consumer_channel *consumer_allocate_channel(
int channel_key,
int shm_fd, int wait_fd,
lttng_ht_add_unique_ulong(consumer_data.channel_ht, &channel->node);
rcu_read_unlock();
pthread_mutex_unlock(&consumer_data.lock);
+
return 0;
}
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
*/
void lttng_consumer_cleanup(void)
{
- int ret;
struct lttng_ht_iter iter;
struct lttng_ht_node_ulong *node;
*/
cds_lfht_for_each_entry(consumer_data.stream_ht->ht, &iter.iter, node,
node) {
- ret = lttng_ht_del(consumer_data.stream_ht, &iter);
- assert(!ret);
- call_rcu(&node->head, consumer_del_stream_rcu);
+ struct lttng_consumer_stream *stream =
+ caa_container_of(node, struct lttng_consumer_stream, node);
+ consumer_del_stream(stream);
}
cds_lfht_for_each_entry(consumer_data.channel_ht->ht, &iter.iter, node,
node) {
- ret = lttng_ht_del(consumer_data.channel_ht, &iter);
- assert(!ret);
- call_rcu(&node->head, consumer_del_channel_rcu);
+ struct lttng_consumer_channel *channel =
+ caa_container_of(node, struct lttng_consumer_channel, node);
+ consumer_del_channel(channel);
}
rcu_read_unlock();
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
*/
struct lttng_consumer_local_data *lttng_consumer_create(
enum lttng_consumer_type type,
- int (*buffer_ready)(struct lttng_consumer_stream *stream,
+ ssize_t (*buffer_ready)(struct lttng_consumer_stream *stream,
struct lttng_consumer_local_data *ctx),
int (*recv_channel)(struct lttng_consumer_channel *channel),
int (*recv_stream)(struct lttng_consumer_stream *stream),
int err;
err = close(ctx->consumer_should_quit[i]);
- assert(!err);
+ if (err) {
+ PERROR("close");
+ }
}
error_quit_pipe:
for (i = 0; i < 2; i++) {
int err;
err = close(ctx->consumer_poll_pipe[i]);
- assert(!err);
+ if (err) {
+ PERROR("close");
+ }
}
error_poll_pipe:
free(ctx);
*/
void lttng_consumer_destroy(struct lttng_consumer_local_data *ctx)
{
- close(ctx->consumer_error_socket);
- close(ctx->consumer_thread_pipe[0]);
- close(ctx->consumer_thread_pipe[1]);
- close(ctx->consumer_poll_pipe[0]);
- close(ctx->consumer_poll_pipe[1]);
- close(ctx->consumer_should_quit[0]);
- close(ctx->consumer_should_quit[1]);
+ int ret;
+
+ ret = close(ctx->consumer_error_socket);
+ if (ret) {
+ PERROR("close");
+ }
+ ret = close(ctx->consumer_thread_pipe[0]);
+ if (ret) {
+ PERROR("close");
+ }
+ ret = close(ctx->consumer_thread_pipe[1]);
+ if (ret) {
+ PERROR("close");
+ }
+ ret = close(ctx->consumer_poll_pipe[0]);
+ if (ret) {
+ PERROR("close");
+ }
+ ret = close(ctx->consumer_poll_pipe[1]);
+ if (ret) {
+ PERROR("close");
+ }
+ ret = close(ctx->consumer_should_quit[0]);
+ if (ret) {
+ PERROR("close");
+ }
+ ret = close(ctx->consumer_should_quit[1]);
+ if (ret) {
+ PERROR("close");
+ }
unlink(ctx->consumer_command_sock_path);
free(ctx);
}
*
* Returns the number of bytes written
*/
-int lttng_consumer_on_read_subbuffer_mmap(
+ssize_t lttng_consumer_on_read_subbuffer_mmap(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len)
{
ERR("Unknown consumer_data type");
assert(0);
}
+
+ return 0;
}
/*
*
* Returns the number of bytes spliced.
*/
-int lttng_consumer_on_read_subbuffer_splice(
+ssize_t lttng_consumer_on_read_subbuffer_splice(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len)
{
}
pthread_mutex_unlock(&consumer_data.lock);
+ /* No FDs and consumer_quit, consumer_cleanup the thread */
+ if (nb_fd == 0 && consumer_quit == 1) {
+ goto end;
+ }
/* poll on the array of fds */
restart:
DBG("polling on %d fd", nb_fd + 1);
goto end;
}
- /* No FDs and consumer_quit, consumer_cleanup the thread */
- if (nb_fd == 0 && consumer_quit == 1) {
- goto end;
- }
-
/*
* If the consumer_poll_pipe triggered poll go
* directly to the beginning of the loop to update the
/* Take care of high priority channels first. */
for (i = 0; i < nb_fd; i++) {
if (pollfd[i].revents & POLLPRI) {
+ ssize_t len;
+
DBG("Urgent read on fd %d", pollfd[i].fd);
high_prio = 1;
- ret = ctx->on_buffer_ready(local_stream[i], ctx);
+ len = ctx->on_buffer_ready(local_stream[i], ctx);
/* it's ok to have an unavailable sub-buffer */
- if (ret == EAGAIN) {
- ret = 0;
- }
- } else if (pollfd[i].revents & POLLERR) {
- ERR("Error returned in polling fd %d.", pollfd[i].fd);
- rcu_read_lock();
- consumer_del_stream_rcu(&local_stream[i]->node.head);
- rcu_read_unlock();
- num_hup++;
- } else if (pollfd[i].revents & POLLNVAL) {
- ERR("Polling fd %d tells fd is not open.", pollfd[i].fd);
- rcu_read_lock();
- consumer_del_stream_rcu(&local_stream[i]->node.head);
- rcu_read_unlock();
- num_hup++;
- } else if ((pollfd[i].revents & POLLHUP) &&
- !(pollfd[i].revents & POLLIN)) {
- if (consumer_data.type == LTTNG_CONSUMER32_UST
- || consumer_data.type == LTTNG_CONSUMER64_UST) {
- DBG("Polling fd %d tells it has hung up. Attempting flush and read.",
- pollfd[i].fd);
- if (!local_stream[i]->hangup_flush_done) {
- lttng_ustconsumer_on_stream_hangup(local_stream[i]);
- /* read after flush */
- do {
- ret = ctx->on_buffer_ready(local_stream[i], ctx);
- } while (ret == EAGAIN);
- }
- } else {
- DBG("Polling fd %d tells it has hung up.", pollfd[i].fd);
+ if (len < 0 && len != -EAGAIN) {
+ goto end;
+ } else if (len > 0) {
+ local_stream[i]->data_read = 1;
}
- rcu_read_lock();
- consumer_del_stream_rcu(&local_stream[i]->node.head);
- rcu_read_unlock();
- num_hup++;
}
}
- /* If every buffer FD has hung up, we end the read loop here */
- if (nb_fd > 0 && num_hup == nb_fd) {
- DBG("every buffer FD has hung up\n");
- if (consumer_quit == 1) {
- goto end;
- }
+ /*
+ * If we read high prio channel in this loop, try again
+ * for more high prio data.
+ */
+ if (high_prio) {
continue;
}
/* Take care of low priority channels. */
- if (high_prio == 0) {
- for (i = 0; i < nb_fd; i++) {
- if (pollfd[i].revents & POLLIN) {
- DBG("Normal read on fd %d", pollfd[i].fd);
- ret = ctx->on_buffer_ready(local_stream[i], ctx);
- /* it's ok to have an unavailable subbuffer */
- if (ret == EAGAIN) {
- ret = 0;
- }
+ for (i = 0; i < nb_fd; i++) {
+ if ((pollfd[i].revents & POLLIN) ||
+ local_stream[i]->hangup_flush_done) {
+ ssize_t len;
+
+ 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 */
+ if (len < 0 && len != -EAGAIN) {
+ goto end;
+ } else if (len > 0) {
+ local_stream[i]->data_read = 1;
+ }
+ }
+ }
+
+ /* Handle hangup and errors */
+ for (i = 0; i < nb_fd; i++) {
+ if (!local_stream[i]->hangup_flush_done
+ && (pollfd[i].revents & (POLLHUP | POLLERR | POLLNVAL))
+ && (consumer_data.type == LTTNG_CONSUMER32_UST
+ || consumer_data.type == LTTNG_CONSUMER64_UST)) {
+ DBG("fd %d is hup|err|nval. Attempting flush and read.",
+ pollfd[i].fd);
+ lttng_ustconsumer_on_stream_hangup(local_stream[i]);
+ /* Attempt read again, for the data we just flushed. */
+ local_stream[i]->data_read = 1;
+ }
+ /*
+ * If the poll flag is HUP/ERR/NVAL and we have
+ * read no data in this pass, we can remove the
+ * stream from its hash table.
+ */
+ if ((pollfd[i].revents & POLLHUP)) {
+ DBG("Polling fd %d tells it has hung up.", pollfd[i].fd);
+ if (!local_stream[i]->data_read) {
+ consumer_del_stream(local_stream[i]);
+ num_hup++;
+ }
+ } else if (pollfd[i].revents & POLLERR) {
+ ERR("Error returned in polling fd %d.", pollfd[i].fd);
+ if (!local_stream[i]->data_read) {
+ consumer_del_stream(local_stream[i]);
+ num_hup++;
+ }
+ } else if (pollfd[i].revents & POLLNVAL) {
+ ERR("Polling fd %d tells fd is not open.", pollfd[i].fd);
+ if (!local_stream[i]->data_read) {
+ consumer_del_stream(local_stream[i]);
+ num_hup++;
}
}
+ local_stream[i]->data_read = 0;
}
}
end:
return NULL;
}
-int lttng_consumer_read_subbuffer(struct lttng_consumer_stream *stream,
+ssize_t lttng_consumer_read_subbuffer(struct lttng_consumer_stream *stream,
struct lttng_consumer_local_data *ctx)
{
switch (consumer_data.type) {
#include <lttng/lttng.h>
-#include "src/common/hashtable/hashtable.h"
+#include <common/hashtable/hashtable.h>
+#include <common/compat/fcntl.h>
/*
* When the receiving thread dies, we need to have a way to make the polling
/* For UST */
struct lttng_ust_lib_ring_buffer *buf;
int cpu;
+ int data_read;
int hangup_flush_done;
/* UID/GID of the user owning the session to which stream belongs */
uid_t uid;
* process.
*/
struct lttng_consumer_local_data {
- /* function to call when data is available on a buffer */
- int (*on_buffer_ready)(struct lttng_consumer_stream *stream,
+ /*
+ * Function to call when data is available on a buffer.
+ * Returns the number of bytes read, or negative error value.
+ */
+ ssize_t (*on_buffer_ready)(struct lttng_consumer_stream *stream,
struct lttng_consumer_local_data *ctx);
/*
* function to call when we receive a new channel, it receives a
extern struct lttng_consumer_local_data *lttng_consumer_create(
enum lttng_consumer_type type,
- int (*buffer_ready)(struct lttng_consumer_stream *stream,
+ ssize_t (*buffer_ready)(struct lttng_consumer_stream *stream,
struct lttng_consumer_local_data *ctx),
int (*recv_channel)(struct lttng_consumer_channel *channel),
int (*recv_stream)(struct lttng_consumer_stream *stream),
int (*update_stream)(int sessiond_key, uint32_t state));
extern void lttng_consumer_destroy(struct lttng_consumer_local_data *ctx);
-extern int lttng_consumer_on_read_subbuffer_mmap(
+extern ssize_t lttng_consumer_on_read_subbuffer_mmap(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len);
-extern int lttng_consumer_on_read_subbuffer_splice(
+extern ssize_t lttng_consumer_on_read_subbuffer_splice(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len);
extern int lttng_consumer_take_snapshot(struct lttng_consumer_local_data *ctx,
extern int lttng_consumer_recv_cmd(struct lttng_consumer_local_data *ctx,
int sock, struct pollfd *consumer_sockpoll);
-int lttng_consumer_read_subbuffer(struct lttng_consumer_stream *stream,
+ssize_t lttng_consumer_read_subbuffer(struct lttng_consumer_stream *stream,
struct lttng_consumer_local_data *ctx);
int lttng_consumer_on_recv_stream(struct lttng_consumer_stream *stream);
#include <stdio.h>
#include <string.h>
+#ifndef _GNU_SOURCE
+#error "lttng-tools error.h needs _GNU_SOURCE"
+#endif
+
/* Stringify the expansion of a define */
#define XSTR(d) STR(d)
#define STR(s) #s
-extern int opt_quiet;
-extern int opt_verbose;
+extern int lttng_opt_quiet;
+extern int lttng_opt_verbose;
#define PRINT_ERR 0x1
#define PRINT_WARN 0x2
/*
* Macro for printing message depending on command line option and verbosity.
*/
-#define __lttng_print(type, fmt, args...) \
- do { \
- if (opt_quiet == 0) { \
- if (type == PRINT_MSG) { \
- fprintf(stdout, fmt, ## args); \
- } else if (((type & PRINT_DBG) && opt_verbose == 1) || \
- ((type & (PRINT_DBG | PRINT_DBG2)) && \
- opt_verbose == 2) || \
- ((type & (PRINT_DBG | PRINT_DBG2 | PRINT_DBG3)) && \
- opt_verbose == 3)) { \
- fprintf(stderr, fmt, ## args); \
- } else if (type & (PRINT_ERR | PRINT_WARN | PRINT_BUG)) { \
- fprintf(stderr, fmt, ## args); \
- } \
- } \
+#define __lttng_print(type, fmt, args...) \
+ do { \
+ if (lttng_opt_quiet == 0 && type == PRINT_MSG) { \
+ fprintf(stdout, fmt, ## args); \
+ } else if (lttng_opt_quiet == 0 && \
+ (((type & PRINT_DBG) && lttng_opt_verbose == 1) || \
+ ((type & (PRINT_DBG | PRINT_DBG2)) && \
+ lttng_opt_verbose == 2) || \
+ ((type & (PRINT_DBG | PRINT_DBG2 | PRINT_DBG3)) && \
+ lttng_opt_verbose == 3))) { \
+ fprintf(stderr, fmt, ## args); \
+ } else if (lttng_opt_quiet == 0 && (type & (PRINT_WARN))) { \
+ fprintf(stderr, fmt, ## args); \
+ } else if (type & (PRINT_ERR | PRINT_BUG)) { \
+ fprintf(stderr, fmt, ## args); \
+ } \
} while (0);
#define MSG(fmt, args...) \
" [in %s() at " __FILE__ ":" XSTR(__LINE__) "]\n", ## args, __func__)
#define _PERROR(fmt, args...) \
- __lttng_print(PRINT_ERR, "perror " fmt "\n", ## args)
+ __lttng_print(PRINT_ERR, "PERROR: " fmt \
+ " [in %s() at " __FILE__ ":" XSTR(__LINE__) "]\n", ## args, __func__)
+
+#if !defined(__linux__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE))
+/*
+ * Version using XSI strerror_r.
+ */
+#define PERROR(call, args...) \
+ do { \
+ char buf[200]; \
+ strerror_r(errno, buf, sizeof(buf)); \
+ _PERROR(call ": %s", ## args, buf); \
+ } while(0);
+#else
+/*
+ * Version using GNU strerror_r, for linux with appropriate defines.
+ */
#define PERROR(call, args...) \
- do { \
+ do { \
char *buf; \
char tmp[200]; \
buf = strerror_r(errno, tmp, sizeof(tmp)); \
_PERROR(call ": %s", ## args, buf); \
} while(0);
+#endif
#endif /* _ERROR_H */
assert(node_ptr == &node->node);
}
+/*
+ * Add replace unsigned long node to hashtable.
+ */
+struct lttng_ht_node_ulong *lttng_ht_add_replace_ulong(struct lttng_ht *ht,
+ struct lttng_ht_node_ulong *node)
+{
+ struct cds_lfht_node *node_ptr;
+ assert(ht);
+ assert(ht->ht);
+ assert(node);
+
+ node_ptr = cds_lfht_add_replace(ht->ht,
+ ht->hash_fct((void *) node->key, HASH_SEED), ht->match_fct,
+ (void *) node->key, &node->node);
+ if (!node_ptr) {
+ return NULL;
+ } else {
+ return caa_container_of(node_ptr, struct lttng_ht_node_ulong, node);
+ }
+ assert(node_ptr == &node->node);
+}
+
/*
* Delete node from hashtable.
*/
struct lttng_ht_node_str *node);
extern void lttng_ht_add_unique_ulong(struct lttng_ht *ht,
struct lttng_ht_node_ulong *node);
+struct lttng_ht_node_ulong *lttng_ht_add_replace_ulong(struct lttng_ht *ht,
+ struct lttng_ht_node_ulong *node);
extern int lttng_ht_del(struct lttng_ht *ht, struct lttng_ht_iter *iter);
#include <sys/mman.h>
#include "rculfhash-internal.h"
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
/* reserve inaccessible memory space without allocation any memory */
static void *memory_map(size_t length)
{
*/
#include <assert.h>
-#include <endian.h> /* attempt to define endianness */
#include <stdint.h> /* defines uint32_t etc */
#include <stdio.h> /* defines printf for tests */
#include <string.h>
#include <urcu/compiler.h>
#include "utils.h"
+#include <common/compat/endian.h> /* attempt to define endianness */
/*
* My best guess at if you are big-endian or little-endian. This may
#define _GNU_SOURCE
#include <assert.h>
-#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
+#include <sys/stat.h>
#include <common/common.h>
#include <common/kernel-ctl/kernel-ctl.h>
#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/compat/fcntl.h>
#include "kernel-consumer.h"
*
* Returns the number of bytes written
*/
-int lttng_kconsumer_on_read_subbuffer_mmap(
+ssize_t lttng_kconsumer_on_read_subbuffer_mmap(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len)
{
unsigned long mmap_offset;
- long ret = 0;
+ ssize_t ret = 0;
off_t orig_offset = stream->out_fd_offset;
int fd = stream->wait_fd;
int outfd = stream->out_fd;
goto end;
}
/* This won't block, but will start writeout asynchronously */
- sync_file_range(outfd, stream->out_fd_offset, ret,
+ lttng_sync_file_range(outfd, stream->out_fd_offset, ret,
SYNC_FILE_RANGE_WRITE);
stream->out_fd_offset += ret;
}
*
* Returns the number of bytes spliced.
*/
-int lttng_kconsumer_on_read_subbuffer_splice(
+ssize_t lttng_kconsumer_on_read_subbuffer_splice(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len)
{
- long ret = 0;
+ ssize_t ret = 0;
loff_t offset = 0;
off_t orig_offset = stream->out_fd_offset;
int fd = stream->wait_fd;
(unsigned long)offset, fd);
ret = splice(fd, &offset, ctx->consumer_thread_pipe[1], NULL, len,
SPLICE_F_MOVE | SPLICE_F_MORE);
- DBG("splice chan to pipe ret %ld", ret);
+ DBG("splice chan to pipe ret %zd", ret);
if (ret < 0) {
errno = -ret;
perror("Error in relay splice");
ret = splice(ctx->consumer_thread_pipe[0], NULL, outfd, NULL, ret,
SPLICE_F_MOVE | SPLICE_F_MORE);
- DBG("splice pipe to file %ld", ret);
+ DBG("splice pipe to file %zd", ret);
if (ret < 0) {
errno = -ret;
perror("Error in file splice");
}
len -= ret;
/* This won't block, but will start writeout asynchronously */
- sync_file_range(outfd, stream->out_fd_offset, ret,
+ lttng_sync_file_range(outfd, stream->out_fd_offset, ret,
SYNC_FILE_RANGE_WRITE);
stream->out_fd_offset += ret;
}
/*
* Consume data on a file descriptor and write it on a trace file.
*/
-int lttng_kconsumer_read_subbuffer(struct lttng_consumer_stream *stream,
+ssize_t lttng_kconsumer_read_subbuffer(struct lttng_consumer_stream *stream,
struct lttng_consumer_local_data *ctx)
{
unsigned long len;
int err;
- long ret = 0;
+ ssize_t ret = 0;
int infd = stream->wait_fd;
DBG("In read_subbuffer (infd : %d)", infd);
/*
* Mmap the ring buffer, read it and write the data to the tracefile.
*
- * Returns the number of bytes written.
+ * Returns the number of bytes written, or negative value on error.
*/
-extern int lttng_kconsumer_on_read_subbuffer_mmap(
+extern ssize_t lttng_kconsumer_on_read_subbuffer_mmap(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len);
/*
* Splice the data from the ring buffer to the tracefile.
*
- * Returns the number of bytes spliced.
+ * Returns the number of bytes spliced, or negative error value on
+ * error.
*/
-extern int lttng_kconsumer_on_read_subbuffer_splice(
+extern ssize_t lttng_kconsumer_on_read_subbuffer_splice(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len);
int sock, struct pollfd *consumer_sockpoll);
-int lttng_kconsumer_read_subbuffer(struct lttng_consumer_stream *stream,
+ssize_t lttng_kconsumer_read_subbuffer(struct lttng_consumer_stream *stream,
struct lttng_consumer_local_data *ctx);
int lttng_kconsumer_on_recv_stream(struct lttng_consumer_stream *stream);
#include <unistd.h>
#include <fcntl.h>
#include <sched.h>
-#include <sys/mman.h>
+#include <sys/signal.h>
#include <common/error.h>
+#include <common/compat/mman.h>
+#include <common/compat/clone.h>
#include "runas.h"
#define RUNAS_CHILD_STACK_SIZE 10485760
-#ifndef MAP_STACK
-#define MAP_STACK 0
+#ifdef __FreeBSD__
+/* FreeBSD MAP_STACK always return -ENOMEM */
+#define LTTNG_MAP_STACK 0
+#else
+#define LTTNG_MAP_STACK MAP_STACK
+#endif
+
+#ifndef MAP_GROWSDOWN
+#define MAP_GROWSDOWN 0
+#endif
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
#endif
struct run_as_data {
if (data->gid != getegid()) {
ret = setegid(data->gid);
if (ret < 0) {
- perror("setegid");
+ PERROR("setegid");
return EXIT_FAILURE;
}
}
if (data->uid != geteuid()) {
ret = seteuid(data->uid);
if (ret < 0) {
- perror("seteuid");
+ PERROR("seteuid");
return EXIT_FAILURE;
}
}
writelen = write(data->retval_pipe, &sendret.c[index],
writeleft);
if (writelen < 0) {
- perror("write");
+ PERROR("write");
return EXIT_FAILURE;
}
writeleft -= writelen;
}
static
-int run_as(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid)
+int run_as_clone(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid)
{
struct run_as_data run_as_data;
int ret = 0;
ret = pipe(retval_pipe);
if (ret < 0) {
- perror("pipe");
+ PERROR("pipe");
retval.i = ret;
goto end;
}
run_as_data.retval_pipe = retval_pipe[1]; /* write end */
child_stack = mmap(NULL, RUNAS_CHILD_STACK_SIZE,
PROT_WRITE | PROT_READ,
- MAP_PRIVATE | MAP_GROWSDOWN | MAP_ANONYMOUS | MAP_STACK,
+ MAP_PRIVATE | MAP_GROWSDOWN | MAP_ANONYMOUS | LTTNG_MAP_STACK,
-1, 0);
if (child_stack == MAP_FAILED) {
- perror("mmap");
+ PERROR("mmap");
retval.i = -ENOMEM;
goto close_pipe;
}
* Pointing to the middle of the stack to support architectures
* where the stack grows up (HPPA).
*/
- pid = clone(child_run_as, child_stack + (RUNAS_CHILD_STACK_SIZE / 2),
- CLONE_FILES | SIGCHLD,
- &run_as_data, NULL);
+ pid = lttng_clone_files(child_run_as, child_stack + (RUNAS_CHILD_STACK_SIZE / 2),
+ &run_as_data);
if (pid < 0) {
- perror("clone");
+ PERROR("clone");
retval.i = pid;
goto unmap_stack;
}
do {
readlen = read(retval_pipe[0], &retval.c[index], readleft);
if (readlen < 0) {
- perror("read");
+ PERROR("read");
ret = -1;
break;
}
*/
pid = waitpid(pid, &status, 0);
if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- perror("wait");
+ PERROR("wait");
retval.i = -1;
}
unmap_stack:
ret = munmap(child_stack, RUNAS_CHILD_STACK_SIZE);
if (ret < 0) {
- perror("munmap");
+ PERROR("munmap");
retval.i = ret;
}
close_pipe:
- close(retval_pipe[0]);
- close(retval_pipe[1]);
+ ret = close(retval_pipe[0]);
+ if (ret) {
+ PERROR("close");
+ }
+ ret = close(retval_pipe[1]);
+ if (ret) {
+ PERROR("close");
+ }
end:
return retval.i;
}
+/*
+ * To be used on setups where gdb has issues debugging programs using
+ * clone/rfork. Note that this is for debuging ONLY, and should not be
+ * considered secure.
+ */
+static
+int run_as_noclone(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid)
+{
+ return cmd(data);
+}
+
+static
+int run_as(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid)
+{
+ if (!getenv("LTTNG_DEBUG_NOCLONE")) {
+ DBG("Using run_as_clone");
+ return run_as_clone(cmd, data, uid, gid);
+ } else {
+ DBG("Using run_as_noclone");
+ return run_as_noclone(cmd, data, uid, gid);
+ }
+}
+
int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid)
{
struct run_as_mkdir_data data;
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
#include <common/defaults.h>
+#include <common/error.h>
#include "sessiond-comm.h"
[ LTTCOMM_ERR_INDEX(LTTCOMM_UST_EVENT_NOT_FOUND)] = "UST event not found",
[ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CONTEXT_EXIST)] = "UST context already exist",
[ LTTCOMM_ERR_INDEX(LTTCOMM_UST_CONTEXT_INVAL)] = "UST invalid context",
+ [ LTTCOMM_ERR_INDEX(LTTCOMM_NEED_ROOT_SESSIOND) ] = "Tracing the kernel requires a root lttng-sessiond daemon and \"tracing\" group user membership",
+ [ LTTCOMM_ERR_INDEX(LTTCOMM_TRACE_ALREADY_STARTED) ] = "Tracing already started",
+ [ LTTCOMM_ERR_INDEX(LTTCOMM_TRACE_ALREADY_STOPPED) ] = "Tracing already stopped",
+
[ LTTCOMM_ERR_INDEX(CONSUMERD_COMMAND_SOCK_READY) ] = "consumerd command socket ready",
[ LTTCOMM_ERR_INDEX(CONSUMERD_SUCCESS_RECV_FD) ] = "consumerd success on receiving fds",
[ LTTCOMM_ERR_INDEX(CONSUMERD_ERROR_RECV_FD) ] = "consumerd error on receiving fds",
[ 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_INVALID) ] = "Invalid parameter",
};
/*
int lttcomm_connect_unix_sock(const char *pathname)
{
struct sockaddr_un sun;
- int fd;
- int ret;
+ int fd, ret, closeret;
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
- perror("socket");
+ PERROR("socket");
ret = fd;
goto error;
}
return fd;
error_connect:
- close(fd);
+ closeret = close(fd);
+ if (closeret) {
+ PERROR("close");
+ }
error:
return ret;
}
/* Blocking call */
new_fd = accept(sock, (struct sockaddr *) &sun, &len);
if (new_fd < 0) {
- perror("accept");
+ PERROR("accept");
}
return new_fd;
/* Create server socket */
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
- perror("socket");
+ PERROR("socket");
goto error;
}
(void) unlink(pathname);
ret = bind(fd, (struct sockaddr *) &sun, sizeof(sun));
if (ret < 0) {
- perror("bind");
+ PERROR("bind");
goto error;
}
ret = listen(sock, LTTNG_SESSIOND_COMM_MAX_LISTEN);
if (ret < 0) {
- perror("listen");
+ PERROR("listen");
}
return ret;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
- ret = recvmsg(sock, &msg, MSG_WAITALL);
+ do {
+ ret = recvmsg(sock, &msg, MSG_WAITALL);
+ } while (ret < 0 && errno == EINTR);
if (ret < 0) {
- perror("recvmsg");
+ PERROR("recvmsg");
}
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 || !lttng_opt_quiet) {
+ PERROR("sendmsg");
+ }
}
return ret;
*/
int lttcomm_close_unix_sock(int sock)
{
- int ret;
+ int ret, closeret;
/* Shutdown receptions and transmissions */
ret = shutdown(sock, SHUT_RDWR);
if (ret < 0) {
- perror("shutdown");
+ PERROR("shutdown");
}
- close(sock);
+ closeret = close(sock);
+ if (closeret) {
+ PERROR("close");
+ }
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 || !lttng_opt_quiet) {
+ PERROR("sendmsg");
+ }
}
return ret;
}
msg.msg_control = recv_fd;
msg.msg_controllen = sizeof(recv_fd);
- ret = recvmsg(sock, &msg, 0);
+ do {
+ ret = recvmsg(sock, &msg, 0);
+ } while (ret < 0 && errno == EINTR);
if (ret < 0) {
- perror("recvmsg fds");
+ PERROR("recvmsg fds");
goto end;
}
if (ret != 1) {
}
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 || !lttng_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);
+ do {
+ ret = recvmsg(sock, &msg, 0);
+ } while (ret < 0 && errno == EINTR);
if (ret < 0) {
- perror("recvmsg fds");
+ PERROR("recvmsg fds");
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;
/* Set socket for credentials retrieval */
ret = setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
if (ret < 0) {
- perror("setsockopt creds unix sock");
+ 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
LTTCOMM_UST_EVENT_NOT_FOUND, /* UST event not found */
LTTCOMM_UST_CONTEXT_EXIST, /* UST context exist */
LTTCOMM_UST_CONTEXT_INVAL, /* UST context invalid */
+ LTTCOMM_NEED_ROOT_SESSIOND, /* root sessiond is needed */
+ LTTCOMM_TRACE_ALREADY_STARTED, /* Tracing already started */
+ LTTCOMM_TRACE_ALREADY_STOPPED, /* Tracing already stopped */
CONSUMERD_COMMAND_SOCK_READY, /* when consumerd command socket ready */
CONSUMERD_SUCCESS_RECV_FD, /* success on receiving fds */
CONSUMERD_SPLICE_EINVAL, /* EINVAL from splice(2) */
CONSUMERD_SPLICE_ENOMEM, /* ENOMEM from splice(2) */
CONSUMERD_SPLICE_ESPIPE, /* ESPIPE from splice(2) */
+ LTTCOMM_INVALID, /* Invalid parameter */
+
/* 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);
#define _GNU_SOURCE
#include <assert.h>
-#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <lttng/ust-ctl.h>
#include <common/common.h>
#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/compat/fcntl.h>
#include "ust-consumer.h"
/*
* Mmap the ring buffer, read it and write the data to the tracefile.
*
- * Returns the number of bytes written
+ * Returns the number of bytes written, else negative value on error.
*/
-int lttng_ustconsumer_on_read_subbuffer_mmap(
+ssize_t lttng_ustconsumer_on_read_subbuffer_mmap(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len)
{
stream->buf, &mmap_offset);
if (ret != 0) {
errno = -ret;
- perror("ustctl_get_mmap_read_offset");
+ PERROR("ustctl_get_mmap_read_offset");
goto end;
}
while (len > 0) {
len = 0;
} else if (ret < 0) {
errno = -ret;
- perror("Error in file write");
+ PERROR("Error in file write");
goto end;
}
/* This won't block, but will start writeout asynchronously */
- sync_file_range(outfd, stream->out_fd_offset, ret,
+ lttng_sync_file_range(outfd, stream->out_fd_offset, ret,
SYNC_FILE_RANGE_WRITE);
stream->out_fd_offset += ret;
}
*
* Returns the number of bytes spliced.
*/
-int lttng_ustconsumer_on_read_subbuffer_splice(
+ssize_t lttng_ustconsumer_on_read_subbuffer_splice(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len)
{
ret = ustctl_snapshot(stream->chan->handle, stream->buf);
if (ret != 0) {
errno = -ret;
- perror("Getting sub-buffer snapshot.");
+ PERROR("Getting sub-buffer snapshot.");
}
return ret;
stream->buf, pos);
if (ret != 0) {
errno = -ret;
- perror("kernctl_snapshot_get_produced");
+ PERROR("kernctl_snapshot_get_produced");
}
return ret;
/* signal the poll thread */
ret = write(ctx->consumer_poll_pipe[1], "4", 1);
if (ret < 0) {
- perror("write consumer poll");
+ PERROR("write consumer poll");
}
end_nosignal:
return 0;
stream->uid, stream->gid);
if (ret < 0) {
ERR("Opening %s", stream->path_name);
- perror("open");
+ PERROR("open");
goto error;
}
stream->out_fd = ret;
/*
* Mmap the ring buffer, read it and write the data to the tracefile.
*
- * Returns the number of bytes written.
+ * Returns the number of bytes written, else negative value on error.
*/
-extern int lttng_ustconsumer_on_read_subbuffer_mmap(
+extern ssize_t lttng_ustconsumer_on_read_subbuffer_mmap(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len);
/* Not implemented */
-extern int lttng_ustconsumer_on_read_subbuffer_splice(
+extern ssize_t lttng_ustconsumer_on_read_subbuffer_splice(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len);
#else /* HAVE_LIBLTTNG_UST_CTL */
static inline
-int lttng_ustconsumer_on_read_subbuffer_mmap(
+ssize_t lttng_ustconsumer_on_read_subbuffer_mmap(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream, unsigned long len)
{
}
static inline
-int lttng_ustconsumer_on_read_subbuffer_splice(
+ssize_t lttng_ustconsumer_on_read_subbuffer_splice(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *uststream, unsigned long len)
{
static char *tracing_group;
static int connected;
+/* Global */
+
+/*
+ * Those two variables are used by error.h to silent or control the verbosity of
+ * error message. They are global to the library so application linking with it
+ * are able to compile correctly and also control verbosity of the library.
+ *
+ * Note that it is *not* possible to silent ERR() and PERROR() macros.
+ */
+int lttng_opt_quiet;
+int lttng_opt_verbose;
+
/*
* Copy string from src to dst and enforce null terminated byte.
*/
SUBDIRS = .
-AM_CFLAGS=-g -Wall -lurcu -lurcu-cds
+AM_CFLAGS = -g -Wall
+AM_LDFLAGS = -lurcu -lurcu-cds
EXTRA_DIST = runall.sh utils.sh lttng/runall.sh lttng/run-kernel-tests.sh
#include "../utils.h"
+int lttng_opt_quiet;
+
int main(int argc, char **argv)
{
struct lttng_handle *handle = NULL;
#include "../utils.h"
+int lttng_opt_quiet;
+
int main(int argc, char **argv)
{
struct lttng_handle *handle = NULL;
#include "../utils.h"
+int lttng_opt_quiet;
+
int main(int argc, char **argv)
{
struct lttng_handle *handle = NULL;
#include "../utils.h"
+int lttng_opt_quiet;
+
int main(int argc, char **argv)
{
struct lttng_handle *handle = NULL;
#define RANDOM_STRING_LEN 11
/* For lttngerr.h */
-int opt_quiet = 1;
-int opt_verbose = 0;
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
static const char alphanum[] =
"0123456789"
PRINT_OK();
printf("Validating kernel session: ");
- assert(kern->fd == 0);
- assert(kern->metadata_stream_fd == 0);
+ assert(kern->fd == -1);
+ assert(kern->metadata_stream_fd == -1);
assert(kern->consumer_fds_sent == 0);
assert(kern->channel_count == 0);
assert(kern->stream_count_global == 0);
assert(kern->metadata == NULL);
- assert(kern->consumer_fd == 0);
+ assert(kern->consumer_fd == -1);
PRINT_OK();
/* Init list in order to avoid sefaults from cds_list_del */
PRINT_OK();
printf("Validating kernel session metadata: ");
- assert(kern->metadata->fd == 0);
+ assert(kern->metadata->fd == -1);
assert(strlen(kern->metadata->pathname));
assert(kern->metadata->conf != NULL);
assert(kern->metadata->conf->attr.overwrite
PRINT_OK();
printf("Validating kernel channel: ");
- assert(chan->fd == 0);
+ assert(chan->fd == -1);
assert(chan->enabled == 1);
assert(strcmp(PATH1, chan->pathname) == 0);
assert(chan->stream_count == 0);
PRINT_OK();
printf("Validating kernel event: ");
- assert(event->fd == 0);
+ assert(event->fd == -1);
assert(event->enabled == 1);
assert(event->ctx == NULL);
assert(event->event->instrumentation == LTTNG_KERNEL_TRACEPOINT);
PRINT_OK();
printf("Validating kernel stream: ");
- assert(stream->fd == 0);
+ assert(stream->fd == -1);
assert(stream->pathname == NULL);
assert(stream->state == 0);
PRINT_OK();
static struct ltt_session_list *session_list;
/* For lttngerr.h */
-int opt_quiet = 1;
-int opt_verbose = 0;
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose = 0;
static const char alphanum[] =
"0123456789"
#define RANDOM_STRING_LEN 11
/* For lttngerr.h */
-int opt_quiet = 1;
-int opt_verbose = 0;
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
static const char alphanum[] =
"0123456789"
AM_CFLAGS = -I. -O2
-AM_LDFLAGS = -llttng-ust -ldl
+AM_LDFLAGS = -llttng-ust
+
+if LTTNG_TOOLS_BUILD_WITH_LIBDL
+AM_LDFLAGS += -ldl
+endif
+if LTTNG_TOOLS_BUILD_WITH_LIBC_DL
+AM_LDFLAGS += -lc
+endif
noinst_PROGRAMS = gen-nevents
gen_nevents_SOURCES = gen-nevents.c tp.c ust_gen_nevents.h
AM_CFLAGS = -I. -O2
-AM_LDFLAGS = -llttng-ust -ldl
+AM_LDFLAGS = -llttng-ust
+
+if LTTNG_TOOLS_BUILD_WITH_LIBDL
+AM_LDFLAGS += -ldl
+endif
+if LTTNG_TOOLS_BUILD_WITH_LIBC_DL
+AM_LDFLAGS += -lc
+endif
noinst_PROGRAMS = gen-events-time
gen_events_time_SOURCES = gen-events-time.c tp.c ust_gen_event.h