#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/resource.h>
#include <inttypes.h>
#include <urcu/futex.h>
#include <urcu/uatomic.h>
#include <unistd.h>
#include <fcntl.h>
+#include <ctype.h>
#include <lttng/lttng.h>
#include <common/common.h>
#include <common/buffer-view.h>
#include <urcu/rculist.h>
+#include "version.h"
#include "cmd.h"
#include "ctf-trace.h"
#include "index.h"
/* command line options */
char *opt_output_path, *opt_working_directory;
-static int opt_daemon, opt_background;
+static int opt_daemon, opt_background, opt_print_version;
int opt_group_output_by_session;
int opt_group_output_by_host;
*/
static struct relay_conn_queue relay_conn_queue;
+/* Cap of file desriptors to be in simultaneous use by the relay daemon. */
+static unsigned int lttng_opt_fd_cap;
+
/* Global relay stream hash table. */
struct lttng_ht *relay_streams_ht;
/* Relayd health monitoring */
struct health_app *health_relayd;
+/* Global fd tracker. */
+struct fd_tracker *the_fd_tracker;
+
static struct option long_options[] = {
{ "control-port", 1, 0, 'C', },
{ "data-port", 1, 0, 'D', },
{ "daemonize", 0, 0, 'd', },
{ "background", 0, 0, 'b', },
{ "group", 1, 0, 'g', },
+ { "fd-cap", 1, 0, '\0', },
{ "help", 0, 0, 'h', },
{ "output", 1, 0, 'o', },
{ "verbose", 0, 0, 'v', },
static const char *config_ignore_options[] = { "help", "config", "version" };
+static void print_version(void) {
+ fprintf(stdout, "%s\n", VERSION);
+}
+
+static void relayd_config_log(void)
+{
+ DBG("LTTng-relayd " VERSION " - " VERSION_NAME "%s%s",
+ GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION,
+ EXTRA_VERSION_NAME[0] == '\0' ? "" : " - " EXTRA_VERSION_NAME);
+ if (EXTRA_VERSION_DESCRIPTION[0] != '\0') {
+ DBG("LTTng-relayd extra version description:\n\t" EXTRA_VERSION_DESCRIPTION "\n");
+ }
+ if (EXTRA_VERSION_PATCHES[0] != '\0') {
+ DBG("LTTng-relayd extra patches:\n\t" EXTRA_VERSION_PATCHES "\n");
+ }
+}
+
/*
* Take an option from the getopt output and set it in the right variable to be
* used later.
switch (opt) {
case 0:
- fprintf(stderr, "option %s", optname);
- if (arg) {
- fprintf(stderr, " with arg %s\n", arg);
+ if (!strcmp(optname, "fd-cap")) {
+ unsigned long v;
+
+ errno = 0;
+ v = strtoul(arg, NULL, 0);
+ if (errno != 0 || !isdigit(arg[0])) {
+ ERR("Wrong value in --fd-cap parameter: %s", arg);
+ ret = -1;
+ goto end;
+ }
+ if (v < DEFAULT_RELAYD_MINIMAL_FD_CAP) {
+ ERR("File descriptor cap must be set to at least %d",
+ DEFAULT_RELAYD_MINIMAL_FD_CAP);
+ }
+ if (v >= UINT_MAX) {
+ ERR("File descriptor cap overflow in --fd-cap parameter: %s", arg);
+ ret = -1;
+ goto end;
+ }
+ lttng_opt_fd_cap = (unsigned int) v;
+ DBG3("File descriptor cap set to %u", lttng_opt_fd_cap);
+
+ } else {
+ fprintf(stderr, "unknown option %s", optname);
+ if (arg) {
+ fprintf(stderr, " with arg %s\n", arg);
+ }
}
break;
case 'C':
}
exit(EXIT_FAILURE);
case 'V':
- fprintf(stdout, "%s\n", VERSION);
- exit(EXIT_SUCCESS);
+ opt_print_version = 1;
+ break;
case 'o':
if (lttng_is_setuid_setgid()) {
WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.",
goto exit;
}
}
+ if (lttng_opt_fd_cap == 0) {
+ int ret;
+ struct rlimit rlimit;
+
+ ret = getrlimit(RLIMIT_NOFILE, &rlimit);
+ if (ret) {
+ PERROR("Failed to get file descriptor limit");
+ retval = -1;
+ }
+
+ lttng_opt_fd_cap = rlimit.rlim_cur;
+ }
if (!opt_group_output_by_session && !opt_group_output_by_host) {
/* Group by host by default */
static void print_global_objects(void)
{
- rcu_register_thread();
-
print_viewer_streams();
print_relay_streams();
print_sessions();
-
- rcu_unregister_thread();
}
/*
if (tracing_group_name_override) {
free((void *) tracing_group_name);
}
+ fd_tracker_log(the_fd_tracker);
}
/*
goto exit_options;
}
+ relayd_config_log();
+
+ if (opt_print_version) {
+ print_version();
+ retval = 0;
+ goto exit_options;
+ }
+
+ ret = fclose(stdin);
+ if (ret) {
+ PERROR("Failed to close stdin");
+ goto exit_options;
+ }
/* Try to create directory if -o, --output is specified. */
if (opt_output_path) {
if (*opt_output_path != '/') {
/* Daemonize */
if (opt_daemon || opt_background) {
- int i;
-
ret = lttng_daemonize(&child_ppid, &recv_child_signal,
!opt_background);
if (ret < 0) {
retval = -1;
goto exit_options;
}
-
- /*
- * We are in the child. Make sure all other file
- * descriptors are closed, in case we are called with
- * more opened file descriptors than the standard ones.
- */
- for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
- (void) close(i);
- }
}
-
if (opt_working_directory) {
ret = utils_change_working_dir(opt_working_directory);
if (ret) {
goto exit_options;
}
}
+ /*
+ * The RCU thread registration (and use, through the fd-tracker's
+ * creation) is done after the daemonization to allow us to not
+ * deal with liburcu's fork() management as the call RCU needs to
+ * be restored.
+ */
+ rcu_register_thread();
+
+ the_fd_tracker = fd_tracker_create(lttng_opt_fd_cap);
+ if (!the_fd_tracker) {
+ retval = -1;
+ goto exit_options;
+ }
/* Initialize thread health monitoring */
health_relayd = health_app_create(NR_HEALTH_RELAYD_TYPES);
/* Ensure all prior call_rcu are done. */
rcu_barrier();
+ fd_tracker_destroy(the_fd_tracker);
+ rcu_unregister_thread();
+
if (!retval) {
exit(EXIT_SUCCESS);
} else {