X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng%2Flttng.c;h=d4dbe2697a8d2a591ed1c045267a559cee69420f;hp=dc9dd9241b9847eb12466fefdefa8120314321ad;hb=54a0adbf3cf5cd691d57b9ebaef083cad30273e1;hpb=3c9bd23cc5999729bb49a973d8c1e2bedef939bb diff --git a/src/bin/lttng/lttng.c b/src/bin/lttng/lttng.c index dc9dd9241..d4dbe2697 100644 --- a/src/bin/lttng/lttng.c +++ b/src/bin/lttng/lttng.c @@ -15,7 +15,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE +#define _LGPL_SOURCE #include #include #include @@ -24,22 +24,23 @@ #include #include #include -#include #include #include #include +#include #include "command.h" /* Variables */ static char *progname; -static int opt_no_sessiond; -static char *opt_sessiond_path; -static pid_t sessiond_pid; -static volatile int recv_child_signal; +int opt_no_sessiond; +char *opt_sessiond_path; + +char *opt_relayd_path; enum { + OPT_RELAYD_PATH, OPT_SESSION_PATH, OPT_DUMP_OPTIONS, OPT_DUMP_COMMANDS, @@ -52,8 +53,10 @@ static struct option long_options[] = { {"group", 1, NULL, 'g'}, {"verbose", 0, NULL, 'v'}, {"quiet", 0, NULL, 'q'}, + {"mi", 1, NULL, 'm'}, {"no-sessiond", 0, NULL, 'n'}, {"sessiond-path", 1, NULL, OPT_SESSION_PATH}, + {"relayd-path", 1, NULL, OPT_RELAYD_PATH}, {"list-options", 0, NULL, OPT_DUMP_OPTIONS}, {"list-commands", 0, NULL, OPT_DUMP_COMMANDS}, {NULL, 0, NULL, 0} @@ -62,6 +65,7 @@ static struct option long_options[] = { /* First level command */ static struct cmd_struct commands[] = { { "list", cmd_list}, + { "status", cmd_status}, { "create", cmd_create}, { "destroy", cmd_destroy}, { "start", cmd_start}, @@ -76,14 +80,17 @@ static struct cmd_struct commands[] = { { "calibrate", cmd_calibrate}, { "view", cmd_view}, { "snapshot", cmd_snapshot}, - { "enable-consumer", cmd_enable_consumer}, /* OBSOLETE */ - { "disable-consumer", cmd_disable_consumer}, /* OBSOLETE */ + { "save", cmd_save}, + { "load", cmd_load}, + { "track", cmd_track}, + { "untrack", cmd_untrack}, { NULL, NULL} /* Array closure */ }; static void usage(FILE *ofp) { - fprintf(ofp, "LTTng Trace Control " VERSION" - " VERSION_NAME"\n\n"); + fprintf(ofp, "LTTng Trace Control " VERSION " - " VERSION_NAME "%s\n\n", + GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION); fprintf(ofp, "usage: lttng [OPTIONS] []\n"); fprintf(ofp, "\n"); fprintf(ofp, "Options:\n"); @@ -93,9 +100,12 @@ static void usage(FILE *ofp) fprintf(ofp, " --list-commands Simple listing of lttng commands\n"); fprintf(ofp, " -v, --verbose Increase verbosity\n"); fprintf(ofp, " -q, --quiet Quiet mode\n"); + fprintf(ofp, " -m, --mi TYPE Machine Interface mode.\n"); + fprintf(ofp, " Type: xml\n"); fprintf(ofp, " -g, --group NAME Unix tracing group name. (default: tracing)\n"); fprintf(ofp, " -n, --no-sessiond Don't spawn a session daemon\n"); fprintf(ofp, " --sessiond-path PATH Session daemon full path\n"); + fprintf(ofp, " --relayd-path PATH Relayd daemon full path\n"); fprintf(ofp, "\n"); fprintf(ofp, "Commands:\n"); fprintf(ofp, " add-context Add context to event and/or channel\n"); @@ -110,9 +120,14 @@ static void usage(FILE *ofp) fprintf(ofp, " set-session Set current session name\n"); fprintf(ofp, " snapshot Snapshot buffers of current session name\n"); fprintf(ofp, " start Start tracing\n"); + fprintf(ofp, " status Show current session's details\n"); fprintf(ofp, " stop Stop tracing\n"); fprintf(ofp, " version Show version information\n"); fprintf(ofp, " view Start trace viewer\n"); + fprintf(ofp, " save Save session configuration\n"); + fprintf(ofp, " load Load session configuration\n"); + fprintf(ofp, " track Track specific system resources\n"); + fprintf(ofp, " untrack Untrack specific system resources\n"); fprintf(ofp, "\n"); fprintf(ofp, "Each command also has its own -h, --help option.\n"); fprintf(ofp, "\n"); @@ -122,8 +137,28 @@ static void usage(FILE *ofp) static void version(FILE *ofp) { - fprintf(ofp, "%s (LTTng Trace Control) " VERSION" - " VERSION_NAME"\n", - progname); + fprintf(ofp, "%s (LTTng Trace Control) " VERSION" - " VERSION_NAME "%s\n", + progname, + GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION); +} + +/* + * Find the MI output type enum from a string. This function is for the support + * of machine interface output. + */ +static int mi_output_type(const char *output_type) +{ + int ret = 0; + + if (!strncasecmp("xml", output_type, 3)) { + ret = LTTNG_MI_XML; + } else { + /* Invalid output format */ + ERR("MI output format not supported"); + ret = -LTTNG_ERR_MI_OUTPUT_TYPE; + } + + return ret; } /* @@ -166,26 +201,11 @@ static void clean_exit(int code) */ static void sighandler(int sig) { - int status; - switch (sig) { case SIGTERM: DBG("SIGTERM caught"); clean_exit(EXIT_FAILURE); break; - case SIGCHLD: - DBG("SIGCHLD caught"); - waitpid(sessiond_pid, &status, 0); - recv_child_signal = 1; - /* Indicate that the session daemon died */ - sessiond_pid = 0; - ERR("Session daemon died (exit status %d)", WEXITSTATUS(status)); - break; - case SIGUSR1: - /* Notify is done */ - recv_child_signal = 1; - DBG("SIGUSR1 caught"); - break; default: DBG("Unknown signal %d caught", sig); break; @@ -206,25 +226,16 @@ static int set_signal_handler(void) sigset_t sigset; if ((ret = sigemptyset(&sigset)) < 0) { - perror("sigemptyset"); + PERROR("sigemptyset"); goto end; } sa.sa_handler = sighandler; sa.sa_mask = sigset; sa.sa_flags = 0; - if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) { - perror("sigaction"); - goto end; - } if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) { - perror("sigaction"); - goto end; - } - - if ((ret = sigaction(SIGCHLD, &sa, NULL)) < 0) { - perror("sigaction"); + PERROR("sigaction"); goto end; } @@ -269,140 +280,6 @@ end: return ret; } -/* - * spawn_sessiond - * - * Spawn a session daemon by forking and execv. - */ -static int spawn_sessiond(char *pathname) -{ - int ret = 0; - pid_t pid; - - MSG("Spawning a session daemon"); - recv_child_signal = 0; - pid = fork(); - if (pid == 0) { - /* - * Spawn session daemon and tell - * it to signal us when ready. - */ - execlp(pathname, "lttng-sessiond", "--sig-parent", "--quiet", NULL); - /* execlp only returns if error happened */ - if (errno == ENOENT) { - ERR("No session daemon found. Use --sessiond-path."); - } else { - perror("execlp"); - } - kill(getppid(), SIGTERM); /* wake parent */ - exit(EXIT_FAILURE); - } else if (pid > 0) { - sessiond_pid = pid; - /* - * Wait for lttng-sessiond to start. We need to use a flag to check if - * the signal has been sent to us, because the child can be scheduled - * before the parent, and thus send the signal before this check. In - * the signal handler, we set the recv_child_signal flag, so anytime we - * check it after the fork is fine. 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 (!recv_child_signal) { - sleep(1); - } - /* - * The signal handler will nullify sessiond_pid on SIGCHLD - */ - if (!sessiond_pid) { - exit(EXIT_FAILURE); - } - goto end; - } else { - perror("fork"); - ret = -1; - goto end; - } - -end: - return ret; -} - -/* - * check_sessiond - * - * Check if the session daemon is available using - * the liblttngctl API for the check. If not, try to - * spawn a daemon. - */ -static int check_sessiond(void) -{ - int ret; - char *pathname = NULL; - - ret = lttng_session_daemon_alive(); - if (ret == 0) { /* not alive */ - /* Try command line option path */ - pathname = opt_sessiond_path; - - /* Try LTTNG_SESSIOND_PATH env variable */ - if (pathname == NULL) { - pathname = getenv(DEFAULT_SESSIOND_PATH_ENV); - } - - /* Try with configured path */ - if (pathname == NULL) { - if (CONFIG_SESSIOND_BIN[0] != '\0') { - pathname = CONFIG_SESSIOND_BIN; - } - } - - /* Let's rock and roll while trying the default path */ - if (pathname == NULL) { - pathname = INSTALL_BIN_PATH "/lttng-sessiond"; - } - - DBG("Session daemon at: %s", pathname); - - /* Check existence and permissions */ - ret = access(pathname, F_OK | X_OK); - if (ret < 0) { - ERR("No such file or access denied: %s", pathname); - goto end; - } - - ret = spawn_sessiond(pathname); - if (ret < 0) { - ERR("Problem occurred when starting %s", pathname); - } - } -end: - return ret; -} - -/* - * Check args for specific options that *must* not trigger a session daemon - * execution. - * - * Return 1 if match else 0. - */ -static int check_args_no_sessiond(int argc, char **argv) -{ - int i; - - for (i = 0; i < argc; i++) { - if ((strncmp(argv[i], "-h", sizeof("-h")) == 0) || - strncmp(argv[i], "--h", sizeof("--h")) == 0 || - strncmp(argv[i], "--list-options", sizeof("--list-options")) == 0 || - strncmp(argv[i], "--list-commands", sizeof("--list-commands")) == 0 || - strncmp(argv[i], "version", sizeof("version")) == 0 || - strncmp(argv[i], "view", sizeof("view")) == 0) { - return 1; - } - } - - return 0; -} - /* * Parse command line arguments. * @@ -411,13 +288,19 @@ static int check_args_no_sessiond(int argc, char **argv) static int parse_args(int argc, char **argv) { int opt, ret; + char *user; + + if (lttng_is_setuid_setgid()) { + ERR("'%s' is not allowed to be executed as a setuid/setgid binary for security reasons. Aborting.", argv[0]); + clean_exit(EXIT_FAILURE); + } if (argc < 2) { usage(stderr); clean_exit(EXIT_FAILURE); } - while ((opt = getopt_long(argc, argv, "+Vhnvqg:", long_options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "+Vhnvqg:m:", long_options, NULL)) != -1) { switch (opt) { case 'V': version(stdout); @@ -428,11 +311,21 @@ static int parse_args(int argc, char **argv) ret = 0; goto end; case 'v': - lttng_opt_verbose += 1; + /* There is only 3 possible level of verbosity. (-vvv) */ + if (lttng_opt_verbose < 3) { + lttng_opt_verbose += 1; + } break; case 'q': lttng_opt_quiet = 1; break; + case 'm': + lttng_opt_mi = mi_output_type(optarg); + if (lttng_opt_mi < 0) { + ret = lttng_opt_mi; + goto error; + } + break; case 'g': lttng_set_tracing_group(optarg); break; @@ -441,6 +334,17 @@ static int parse_args(int argc, char **argv) break; case OPT_SESSION_PATH: opt_sessiond_path = strdup(optarg); + if (!opt_sessiond_path) { + ret = -1; + goto error; + } + break; + case OPT_RELAYD_PATH: + opt_relayd_path = strdup(optarg); + if (!opt_relayd_path) { + ret = -1; + goto error; + } break; case OPT_DUMP_OPTIONS: list_options(stdout); @@ -462,13 +366,6 @@ static int parse_args(int argc, char **argv) lttng_opt_verbose = 0; } - /* Spawn session daemon if needed */ - if (opt_no_sessiond == 0 && check_args_no_sessiond(argc, argv) == 0 && - (check_sessiond() < 0)) { - ret = 1; - goto error; - } - /* No leftovers, print usage and quit */ if ((argc - optind) == 0) { usage(stderr); @@ -476,7 +373,15 @@ static int parse_args(int argc, char **argv) goto error; } - /* + /* For Mathieu Desnoyers a.k.a. Dr. Tracing */ + user = getenv("USER"); + if (user != NULL && ((strncmp(progname, "drtrace", 7) == 0 || + strncmp("compudj", user, 7) == 0))) { + MSG("%c[%d;%dmWelcome back Dr Tracing!%c[%dm\n", 27,1,33,27,0); + } + /* Thanks Mathieu */ + + /* * Handle leftovers which is a first level command with the trailing * options. */ @@ -522,18 +427,9 @@ error: int main(int argc, char *argv[]) { int ret; - char *user; progname = argv[0] ? argv[0] : "lttng"; - /* For Mathieu Desnoyers a.k.a. Dr. Tracing */ - user = getenv("USER"); - if (user != NULL && ((strncmp(progname, "drtrace", 7) == 0 || - strncmp("compudj", user, 7) == 0))) { - MSG("%c[%d;%dmWelcome back Dr Tracing!%c[%dm\n", 27,1,33,27,0); - } - /* Thanks Mathieu */ - ret = set_signal_handler(); if (ret < 0) { clean_exit(ret);