X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Flib%2Flttng-ctl%2Flttng-ctl.c;h=b6487b7c25f51c490ecb3f3bf28343244a6b680d;hb=44a5e5eb99f1d8b528f83fda5585677a3882f5f5;hp=a05a8049ec5dd7186fe83fa01ce83478a41f392f;hpb=00e2e675d54dc726a7c8f8887c889cc8ef022003;p=lttng-tools.git diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index a05a8049e..b6487b7c2 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -20,6 +20,7 @@ */ #define _GNU_SOURCE +#include #include #include #include @@ -32,9 +33,30 @@ #include #include +#include "filter-parser.h" +#include "filter-ast.h" +#include "filter-bytecode.h" +#include "memstream.h" + +#ifdef DEBUG +const int print_xml = 1; +#define dbg_printf(fmt, args...) \ + printf("[debug liblttng-ctl] " fmt, ## args) +#else +const int print_xml = 0; +#define dbg_printf(fmt, args...) \ +do { \ + /* do nothing but check printf format */ \ + if (0) \ + printf("[debug liblttnctl] " fmt, ## args); \ +} while (0) +#endif + + /* Socket to session daemon for communication */ static int sessiond_socket; static char sessiond_sock_path[PATH_MAX]; +static char health_sock_path[PATH_MAX]; /* Variables */ static char *tracing_group; @@ -114,6 +136,31 @@ end: return ret; } +/* + * Send var len data to the session daemon. + * + * On success, returns the number of bytes sent (>=0) + * On error, returns -1 + */ +static int send_session_varlen(void *data, size_t len) +{ + int ret; + + if (!connected) { + ret = -ENOTCONN; + goto end; + } + if (!data || !len) { + ret = 0; + goto end; + } + + ret = lttcomm_send_unix_sock(sessiond_socket, data, len); + +end: + return ret; +} + /* * Receive data from the sessiond socket. * @@ -311,10 +358,14 @@ static int disconnect_sessiond(void) /* * Ask the session daemon a specific command and put the data into buf. + * Takes extra var. len. data as input to send to the session daemon. * * Return size of data (only payload, not header) or a negative error code. */ -static int ask_sessiond(struct lttcomm_session_msg *lsm, void **buf) +static int ask_sessiond_varlen(struct lttcomm_session_msg *lsm, + void *vardata, + size_t varlen, + void **buf) { int ret; size_t size; @@ -331,6 +382,11 @@ static int ask_sessiond(struct lttcomm_session_msg *lsm, void **buf) if (ret < 0) { goto end; } + /* Send var len data */ + ret = send_session_varlen(vardata, varlen); + if (ret < 0) { + goto end; + } /* Get header from data transmission */ ret = recv_data_sessiond(&llm, sizeof(llm)); @@ -381,6 +437,16 @@ end: return ret; } +/* + * Ask the session daemon a specific command and put the data into buf. + * + * Return size of data (only payload, not header) or a negative error code. + */ +static int ask_sessiond(struct lttcomm_session_msg *lsm, void **buf) +{ + return ask_sessiond_varlen(lsm, NULL, 0, buf); +} + /* * Create lttng handle and return pointer. * The returned pointer will be NULL in case of malloc() error. @@ -555,6 +621,139 @@ int lttng_enable_event(struct lttng_handle *handle, return ask_sessiond(&lsm, NULL); } +/* + * set filter for an event + * Return negative error value on error. + * Return size of returned session payload data if OK. + */ + +int lttng_set_event_filter(struct lttng_handle *handle, + const char *event_name, const char *channel_name, + const char *filter_expression) +{ + struct lttcomm_session_msg lsm; + struct filter_parser_ctx *ctx; + FILE *fmem; + int ret = 0; + + /* Safety check. */ + if (handle == NULL) { + return -1; + } + + if (!filter_expression) { + return 0; + } + + /* + * casting const to non-const, as the underlying function will + * use it in read-only mode. + */ + fmem = lttng_fmemopen((void *) filter_expression, + strlen(filter_expression), "r"); + if (!fmem) { + fprintf(stderr, "Error opening memory as stream\n"); + return -ENOMEM; + } + ctx = filter_parser_ctx_alloc(fmem); + if (!ctx) { + fprintf(stderr, "Error allocating parser\n"); + ret = -ENOMEM; + goto alloc_error; + } + ret = filter_parser_ctx_append_ast(ctx); + if (ret) { + fprintf(stderr, "Parse error\n"); + ret = -EINVAL; + goto parse_error; + } + ret = filter_visitor_set_parent(ctx); + if (ret) { + fprintf(stderr, "Set parent error\n"); + ret = -EINVAL; + goto parse_error; + } + if (print_xml) { + ret = filter_visitor_print_xml(ctx, stdout, 0); + if (ret) { + fflush(stdout); + fprintf(stderr, "XML print error\n"); + ret = -EINVAL; + goto parse_error; + } + } + + dbg_printf("Generating IR... "); + fflush(stdout); + ret = filter_visitor_ir_generate(ctx); + if (ret) { + fprintf(stderr, "Generate IR error\n"); + ret = -EINVAL; + goto parse_error; + } + dbg_printf("done\n"); + + dbg_printf("Validating IR... "); + fflush(stdout); + ret = filter_visitor_ir_check_binary_op_nesting(ctx); + if (ret) { + ret = -EINVAL; + goto parse_error; + } + dbg_printf("done\n"); + + dbg_printf("Generating bytecode... "); + fflush(stdout); + ret = filter_visitor_bytecode_generate(ctx); + if (ret) { + fprintf(stderr, "Generate bytecode error\n"); + ret = -EINVAL; + goto parse_error; + } + dbg_printf("done\n"); + dbg_printf("Size of bytecode generated: %u bytes.\n", + bytecode_get_len(&ctx->bytecode->b)); + + memset(&lsm, 0, sizeof(lsm)); + + lsm.cmd_type = LTTNG_SET_FILTER; + + /* Copy channel name */ + copy_string(lsm.u.filter.channel_name, channel_name, + sizeof(lsm.u.filter.channel_name)); + /* Copy event name */ + copy_string(lsm.u.filter.event_name, event_name, + sizeof(lsm.u.filter.event_name)); + lsm.u.filter.bytecode_len = sizeof(ctx->bytecode->b) + + bytecode_get_len(&ctx->bytecode->b); + + copy_lttng_domain(&lsm.domain, &handle->domain); + + copy_string(lsm.session.name, handle->session_name, + sizeof(lsm.session.name)); + + ret = ask_sessiond_varlen(&lsm, &ctx->bytecode->b, + lsm.u.filter.bytecode_len, NULL); + + filter_bytecode_free(ctx); + filter_ir_free(ctx); + filter_parser_ctx_free(ctx); + if (fclose(fmem) != 0) { + perror("fclose"); + } + return ret; + +parse_error: + filter_bytecode_free(ctx); + filter_ir_free(ctx); + filter_parser_ctx_free(ctx); +alloc_error: + if (fclose(fmem) != 0) { + perror("fclose"); + } + return ret; +} + /* * Disable event(s) of a channel and domain. * If no event name is specified, all events are disabled. @@ -1081,6 +1280,98 @@ int lttng_disable_consumer(struct lttng_handle *handle) return ask_sessiond(&lsm, NULL); } +/* + * Set health socket path by putting it in the global health_sock_path + * variable. + * + * Returns 0 on success or assert(0) on ENOMEM. + */ +static int set_health_socket_path(void) +{ + int ret; + int in_tgroup = 0; /* In tracing group */ + uid_t uid; + const char *home; + + uid = getuid(); + + if (uid != 0) { + /* Are we in the tracing group ? */ + in_tgroup = check_tracing_group(tracing_group); + } + + if ((uid == 0) || in_tgroup) { + copy_string(health_sock_path, DEFAULT_GLOBAL_HEALTH_UNIX_SOCK, + sizeof(health_sock_path)); + } + + if (uid != 0) { + /* + * With GNU C < 2.1, snprintf returns -1 if the target buffer is too small; + * With GNU C >= 2.1, snprintf returns the required size (excluding closing null) + */ + home = getenv("HOME"); + if (home == NULL) { + /* Fallback in /tmp .. */ + home = "/tmp"; + } + + ret = snprintf(health_sock_path, sizeof(health_sock_path), + DEFAULT_HOME_HEALTH_UNIX_SOCK, home); + if ((ret < 0) || (ret >= sizeof(health_sock_path))) { + /* ENOMEM at this point... just kill the control lib. */ + assert(0); + } + } + + return 0; +} + +/* + * Check session daemon health for a specific health component. + * + * Return 0 if health is OK or else 1 if BAD. A return value of -1 indicate + * that the control library was not able to connect to the session daemon + * health socket. + * + * Any other positive value is an lttcomm error which can be translate with + * lttng_strerror(). + */ +int lttng_health_check(enum lttng_health_component c) +{ + int sock, ret; + struct lttcomm_health_msg msg; + struct lttcomm_health_data reply; + + /* Connect to the sesssion daemon */ + sock = lttcomm_connect_unix_sock(health_sock_path); + if (sock < 0) { + ret = -1; + goto error; + } + + msg.cmd = LTTNG_HEALTH_CHECK; + msg.component = c; + + ret = lttcomm_send_unix_sock(sock, (void *)&msg, sizeof(msg)); + if (ret < 0) { + goto close_error; + } + + ret = lttcomm_recv_unix_sock(sock, (void *)&reply, sizeof(reply)); + if (ret < 0) { + goto close_error; + } + + ret = reply.ret_code; + +close_error: + close(sock); + +error: + return ret; +} + /* * lib constructor */ @@ -1088,4 +1379,6 @@ static void __attribute__((constructor)) init() { /* Set default session group */ lttng_set_tracing_group(DEFAULT_TRACING_GROUP); + /* Set socket for health check */ + (void) set_health_socket_path(); }