Fix: add -b, --background option
[lttng-tools.git] / src / bin / lttng-sessiond / main.c
index bedc61c110654744223f25de55f1713c97be8abd..bbdf141b2409825ee1b900453b2914ec03d7c9d3 100644 (file)
@@ -45,6 +45,7 @@
 #include <common/futex.h>
 #include <common/relayd/relayd.h>
 #include <common/utils.h>
+#include <common/daemonize.h>
 
 #include "lttng-sessiond.h"
 #include "buffer-registry.h"
@@ -73,7 +74,7 @@ static const char *tracing_group_name = DEFAULT_TRACING_GROUP;
 static const char *opt_pidfile;
 static int opt_sig_parent;
 static int opt_verbose_consumer;
-static int opt_daemon;
+static int opt_daemon, opt_background;
 static int opt_no_kernel;
 static int is_root;                    /* Set to 1 if the daemon is running as root */
 static pid_t ppid;          /* Parent PID for --sig-parent option */
@@ -243,6 +244,38 @@ struct health_app *health_sessiond;
 /* JUL TCP port for registration. Used by the JUL thread. */
 unsigned int jul_tcp_port = DEFAULT_JUL_TCP_PORT;
 
+/*
+ * Whether sessiond is ready for commands/health check requests.
+ * NR_LTTNG_SESSIOND_READY must match the number of calls to
+ * lttng_sessiond_notify_ready().
+ */
+#define NR_LTTNG_SESSIOND_READY                2
+int lttng_sessiond_ready = NR_LTTNG_SESSIOND_READY;
+
+/* Notify parents that we are ready for cmd and health check */
+static
+void lttng_sessiond_notify_ready(void)
+{
+       if (uatomic_sub_return(&lttng_sessiond_ready, 1) == 0) {
+               /*
+                * Notify parent pid that we are ready to accept command
+                * for client side.  This ppid is the one from the
+                * external process that spawned us.
+                */
+               if (opt_sig_parent) {
+                       kill(ppid, SIGUSR1);
+               }
+
+               /*
+                * Notify the parent of the fork() process that we are
+                * ready.
+                */
+               if (opt_daemon || opt_background) {
+                       kill(child_ppid, SIGUSR1);
+               }
+       }
+}
+
 static
 void setup_consumerd_path(void)
 {
@@ -801,13 +834,13 @@ static void *thread_manage_kernel(void *data)
         */
        lttng_poll_init(&events);
 
-       if (testpoint(thread_manage_kernel)) {
+       if (testpoint(sessiond_thread_manage_kernel)) {
                goto error_testpoint;
        }
 
        health_code_update();
 
-       if (testpoint(thread_manage_kernel_before_loop)) {
+       if (testpoint(sessiond_thread_manage_kernel_before_loop)) {
                goto error_testpoint;
        }
 
@@ -987,7 +1020,7 @@ static void *thread_manage_consumer(void *data)
 restart:
        health_poll_entry();
 
-       if (testpoint(thread_manage_consumer)) {
+       if (testpoint(sessiond_thread_manage_consumer)) {
                goto error;
        }
 
@@ -1260,7 +1293,7 @@ static void *thread_manage_apps(void *data)
 
        health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_MANAGE);
 
-       if (testpoint(thread_manage_apps)) {
+       if (testpoint(sessiond_thread_manage_apps)) {
                goto error_testpoint;
        }
 
@@ -1276,7 +1309,7 @@ static void *thread_manage_apps(void *data)
                goto error;
        }
 
-       if (testpoint(thread_manage_apps_before_loop)) {
+       if (testpoint(sessiond_thread_manage_apps_before_loop)) {
                goto error;
        }
 
@@ -1345,10 +1378,6 @@ static void *thread_manage_apps(void *data)
                                        }
 
                                        DBG("Apps with sock %d added to poll set", sock);
-
-                                       health_code_update();
-
-                                       break;
                                }
                        } else {
                                /*
@@ -1364,7 +1393,6 @@ static void *thread_manage_apps(void *data)
 
                                        /* Socket closed on remote end. */
                                        ust_app_unregister(pollfd);
-                                       break;
                                }
                        }
 
@@ -1536,6 +1564,10 @@ static void *thread_dispatch_ust_registration(void *data)
 
        health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG_DISPATCH);
 
+       if (testpoint(sessiond_thread_app_reg_dispatch)) {
+               goto error_testpoint;
+       }
+
        health_code_update();
 
        CDS_INIT_LIST_HEAD(&wait_queue.head);
@@ -1740,6 +1772,7 @@ error:
                free(wait_node);
        }
 
+error_testpoint:
        DBG("Dispatch thread dying");
        if (err) {
                health_error();
@@ -1767,7 +1800,7 @@ static void *thread_registration_apps(void *data)
 
        health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG);
 
-       if (testpoint(thread_registration_apps)) {
+       if (testpoint(sessiond_thread_registration_apps)) {
                goto error_testpoint;
        }
 
@@ -1928,11 +1961,6 @@ static void *thread_registration_apps(void *data)
 
 exit:
 error:
-       if (err) {
-               health_error();
-               ERR("Health error occurred in %s", __func__);
-       }
-
        /* Notify that the registration thread is gone */
        notify_ust_apps(0);
 
@@ -1957,6 +1985,10 @@ error_listen:
 error_create_poll:
 error_testpoint:
        DBG("UST Registration thread cleanup complete");
+       if (err) {
+               health_error();
+               ERR("Health error occurred in %s", __func__);
+       }
        health_unregister(health_sessiond);
 
        return NULL;
@@ -2937,9 +2969,74 @@ skip_domain:
        }
        case LTTNG_ENABLE_EVENT:
        {
+               struct lttng_event_exclusion *exclusion = NULL;
+               struct lttng_filter_bytecode *bytecode = NULL;
+
+               /* Handle exclusion events and receive it from the client. */
+               if (cmd_ctx->lsm->u.enable.exclusion_count > 0) {
+                       size_t count = cmd_ctx->lsm->u.enable.exclusion_count;
+
+                       exclusion = zmalloc(sizeof(struct lttng_event_exclusion) +
+                                       (count * LTTNG_SYMBOL_NAME_LEN));
+                       if (!exclusion) {
+                               ret = LTTNG_ERR_EXCLUSION_NOMEM;
+                               goto error;
+                       }
+
+                       DBG("Receiving var len exclusion event list from client ...");
+                       exclusion->count = count;
+                       ret = lttcomm_recv_unix_sock(sock, exclusion->names,
+                                       count * LTTNG_SYMBOL_NAME_LEN);
+                       if (ret <= 0) {
+                               DBG("Nothing recv() from client var len data... continuing");
+                               *sock_error = 1;
+                               free(exclusion);
+                               ret = LTTNG_ERR_EXCLUSION_INVAL;
+                               goto error;
+                       }
+               }
+
+               /* Handle filter and get bytecode from client. */
+               if (cmd_ctx->lsm->u.enable.bytecode_len > 0) {
+                       size_t bytecode_len = cmd_ctx->lsm->u.enable.bytecode_len;
+
+                       if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
+                               ret = LTTNG_ERR_FILTER_INVAL;
+                               free(exclusion);
+                               goto error;
+                       }
+
+                       bytecode = zmalloc(bytecode_len);
+                       if (!bytecode) {
+                               free(exclusion);
+                               ret = LTTNG_ERR_FILTER_NOMEM;
+                               goto error;
+                       }
+
+                       /* Receive var. len. data */
+                       DBG("Receiving var len filter's bytecode from client ...");
+                       ret = lttcomm_recv_unix_sock(sock, bytecode, bytecode_len);
+                       if (ret <= 0) {
+                               DBG("Nothing recv() from client car len data... continuing");
+                               *sock_error = 1;
+                               free(bytecode);
+                               free(exclusion);
+                               ret = LTTNG_ERR_FILTER_INVAL;
+                               goto error;
+                       }
+
+                       if ((bytecode->len + sizeof(*bytecode)) != bytecode_len) {
+                               free(bytecode);
+                               free(exclusion);
+                               ret = LTTNG_ERR_FILTER_INVAL;
+                               goto error;
+                       }
+               }
+
                ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain,
                                cmd_ctx->lsm->u.enable.channel_name,
-                               &cmd_ctx->lsm->u.enable.event, NULL, kernel_poll_pipe[1]);
+                               &cmd_ctx->lsm->u.enable.event, bytecode, exclusion,
+                               kernel_poll_pipe[1]);
                break;
        }
        case LTTNG_ENABLE_ALL_EVENT:
@@ -3263,46 +3360,6 @@ skip_domain:
                                cmd_ctx->lsm->u.reg.path, cdata);
                break;
        }
-       case LTTNG_ENABLE_EVENT_WITH_FILTER:
-       {
-               struct lttng_filter_bytecode *bytecode;
-
-               if (cmd_ctx->lsm->u.enable.bytecode_len > LTTNG_FILTER_MAX_LEN) {
-                       ret = LTTNG_ERR_FILTER_INVAL;
-                       goto error;
-               }
-               if (cmd_ctx->lsm->u.enable.bytecode_len == 0) {
-                       ret = LTTNG_ERR_FILTER_INVAL;
-                       goto error;
-               }
-               bytecode = zmalloc(cmd_ctx->lsm->u.enable.bytecode_len);
-               if (!bytecode) {
-                       ret = LTTNG_ERR_FILTER_NOMEM;
-                       goto error;
-               }
-               /* Receive var. len. data */
-               DBG("Receiving var len data from client ...");
-               ret = lttcomm_recv_unix_sock(sock, bytecode,
-                               cmd_ctx->lsm->u.enable.bytecode_len);
-               if (ret <= 0) {
-                       DBG("Nothing recv() from client var len data... continuing");
-                       *sock_error = 1;
-                       ret = LTTNG_ERR_FILTER_INVAL;
-                       goto error;
-               }
-
-               if (bytecode->len + sizeof(*bytecode)
-                               != cmd_ctx->lsm->u.enable.bytecode_len) {
-                       free(bytecode);
-                       ret = LTTNG_ERR_FILTER_INVAL;
-                       goto error;
-               }
-
-               ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain,
-                               cmd_ctx->lsm->u.enable.channel_name,
-                               &cmd_ctx->lsm->u.enable.event, bytecode, kernel_poll_pipe[1]);
-               break;
-       }
        case LTTNG_DATA_PENDING:
        {
                ret = cmd_data_pending(cmd_ctx->session);
@@ -3545,6 +3602,8 @@ static void *thread_manage_health(void *data)
                goto error;
        }
 
+       lttng_sessiond_notify_ready();
+
        while (1) {
                DBG("Health check ready");
 
@@ -3673,10 +3732,6 @@ static void *thread_manage_clients(void *data)
 
        health_register(health_sessiond, HEALTH_SESSIOND_TYPE_CMD);
 
-       if (testpoint(thread_manage_clients)) {
-               goto error_testpoint;
-       }
-
        health_code_update();
 
        ret = lttcomm_listen_unix_sock(client_sock);
@@ -3699,20 +3754,14 @@ static void *thread_manage_clients(void *data)
                goto error;
        }
 
-       /*
-        * Notify parent pid that we are ready to accept command for client side.
-        * This ppid is the one from the external process that spawned us.
-        */
-       if (opt_sig_parent) {
-               kill(ppid, SIGUSR1);
-       }
+       lttng_sessiond_notify_ready();
 
-       /* Notify the parent of the fork() process that we are ready. */
-       if (opt_daemon) {
-               kill(child_ppid, SIGUSR1);
+       /* This testpoint is after we signal readiness to the parent. */
+       if (testpoint(sessiond_thread_manage_clients)) {
+               goto error;
        }
 
-       if (testpoint(thread_manage_clients_before_loop)) {
+       if (testpoint(sessiond_thread_manage_clients_before_loop)) {
                goto error;
        }
 
@@ -3887,7 +3936,6 @@ error:
 
 error_listen:
 error_create_poll:
-error_testpoint:
        unlink(client_unix_sock_path);
        if (client_sock >= 0) {
                ret = close(client_sock);
@@ -3930,6 +3978,7 @@ static void usage(void)
        fprintf(stderr, "      --consumerd64-path PATH     Specify path for the 64-bit UST consumer daemon binary\n");
        fprintf(stderr, "      --consumerd64-libdir PATH   Specify path for the 64-bit UST consumer daemon libraries\n");
        fprintf(stderr, "  -d, --daemonize                    Start as a daemon.\n");
+       fprintf(stderr, "  -b, --background                   Start as a daemon, keeping console open.\n");
        fprintf(stderr, "  -g, --group NAME                   Specify the tracing group name. (default: tracing)\n");
        fprintf(stderr, "  -V, --version                      Show version number.\n");
        fprintf(stderr, "  -S, --sig-parent                   Send SIGUSR1 to parent pid to notify readiness.\n");
@@ -3972,12 +4021,13 @@ static int parse_args(int argc, char **argv)
                { "no-kernel", 0, 0, 'N' },
                { "pidfile", 1, 0, 'p' },
                { "jul-tcp-port", 1, 0, 'J' },
+               { "background", 0, 0, 'b' },
                { NULL, 0, 0, 0 }
        };
 
        while (1) {
                int option_index = 0;
-               c = getopt_long(argc, argv, "dhqvVSN" "a:c:g:s:C:E:D:F:Z:u:t:p:J:",
+               c = getopt_long(argc, argv, "dhqvVSN" "a:c:g:s:C:E:D:F:Z:u:t:p:J:b",
                                long_options, &option_index);
                if (c == -1) {
                        break;
@@ -3999,6 +4049,9 @@ static int parse_args(int argc, char **argv)
                case 'd':
                        opt_daemon = 1;
                        break;
+               case 'b':
+                       opt_background = 1;
+                       break;
                case 'g':
                        tracing_group_name = optarg;
                        break;
@@ -4483,95 +4536,6 @@ error:
        return;
 }
 
-/*
- * Daemonize this process by forking and making the parent wait for the child
- * to signal it indicating readiness. Once received, the parent successfully
- * quits.
- *
- * The child process undergoes the same action that daemon(3) does meaning
- * setsid, chdir, and dup /dev/null into 0, 1 and 2.
- *
- * Return 0 on success else -1 on error.
- */
-static int daemonize(void)
-{
-       int ret;
-       pid_t pid;
-
-       /* Get parent pid of this process. */
-       child_ppid = getppid();
-
-       pid = fork();
-       if (pid < 0) {
-               PERROR("fork");
-               goto error;
-       } else if (pid == 0) {
-               int fd;
-               pid_t sid;
-
-               /* Child */
-
-               /*
-                * Get the newly created parent pid so we can signal that process when
-                * we are ready to operate.
-                */
-               child_ppid = getppid();
-
-               sid = setsid();
-               if (sid < 0) {
-                       PERROR("setsid");
-                       goto error;
-               }
-
-               /* Try to change directory to /. If we can't well at least notify. */
-               ret = chdir("/");
-               if (ret < 0) {
-                       PERROR("chdir");
-               }
-
-               fd = open(_PATH_DEVNULL, O_RDWR, 0);
-               if (fd < 0) {
-                       PERROR("open %s", _PATH_DEVNULL);
-                       /* Let 0, 1 and 2 open since we can't bind them to /dev/null. */
-               } else {
-                       (void) dup2(fd, STDIN_FILENO);
-                       (void) dup2(fd, STDOUT_FILENO);
-                       (void) dup2(fd, STDERR_FILENO);
-                       if (fd > 2) {
-                               ret = close(fd);
-                               if (ret < 0) {
-                                       PERROR("close");
-                               }
-                       }
-               }
-               goto end;
-       } else {
-               /* Parent */
-
-               /*
-                * Waiting for child to notify this parent that it can exit. Note that
-                * sleep() is interrupted before the 1 second delay as soon as the
-                * signal is received, so it will not cause visible delay for the
-                * user.
-                */
-               while (!CMM_LOAD_SHARED(recv_child_signal)) {
-                       sleep(1);
-               }
-
-               /*
-                * From this point on, the parent can exit and the child is now an
-                * operationnal session daemon ready to serve clients and applications.
-                */
-               exit(EXIT_SUCCESS);
-       }
-
-end:
-       return 0;
-
-error:
-       return -1;
-}
-
 /*
  * main
  */
@@ -4605,10 +4569,11 @@ int main(int argc, char **argv)
        }
 
        /* Daemonize */
-       if (opt_daemon) {
+       if (opt_daemon || opt_background) {
                int i;
 
-               ret = daemonize();
+               ret = lttng_daemonize(&child_ppid, &recv_child_signal,
+                       !opt_background);
                if (ret < 0) {
                        goto error;
                }
This page took 0.029096 seconds and 4 git commands to generate.