* Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
* Mathieu Desnoyers <mathieu.desnoyers@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 free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 only,
+ * as published by the Free Software Foundation.
*
- * 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.
+ * 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.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define _GNU_SOURCE
#include "shm.h"
#include "ust-ctl.h"
#include "utils.h"
+#include "fd-limit.h"
#define CONSUMERD_FILE "lttng-consumerd"
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;
* If a custom kernel consumer was registered, close the socket before
* tearing down the complete kernel session structure
*/
- if (session->kernel_session->consumer_fd != kconsumer_data.cmd_sock) {
+ if (kconsumer_data.cmd_sock >= 0 &&
+ session->kernel_session->consumer_fd != kconsumer_data.cmd_sock) {
lttcomm_close_unix_sock(session->kernel_session->consumer_fd);
}
DBG("Sending metadata stream fd");
- /* Extra protection. It's NOT supposed to be set to 0 at this point */
- if (session->consumer_fd == 0) {
+ /* Extra protection. It's NOT supposed to be set to -1 at this point */
+ if (session->consumer_fd < 0) {
session->consumer_fd = consumer_data->cmd_sock;
}
- if (session->metadata_stream_fd != 0) {
+ if (session->metadata_stream_fd >= 0) {
/* Send metadata channel fd */
lkm.cmd_type = LTTNG_CONSUMER_ADD_CHANNEL;
lkm.u.channel.channel_key = session->metadata->fd;
lkm.u.channel.max_sb_size = session->metadata->conf->attr.subbuf_size;
lkm.u.channel.mmap_len = 0; /* for kernel */
- DBG("Sending metadata channel %d to consumer", lkm.u.stream.stream_key);
+ DBG("Sending metadata 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");
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;
}
* Using message-based transmissions to ensure we don't
* have to deal with partially received messages.
*/
+ ret = lttng_fd_get(LTTNG_FD_APPS, 1);
+ if (ret < 0) {
+ ERR("Exhausted file descriptors allowed for applications.");
+ free(ust_cmd);
+ ret = close(sock);
+ if (ret) {
+ PERROR("close");
+ }
+ sock = -1;
+ continue;
+ }
ret = lttcomm_recv_unix_sock(sock, &ust_cmd->reg_msg,
sizeof(struct ust_register_msg));
if (ret < 0 || ret < sizeof(struct ust_register_msg)) {
if (ret) {
PERROR("close");
}
+ lttng_fd_put(LTTNG_FD_APPS, 1);
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)",
PERROR("close");
}
}
- if (clock >= 0) {
+ if (sock >= 0) {
ret = close(sock);
if (ret) {
PERROR("close");
}
+ lttng_fd_put(LTTNG_FD_APPS, 1);
}
unlink(apps_unix_sock_path);
error:
WARN("No kernel tracer available");
kernel_tracer_fd = -1;
- return LTTCOMM_KERN_NA;
+ if (!is_root) {
+ return LTTCOMM_NEED_ROOT_SESSIOND;
+ } else {
+ return LTTCOMM_KERN_NA;
+ }
}
/*
if (session->consumer_fds_sent == 0) {
/*
* Assign default kernel consumer socket if no consumer assigned to the
- * kernel session. At this point, it's NOT suppose to be 0 but this is
+ * kernel session. At this point, it's NOT supposed to be -1 but this is
* an extra security check.
*/
- if (session->consumer_fd == 0) {
+ if (session->consumer_fd < 0) {
session->consumer_fd = kconsumer_data.cmd_sock;
}
}
/* Set kernel consumer socket fd */
- if (kconsumer_data.cmd_sock) {
+ if (kconsumer_data.cmd_sock >= 0) {
session->kernel_session->consumer_fd = kconsumer_data.cmd_sock;
}
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;
}
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;
}
break;
default:
DBG("Getting session %s by name", cmd_ctx->lsm->session.name);
+ /*
+ * We keep the session list lock across _all_ commands
+ * for now, because the per-session lock does not
+ * handle teardown properly.
+ */
session_lock_list();
cmd_ctx->session = session_find_by_name(cmd_ctx->lsm->session.name);
- session_unlock_list();
if (cmd_ctx->session == NULL) {
if (cmd_ctx->lsm->session.name != NULL) {
ret = LTTCOMM_SESS_NOT_FOUND;
switch (cmd_ctx->lsm->domain.type) {
case LTTNG_DOMAIN_KERNEL:
if (!is_root) {
- ret = LTTCOMM_KERN_NA;
+ ret = LTTCOMM_NEED_ROOT_SESSIOND;
goto error;
}
{
ret = cmd_destroy_session(cmd_ctx->session,
cmd_ctx->lsm->session.name);
+ /*
+ * Set session to NULL so we do not unlock it after
+ * free.
+ */
+ cmd_ctx->session = NULL;
break;
}
case LTTNG_LIST_DOMAINS:
if (cmd_ctx->session) {
session_unlock(cmd_ctx->session);
}
+ if (need_tracing_session) {
+ session_unlock_list();
+ }
init_setup_error:
return ret;
}
PERROR("close");
}
sock = -1;
- free(cmd_ctx);
+ clean_command_ctx(&cmd_ctx);
continue;
}
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 = 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 */
goto error;
}
+ /*
+ * Init UST app hash table. Alloc hash table before this point since
+ * cleanup() can get called after that point.
+ */
+ ust_app_ht_alloc();
+
/* After this point, we can safely call cleanup() with "goto exit" */
/*
/* Set ulimit for open files */
set_ulimit();
}
+ /* init lttng_fd tracking must be done after set_ulimit. */
+ lttng_fd_init();
ret = set_consumer_sockets(&ustconsumer64_data, rundir);
if (ret < 0) {
/* Init UST command queue. */
cds_wfq_init(&ust_cmd_queue.queue);
- /* Init UST app hash table */
- ust_app_ht_alloc();
-
/*
* Get session list pointer. This pointer MUST NOT be free(). This list is
* statically declared in session.c