[lttng-dev] Patch mi lttng

Jonathan Rajotte-Julien jonathan.rajotte-julien at ericsson.com
Tue May 13 14:00:11 EDT 2014



On 05/13/2014 01:32 PM, David Goulet wrote:
> As discussed on #lttng, this looks good to me.
>

;)

> Since you might continue working on this to support all command, I would
> be more keen to merge that in 2.6 with every command working instead of
> half of it.

Absolutely. And with a full set of tests with it.

>
> It's important to consider the fact that once merged and released this
> becomes a public ABI thus we'll be committed to it. I'll be way more
> comfortable with all the commands implemented so we can expose at once
> the full ABI and maybe fix issues on the way without having the burden
> of backward compatibility.
>
> Please raise your hand if you are not happy nor ok with this or have a
> better idea :).
>
> Cheers!
> David
>
> On 21 Apr (17:05:24), Jonathan Rajotte wrote:
>> Salut,
>>
>> Donc voici les patchs réalisés dans le cadre du projet.(sans compter la
>> premiere qui est sur la branche à David déja [1]). Elles sont basées sur
>> cet branche [1].
>>
>> J'étais en train de mettre en place des tests mais le temps me manque et
>> je ne suis pas un expert bash, ce qui ralentit un peu les choses car
>> manipuler du xml en bash c'est pas facile (en tout cas pas pour moi).
>>
>> J'ai une patch de bash completion. Cependant elle force une dépendance vers
>> xmllint... et bon j'ai pas trouvé de commande bash afin de vérifier la
>> présence de xmllint qui soit fiable à tout coup.
>>
>> Je suis en fin de session pour l'instant donc je ne pourrais pas assurer un
>> suivi efficace de tout cela. Mais je veux vraiment que cette feature soit
>> accepté au final.
>>
>> Bref voilà !
>>
>> Merci encore pour l'expérience. Si ce n'était pas de vous mon projet 4
>> aurait été pénible.
>>
>> https://github.com/dgoulet/lttng-tools-dev/tree/mi
>>
>> --
>> Jonathan Rajotte Julien
>> Chargé de laboratoire, INF1995
>> Polytechnique Montréal
>
>>  From 1652234b660950b84b4eb7bdc924092761c4cdb8 Mon Sep 17 00:00:00 2001
>> From: Jonathan Rajotte <jonathan.r.julien at gmail.com>
>> Date: Wed, 16 Apr 2014 16:08:38 -0400
>> Subject: [PATCH 1/5] Mi: add mi support for lttng struct
>>
>> Add mi-lttng support to the following struct:
>>      lttng_domain
>>      lttng_channel
>>      lttng_channel_attr
>>      lttng_event
>>          +multiple mi utility format:
>>              common attribute
>>              tracepoint_loglevel
>>              tracepoint_no_loglevel
>>              function probe
>>              function entry
>>      lttng_event_field
>>
>> mi-lttng other element
>>      pid element
>>
>> Signed-off-by: Jonathan Rajotte <jonathan.r.julien at gmail.com>
>> ---
>>   src/common/mi-lttng.c | 668 +++++++++++++++++++++++++++++++++++++++++++++++++-
>>   src/common/mi-lttng.h | 296 +++++++++++++++++++++-
>>   2 files changed, 949 insertions(+), 15 deletions(-)
>>
>> diff --git a/src/common/mi-lttng.c b/src/common/mi-lttng.c
>> index 052b542..2e4c366 100644
>> --- a/src/common/mi-lttng.c
>> +++ b/src/common/mi-lttng.c
>> @@ -16,11 +16,13 @@
>>    * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
>>    */
>>
>> +
>>   #include <include/config.h>
>>   #include <common/config/config.h>
>> -
>>   #include "mi-lttng.h"
>>
>> +#include <assert.h>
>> +
>>   /* Strings related to command */
>>   const char * const mi_lttng_element_command = "command";
>>   const char * const mi_lttng_element_command_version = "version";
>> @@ -38,6 +40,133 @@ const char * const mi_lttng_element_version_license = "license";
>>   const char * const mi_lttng_element_version_patch_level = "patchLevel";
>>   const char * const mi_lttng_element_version_description = "description";
>>
>> +/* Strings related to pid */
>> +const char * const mi_lttng_element_pids = "pids";
>> +const char * const mi_lttng_element_pid = "pid";
>> +const char * const mi_lttng_element_pid_id = "id";
>> +
>> +/* String related to a lttng_event_field */
>> +const char * const mi_lttng_element_event_field = "event_field";
>> +const char * const mi_lttng_element_event_fields = "event_fields";
>> +
>> +/* General elements of mi_lttng */
>> +const char * const mi_lttng_element_type_other = "OTHER";
>> +const char * const mi_lttng_element_type_integer = "INTEGER";
>> +const char * const mi_lttng_element_type_enum = "ENUM";
>> +const char * const mi_lttng_element_type_float = "FLOAT";
>> +const char * const mi_lttng_element_type_string = "STRING";
>> +const char * const mi_lttng_element_nowrite = "nowrite";
>> +
>> +const char * const mi_lttng_element_empty = "";
>> +
>> +const char *mi_lttng_loglevel_string(int value)
>> +{
>> +	switch (value) {
>> +	case -1:
>> +		return "";
>> +	case LTTNG_LOGLEVEL_EMERG:
>> +		return "TRACE_EMERG";
>> +	case LTTNG_LOGLEVEL_ALERT:
>> +		return "TRACE_ALERT";
>> +	case LTTNG_LOGLEVEL_CRIT:
>> +		return "TRACE_CRIT";
>> +	case LTTNG_LOGLEVEL_ERR:
>> +		return "TRACE_ERR";
>> +	case LTTNG_LOGLEVEL_WARNING:
>> +		return "TRACE_WARNING";
>> +	case LTTNG_LOGLEVEL_NOTICE:
>> +		return "TRACE_NOTICE";
>> +	case LTTNG_LOGLEVEL_INFO:
>> +		return "TRACE_INFO";
>> +	case LTTNG_LOGLEVEL_DEBUG_SYSTEM:
>> +		return "TRACE_DEBUG_SYSTEM";
>> +	case LTTNG_LOGLEVEL_DEBUG_PROGRAM:
>> +		return "TRACE_DEBUG_PROGRAM";
>> +	case LTTNG_LOGLEVEL_DEBUG_PROCESS:
>> +		return "TRACE_DEBUG_PROCESS";
>> +	case LTTNG_LOGLEVEL_DEBUG_MODULE:
>> +		return "TRACE_DEBUG_MODULE";
>> +	case LTTNG_LOGLEVEL_DEBUG_UNIT:
>> +		return "TRACE_DEBUG_UNIT";
>> +	case LTTNG_LOGLEVEL_DEBUG_FUNCTION:
>> +		return "TRACE_DEBUG_FUNCTION";
>> +	case LTTNG_LOGLEVEL_DEBUG_LINE:
>> +		return "TRACE_DEBUG_LINE";
>> +	case LTTNG_LOGLEVEL_DEBUG:
>> +		return "TRACE_DEBUG";
>> +	default:
>> +		return "UNKNOWN";
>> +	}
>> +}
>> +
>> +const char *mi_lttng_logleveltype_string(enum lttng_loglevel_type value)
>> +{
>> +	switch (value) {
>> +	case LTTNG_EVENT_LOGLEVEL_ALL:
>> +		return "ALL";
>> +	case LTTNG_EVENT_LOGLEVEL_RANGE:
>> +		return "RANGE";
>> +	case LTTNG_EVENT_LOGLEVEL_SINGLE:
>> +		return "SINGLE";
>> +	default:
>> +		return "UNKNOWN";
>> +	}
>> +}
>> +
>> +const char *mi_lttng_eventtype_string(enum lttng_event_type value)
>> +{
>> +	switch (value) {
>> +	case LTTNG_EVENT_ALL:
>> +		return config_event_type_all;
>> +		break;
>> +	case LTTNG_EVENT_TRACEPOINT:
>> +		return config_event_type_tracepoint;
>> +		break;
>> +	case LTTNG_EVENT_PROBE:
>> +		return config_event_type_probe;
>> +		break;
>> +	case LTTNG_EVENT_FUNCTION:
>> +		return config_event_type_function;
>> +		break;
>> +	case LTTNG_EVENT_FUNCTION_ENTRY:
>> +		return config_event_type_function_entry;
>> +		break;
>> +	case LTTNG_EVENT_SYSCALL:
>> +		return config_event_type_syscall;
>> +		break;
>> +	case LTTNG_EVENT_NOOP:
>> +		return config_event_type_noop;
>> +		break;
>> +	default:
>> +		return mi_lttng_element_empty;
>> +		break;
>> +	}
>> +}
>> +
>> +const char *eventfieldtype_string(enum lttng_event_field_type val)
>> +{
>> +	const char *ret;
>> +
>> +	switch (val) {
>> +	case(LTTNG_EVENT_FIELD_INTEGER):
>> +		ret = mi_lttng_element_type_integer;
>> +		break;
>> +	case(LTTNG_EVENT_FIELD_ENUM):
>> +		ret = mi_lttng_element_type_enum;
>> +		break;
>> +	case(LTTNG_EVENT_FIELD_FLOAT):
>> +		ret = mi_lttng_element_type_float;
>> +		break;
>> +	case(LTTNG_EVENT_FIELD_STRING):
>> +		ret = mi_lttng_element_type_string;
>> +		break;
>> +	default:
>> +		ret = mi_lttng_element_type_other;
>> +		break;
>> +	}
>> +	return ret;
>> +}
>> +
>>   LTTNG_HIDDEN
>>   struct mi_writer *mi_lttng_writer_create(int fd_output, int mi_output_type)
>>   {
>> @@ -90,7 +219,6 @@ LTTNG_HIDDEN
>>   int mi_lttng_writer_command_open(struct mi_writer *writer, const char *command)
>>   {
>>   	int ret;
>> -
>>   	ret = mi_lttng_writer_open_element(writer, mi_lttng_element_command);
>>   	if (ret) {
>>   		goto end;
>> @@ -121,6 +249,25 @@ int mi_lttng_writer_close_element(struct mi_writer *writer)
>>   }
>>
>>   LTTNG_HIDDEN
>> +int mi_lttng_close_multi_element(struct mi_writer *writer,
>> +		unsigned int nb_element)
>> +{
>> +	int ret, i;
>> +	if (nb_element < 1) {
>> +		ret = 0;
>> +		goto end;
>> +	}
>> +	for (i = 0; i < nb_element; i++) {
>> +		ret = mi_lttng_writer_close_element(writer);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>>   int mi_lttng_writer_write_element_unsigned_int(struct mi_writer *writer,
>>   		const char *element_name, uint64_t value)
>>   {
>> @@ -228,12 +375,20 @@ end:
>>   }
>>
>>   LTTNG_HIDDEN
>> +int mi_lttng_sessions_open(struct mi_writer *writer)
>> +{
>> +	return mi_lttng_writer_open_element(writer, config_element_sessions);
>> +}
>> +
>> +LTTNG_HIDDEN
>>   int mi_lttng_session(struct mi_writer *writer,
>>   		struct lttng_session *session, int is_open)
>>   {
>>   	int ret;
>>
>> -	/* open sessions element */
>> +	assert(session);
>> +
>> +	/* Open sessions element */
>>   	ret = mi_lttng_writer_open_element(writer,
>>   			config_element_session);
>>   	if (ret) {
>> @@ -247,28 +402,28 @@ int mi_lttng_session(struct mi_writer *writer,
>>   		goto end;
>>   	}
>>
>> -	/* path */
>> +	/* Path */
>>   	ret = mi_lttng_writer_write_element_string(writer,
>>   			config_element_path, session->path);
>>   	if (ret) {
>>   		goto end;
>>   	}
>>
>> -	/* enabled ? */
>> -	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +	/* Enabled ? */
>> +	ret = mi_lttng_writer_write_element_bool(writer,
>>   			config_element_enabled, session->enabled);
>>   	if (ret) {
>>   		goto end;
>>   	}
>>
>> -	/* snapshot mode */
>> +	/* Snapshot mode */
>>   	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>>   			config_element_snapshot_mode, session->snapshot_mode);
>>   	if (ret) {
>>   		goto end;
>>   	}
>>
>> -	/* live timer interval in usec */
>> +	/* Live timer interval in usec */
>>   	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>>   			config_element_live_timer_interval,
>>   			session->live_timer_interval);
>> @@ -284,3 +439,500 @@ end:
>>   	return ret;
>>
>>   }
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_domains_open(struct mi_writer *writer)
>> +{
>> +	return mi_lttng_writer_open_element(writer, config_element_domains);
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_domain(struct mi_writer *writer,
>> +		struct lttng_domain *domain, int is_open)
>> +{
>> +	int ret = 0;
>> +	const char *str_domain;
>> +	const char *str_buffer;
>> +
>> +	assert(domain);
>> +
>> +	/* Open domain element */
>> +	ret = mi_lttng_writer_open_element(writer, config_element_domain);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Type
>> +	 * Note: This is a *duplicate* of get_domain_str from bin/lttng/utils.c
>> +	 */
>> +	switch (domain->type) {
>> +	case LTTNG_DOMAIN_KERNEL:
>> +		str_domain = config_domain_type_kernel;
>> +		break;
>> +	case LTTNG_DOMAIN_UST:
>> +		str_domain = config_domain_type_ust;
>> +		break;
>> +	case LTTNG_DOMAIN_JUL:
>> +		str_domain = config_domain_type_jul;
>> +		break;
>> +	default:
>> +		/* Should not have an unknown domain */
>> +		assert(0);
>> +	}
>> +
>> +	ret = mi_lttng_writer_write_element_string(writer, config_element_type,
>> +			str_domain);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Buffer Type */
>> +	switch (domain->buf_type) {
>> +	case LTTNG_BUFFER_PER_PID:
>> +		str_buffer = config_buffer_type_per_pid;
>> +		break;
>> +	case LTTNG_BUFFER_PER_UID:
>> +		str_buffer = config_buffer_type_per_uid;
>> +		break;
>> +	case LTTNG_BUFFER_GLOBAL:
>> +		str_buffer = config_buffer_type_global;
>> +		break;
>> +	default:
>> +		/* Shoul not have an unknow buffer type */
>> +		assert(0);
>> +	}
>> +
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			config_element_buffer_type, str_buffer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* TODO: attr... not sure how to use the union.... */
>> +
>> +	if (!is_open) {
>> +		/* Closing domain element */
>> +		ret = mi_lttng_writer_close_element(writer);
>> +	}
>> +
>> +end:
>> +	return ret;
>> +
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_channels_open(struct mi_writer *writer)
>> +{
>> +	return mi_lttng_writer_open_element(writer, config_element_channels);
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_channel(struct mi_writer *writer,
>> +		struct lttng_channel *channel, int is_open)
>> +{
>> +	int ret = 0;
>> +
>> +	assert(channel);
>> +
>> +	/* Opening channel element */
>> +	ret = mi_lttng_writer_open_element(writer, config_element_channel);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +	/* Name */
>> +	ret = mi_lttng_writer_write_element_string(writer, config_element_name,
>> +			channel->name);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Enabled ? */
>> +	ret = mi_lttng_writer_write_element_bool(writer,
>> +			config_element_enabled, channel->enabled);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Attribute */
>> +	ret = mi_lttng_channel_attr(writer, &channel->attr);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	if (!is_open) {
>> +		/* Closing channel element */
>> +		ret = mi_lttng_writer_close_element(writer);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_channel_attr(struct mi_writer *writer,
>> +		struct lttng_channel_attr *attr)
>> +{
>> +	int ret = 0;
>> +
>> +	assert(attr);
>> +
>> +	/* Opening Attributes */
>> +	ret = mi_lttng_writer_open_element(writer, config_element_attributes);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Overwrite */
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +		config_element_overwrite_mode,
>> +		attr->overwrite ? config_overwrite_mode_overwrite :
>> +			config_overwrite_mode_discard);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Sub buffer size in byte */
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +		config_element_subbuf_size, attr->subbuf_size);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Number of sub buffer (power of two) */
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +		config_element_num_subbuf,
>> +		attr->num_subbuf);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Switch timer interval in usec */
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +		config_element_switch_timer_interval,
>> +		attr->switch_timer_interval);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Read timer interval in usec */
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +		config_element_read_timer_interval,
>> +		attr->read_timer_interval);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Event output */
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +		config_element_output_type,
>> +		attr->output == LTTNG_EVENT_SPLICE ?
>> +		config_output_type_splice : config_output_type_mmap);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Tracefile size in bytes */
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +		config_element_tracefile_size, attr->tracefile_size);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Count of tracefiles */
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +		config_element_tracefile_count,
>> +		attr->tracefile_count);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Live timer interval in usec*/
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +		config_element_live_timer_interval,
>> +		attr->live_timer_interval);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Closing attributes */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +end:
>> +	return ret;
>> +
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_event_common_attributes(struct mi_writer *writer,
>> +		struct lttng_event *event)
>> +{
>> +	int ret;
>> +
>> +	/* Open event element */
>> +	ret = mi_lttng_writer_open_element(writer, config_element_event);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* event name */
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			config_element_name, event->name);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* event type */
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			config_element_type, mi_lttng_eventtype_string(event->type));
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* is event enabled */
>> +	ret = mi_lttng_writer_write_element_bool(writer,
>> +			config_element_enabled, event->enabled);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* event filter enabled? */
>> +	ret = mi_lttng_writer_write_element_bool(writer,
>> +			config_element_filter, event->filter);
>> +
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_event_tracepoint_loglevel(struct mi_writer *writer,
>> +		struct lttng_event *event)
>> +{
>> +	int ret;
>> +
>> +	/* event loglevel */
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			config_element_loglevel, mi_lttng_loglevel_string(event->loglevel));
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			config_element_loglevel_type,
>> +			mi_lttng_logleveltype_string(event->loglevel_type));
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* event exclusion filter */
>> +	ret = mi_lttng_writer_write_element_bool(writer,
>> +			config_element_exclusion, event->exclusion);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_event_tracepoint_no_loglevel(struct mi_writer *writer,
>> +		struct lttng_event *event)
>> +{
>> +	/* event exclusion filter */
>> +	return mi_lttng_writer_write_element_bool(writer,
>> +			config_element_exclusion, event->exclusion);
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_event_function_probe(struct mi_writer *writer,
>> +		struct lttng_event *event)
>> +{
>> +	int ret;
>> +
>> +	if (event->attr.probe.addr != 0) {
>> +		/* event probe address */
>> +		ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +				config_element_address, event->attr.probe.addr);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	} else {
>> +		/* event probe offset */
>> +		ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +				config_element_offset, event->attr.probe.offset);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +
>> +		/* event probe symbol_name */
>> +		ret = mi_lttng_writer_write_element_string(writer,
>> +				config_element_symbol_name, event->attr.probe.symbol_name);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_event_function_entry(struct mi_writer *writer,
>> +		struct lttng_event *event)
>> +{
>> +	/* event probe symbol_name */
>> +	return mi_lttng_writer_write_element_string(writer,
>> +			config_element_symbol_name, event->attr.ftrace.symbol_name);
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_events_open(struct mi_writer *writer)
>> +{
>> +	return mi_lttng_writer_open_element(writer, config_element_events);
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_event(struct mi_writer *writer,
>> +		struct lttng_event *event, int is_open)
>> +{
>> +	int ret;
>> +
>> +	ret = mi_lttng_event_common_attributes(writer, event);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	switch (event->type) {
>> +	case LTTNG_EVENT_ALL:
>> +		/* We should never have "all" events in list. */
>> +		assert(0);
>> +		break;
>> +	case LTTNG_EVENT_TRACEPOINT:
>> +	{
>> +		if (event->loglevel != -1) {
>> +			ret = mi_lttng_event_tracepoint_loglevel(writer, event);
>> +		} else {
>> +			ret = mi_lttng_event_tracepoint_no_loglevel(writer, event);
>> +		}
>> +		break;
>> +	}
>> +	case LTTNG_EVENT_PROBE:
>> +		ret = mi_lttng_event_function_probe(writer, event);
>> +		break;
>> +	case LTTNG_EVENT_FUNCTION_ENTRY:
>> +		ret = mi_lttng_event_function_entry(writer, event);
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	if (!is_open) {
>> +		ret = mi_lttng_writer_close_element(writer);
>> +	}
>> +
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_pids_open(struct mi_writer *writer)
>> +{
>> +	return mi_lttng_writer_open_element(writer, mi_lttng_element_pids);
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_pid(struct mi_writer *writer, pid_t pid , const char *cmdline,
>> +		int is_open)
>> +{
>> +	int ret;
>> +
>> +	/* Open element pid */
>> +	ret = mi_lttng_writer_open_element(writer, mi_lttng_element_pid);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Writing pid number */
>> +	ret = mi_lttng_writer_write_element_signed_int(writer,
>> +			mi_lttng_element_pid_id, (int)pid);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Writing name of the process */
>> +	ret = mi_lttng_writer_write_element_string(writer, config_element_name,
>> +			cmdline);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	if (!is_open) {
>> +		/* Closing Pid */
>> +		ret = mi_lttng_writer_close_element(writer);
>> +	}
>> +
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_event_fields_open(struct mi_writer *writer)
>> +{
>> +	return mi_lttng_writer_open_element(writer, mi_lttng_element_event_fields);
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_event_field(struct mi_writer *writer,
>> +		struct lttng_event_field *field)
>> +{
>> +	int ret;
>> +
>> +	if (!field->field_name[0]) {
>> +		/* To Review: not sure if legal david ?
>> +		 * how should this be handle ?
>> +		 */
>> +		ret = 0;
>> +		goto end;
>> +	}
>> +
>> +	/* Open field */
>> +	ret = mi_lttng_writer_open_element(writer, mi_lttng_element_event_field);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	if (!field->field_name[0]) {
>> +		goto close;
>> +	}
>> +
>> +	/* Name */
>> +	ret = mi_lttng_writer_write_element_string(writer, config_element_name,
>> +			field->field_name);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Type */
>> +	ret = mi_lttng_writer_write_element_string(writer, config_element_type,
>> +			eventfieldtype_string(field->type));
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* nowrite  */
>> +	ret = mi_lttng_writer_write_element_signed_int(writer,
>> +			mi_lttng_element_nowrite, field->nowrite);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +close:
>> +	/* Close field element */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +
>> +end:
>> +	return ret;
>> +}
>> diff --git a/src/common/mi-lttng.h b/src/common/mi-lttng.h
>> index bdc4a05..2dca80c 100644
>> --- a/src/common/mi-lttng.h
>> +++ b/src/common/mi-lttng.h
>> @@ -61,6 +61,28 @@ const char * const mi_lttng_element_version_license;
>>   const char * const mi_lttng_element_version_patch_level;
>>   const char * const mi_lttng_element_version_description;
>>
>> +/* String related to a lttng_event_field */
>> +const char * const mi_lttng_element_event_field;
>> +const char * const mi_lttng_element_event_fields;
>> +
>> +/* Strings related to pid */
>> +const char * const mi_lttng_element_pids;
>> +const char * const mi_lttng_element_pid;
>> +const char * const mi_lttng_element_pid_id;
>> +
>> +/* General element of mi_lttng */
>> +const char * const mi_lttng_element_type_other;
>> +const char * const mi_lttng_element_type_integer;
>> +const char * const mi_lttng_element_type_enum;
>> +const char * const mi_lttng_element_type_float;
>> +const char * const mi_lttng_element_type_string;
>> +const char * const mi_lttng_element_nowrite;
>> +
>> +/* Utility string function  */
>> +const char *mi_lttng_loglevel_string(int value);
>> +const char *mi_lttng_logleveltype_string(enum lttng_loglevel_type value);
>> +const char *mi_lttng_eventfieldtype_string(enum lttng_event_field_type value);
>> +
>>   /*
>>    * Create an instance of a machine interface writer.
>>    *
>> @@ -128,6 +150,19 @@ int mi_lttng_writer_open_element(struct mi_writer *writer,
>>   int mi_lttng_writer_close_element(struct mi_writer *writer);
>>
>>   /*
>> + * Close multiple element.
>> + *
>> + * writer An instance of a machine interface writer.
>> + *
>> + * nb_element
>> + *
>> + * Returns zero if the XML document could be closed cleanly.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_close_multi_element(struct mi_writer *writer,
>> +		unsigned int nb_element);
>> +
>> +/*
>>    * Write an element of type unsigned int.
>>    *
>>    * writer An instance of a machine interface writer.
>> @@ -205,24 +240,271 @@ int mi_lttng_version(struct mi_writer *writer, struct mi_lttng_version *version,
>>   		const char *lttng_description, const char *lttng_license);
>>
>>   /*
>> + * Machine interface: open a sessions element.
>> + *
>> + * writer An instance of a machine interface writer
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_sessions_open(struct mi_writer *writer);
>> +
>> +/*
>>    * Machine interface of struct session.
>>    *
>>    * writer An instance of a machine interface writer
>>    *
>>    * session An instance of a session
>>    *
>> - * isOpen Define if we close the session element
>> - *        This should be use carefully and the client
>> - *        need to close the session element.
>> - *        Use case: nested addition information on a session
>> + * is_open Define if we close the session element
>> + *         This should be used carefully and the client
>> + *         need to close the session element.
>> + *         Use case: nested addtionnal information on a session
>>    *                  ex: domain,channel event.
>> - *        0-> False
>> - *        1-> True
>> + *         0-> False
>> + *         1-> True
>>    *
>>    * Returns zero if the element's value could be written.
>>    * Negative values indicate an error.
>>    */
>>   int mi_lttng_session(struct mi_writer *writer,
>> -		struct lttng_session *session, int isOpen);
>> +		struct lttng_session *session, int is_open);
>> +
>> +/*
>> + * Machine interface: open a domains element.
>> + *
>> + * writer An instance of a machine interface writer
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_domains_open(struct mi_writer *writer);
>> +
>> +/*
>> + * Machine interface of struct domain.
>> + *
>> + * writer An instance of a machine interface writer
>> + *
>> + * domain An instance of a domain
>> + *
>> + * is_open Define if we close the domain element
>> + *         This should be used carefully and the client
>> + *         need to close the domain element.
>> + *         Use case: nested addition information on a domain
>> + *                  ex: channel event.
>> + *         0-> False
>> + *         1-> True
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_domain(struct mi_writer *writer,
>> +		struct lttng_domain *domain, int is_open);
>> +
>> +/*
>> + * Machine interface: open a channels element.
>> + *
>> + * writer An instance of a machine interface writer
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_channels_open(struct mi_writer *writer);
>> +
>> +/*
>> + * Machine interface of struct channel.
>> + *
>> + * writer An instance of a machine interface writer
>> + *
>> + * channel An instance of a channel
>> + *
>> + * is_open Define if we close the channel element
>> + *         This should be used carefully and the client
>> + *         need to close the channel element.
>> + *         Use case: nested addition information on a domain
>> + *                  ex: channel event.
>> + *         0-> False
>> + *         1-> True
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_channel(struct mi_writer *writer,
>> +		struct lttng_channel *channel, int is_open);
>> +
>> +/*
>> + * Machine interface of struct channel_attr.
>> + *
>> + * writer An instance of a machine interface writer
>> + *
>> + * attr An instance of a channel_attr struct
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_channel_attr(struct mi_writer *writer,
>> +		struct lttng_channel_attr *attr);
>> +
>> +/*
>> +* Machine interface for event common attribute.
>> +*
>> +* writer An instance of a mi writer.
>> +*
>> +* event single trace event.
>> +*
>> +* The common attribute are:
>> +* - mi event element
>> +* - event name
>> +* - event type
>> +* - enabled tag
>> +* - event filter
>> +*
>> +* Returns zero if the element's value could be written.
>> +* Negative values indicate an error.
>> +*/
>> +int mi_lttng_event_common_attributes(struct mi_writer *writer,
>> +		struct lttng_event *event);
>> +
>> +/*
>> + * Machine interface for kernel tracepoint event with a loglevel.
>> + *
>> + * writer An instance of a mi writer.
>> + *
>> + * event single trace event.
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_event_tracepoint_loglevel(struct mi_writer *writer,
>> +		struct lttng_event *event);
>> +
>> +/*
>> + * Machine interface for kernel tracepoint event with no loglevel.
>> + *
>> + * writer An instance of a mi writer.
>> + *
>> + * event single trace event.
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_event_tracepoint_no_loglevel(struct mi_writer *writer,
>> +		struct lttng_event *event);
>> +
>> +/*
>> + * Machine interface for kernel function and probe event.
>> + *
>> + * writer An instance of a mi writer.
>> + *
>> + * event single trace event.
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_event_function_probe(struct mi_writer *writer,
>> +		struct lttng_event *event);
>> +
>> +/*
>> + * Machine interface for kernel function entry event.
>> + *
>> + * writer An instance of a mi writer.
>> + *
>> + * event single trace event.
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_event_function_entry(struct mi_writer *writer,
>> +		struct lttng_event *event);
>> +
>> +/*
>> + * Machine interface: open an events element.
>> + *
>> + * writer An instance of a machine interface writer
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_events_open(struct mi_writer *writer);
>> +
>> +/*
>> + * Machine interface for printing an event.
>> + * The trace event type currently supported are:
>> + *  TRACEPOINT,
>> + *  PROBE,
>> + *  FUNCTION,
>> + *  FUNCTION_ENTRY,
>> + *  SYSCALL
>> + *
>> + * writer An instance of a mi writer.
>> + *
>> + * event single trace event.
>> + *
>> + * is_open Define if we close the event element
>> + *         This should be used carefully and the client
>> + *         need to close the event element.
>> + *         Use case: nested additional information
>> + *         0-> False
>> + *         1-> True
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_event(struct mi_writer *writer, struct lttng_event *event,
>> +		int is_open);
>> +
>> +/*
>> + * Machine interface for struct lttng_event_field .
>> + *
>> + * writer An instance of a mi writer.
>> + *
>> + * field An event_field instance.
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_event_field(struct mi_writer *writer,
>> +		struct lttng_event_field *field);
>> +
>> +/*
>> + * Machine interface: open a event_fields element.
>> + *
>> + * writer An instance of a machine interface writer
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_event_fields_open(struct mi_writer *writer);
>> +
>> +/*
>> + * Machine interface: open a pids element.
>> + *
>> + * writer An instance of a machine interface writer
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_pids_open(struct mi_writer *writer);
>> +
>> +/*
>> + * Machine interface of a pid.
>> + *
>> + * writer An instance of a machine interface writer
>> + *
>> + * pid A pid
>> + *
>> + * is_open Define if we close the pid element
>> + *         This should be used carefully and the client
>> + *         need to close the pid element.
>> + *         Use case: nested addition information on a domain
>> + *                  ex: channel event.
>> + *         0-> False
>> + *         1-> True
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_pid(struct mi_writer *writer, pid_t pid , const char *cmdline,
>> +		int is_open);
>>
>>   #endif /* _MI_LTTNG_H */
>> --
>> 1.9.1
>>
>
>>  From 72a6be5b35ed54aeec90a602683a7431618f56e0 Mon Sep 17 00:00:00 2001
>> From: Jonathan Rajotte <jonathan.r.julien at gmail.com>
>> Date: Wed, 16 Apr 2014 17:03:31 -0400
>> Subject: [PATCH 2/5] Mi: support for command list
>>
>> Signed-off-by: Jonathan Rajotte <jonathan.r.julien at gmail.com>
>> ---
>>   src/bin/lttng/commands/list.c | 1031 ++++++++++++++++++++++++++++++++---------
>>   1 file changed, 801 insertions(+), 230 deletions(-)
>>
>> diff --git a/src/bin/lttng/commands/list.c b/src/bin/lttng/commands/list.c
>> index bbd674c..355375a 100644
>> --- a/src/bin/lttng/commands/list.c
>> +++ b/src/bin/lttng/commands/list.c
>> @@ -23,6 +23,8 @@
>>   #include <string.h>
>>   #include <assert.h>
>>
>> +#include <common/mi-lttng.h>
>> +
>>   #include "../command.h"
>>
>>   static int opt_userspace;
>> @@ -48,6 +50,7 @@ enum {
>>   };
>>
>>   static struct lttng_handle *handle;
>> +static struct mi_writer *writer;
>>
>>   static struct poptOption long_options[] = {
>>   	/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
>> @@ -177,46 +180,6 @@ const char *exclusion_string(int value)
>>   	}
>>   }
>>
>> -static const char *loglevel_string(int value)
>> -{
>> -	switch (value) {
>> -	case -1:
>> -		return "";
>> -	case LTTNG_LOGLEVEL_EMERG:
>> -		return "TRACE_EMERG";
>> -	case LTTNG_LOGLEVEL_ALERT:
>> -		return "TRACE_ALERT";
>> -	case LTTNG_LOGLEVEL_CRIT:
>> -		return "TRACE_CRIT";
>> -	case LTTNG_LOGLEVEL_ERR:
>> -		return "TRACE_ERR";
>> -	case LTTNG_LOGLEVEL_WARNING:
>> -		return "TRACE_WARNING";
>> -	case LTTNG_LOGLEVEL_NOTICE:
>> -		return "TRACE_NOTICE";
>> -	case LTTNG_LOGLEVEL_INFO:
>> -		return "TRACE_INFO";
>> -	case LTTNG_LOGLEVEL_DEBUG_SYSTEM:
>> -		return "TRACE_DEBUG_SYSTEM";
>> -	case LTTNG_LOGLEVEL_DEBUG_PROGRAM:
>> -		return "TRACE_DEBUG_PROGRAM";
>> -	case LTTNG_LOGLEVEL_DEBUG_PROCESS:
>> -		return "TRACE_DEBUG_PROCESS";
>> -	case LTTNG_LOGLEVEL_DEBUG_MODULE:
>> -		return "TRACE_DEBUG_MODULE";
>> -	case LTTNG_LOGLEVEL_DEBUG_UNIT:
>> -		return "TRACE_DEBUG_UNIT";
>> -	case LTTNG_LOGLEVEL_DEBUG_FUNCTION:
>> -		return "TRACE_DEBUG_FUNCTION";
>> -	case LTTNG_LOGLEVEL_DEBUG_LINE:
>> -		return "TRACE_DEBUG_LINE";
>> -	case LTTNG_LOGLEVEL_DEBUG:
>> -		return "TRACE_DEBUG";
>> -	default:
>> -		return "<<UNKNOWN>>";
>> -	}
>> -}
>> -
>>   static const char *logleveltype_string(enum lttng_loglevel_type value)
>>   {
>>   	switch (value) {
>> @@ -244,7 +207,7 @@ static void print_events(struct lttng_event *event)
>>   				indent6,
>>   				event->name,
>>   				logleveltype_string(event->loglevel_type),
>> -				loglevel_string(event->loglevel),
>> +				mi_lttng_loglevel_string(event->loglevel),
>>   				event->loglevel,
>>   				enabled_string(event->enabled),
>>   				exclusion_string(event->exclusion),
>> @@ -333,9 +296,91 @@ static void print_event_field(struct lttng_event_field *field)
>>   		field_type(field), field->nowrite ? " [no write]" : "");
>>   }
>>
>> +/*
>> + * Machine interface
>> + * Jul and ust event listing
>> + */
>> +static int mi_list_jul_ust_events(struct lttng_event *events, int count,
>> +		struct lttng_domain *domain)
>> +{
>> +	int ret, i;
>> +	pid_t cur_pid = 0;
>> +	char *cmdline = NULL;
>> +	int pid_element_open = 0;
>> +
>> +	/* Open domains element */
>> +	ret = mi_lttng_domains_open(writer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Write domain */
>> +	ret = mi_lttng_domain(writer, domain, 1);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Open pids element */
>> +	ret = mi_lttng_pids_open(writer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	for (i = 0; i < count; i++) {
>> +		if (cur_pid != events[i].pid) {
>> +			if (pid_element_open) {
>> +				/* Close the previous envents and  pid element */
>> +				ret = mi_lttng_close_multi_element(writer, 2);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +				pid_element_open = !pid_element_open;
>> +			}
>> +
>> +			cur_pid = events[i].pid;
>> +			cmdline = get_cmdline_by_pid(cur_pid);
>> +
>> +			if (!pid_element_open) {
>> +				/* Open and write a pid elemen */
>> +				ret = mi_lttng_pid(writer, cur_pid, cmdline, 1);
>> +				if (ret) {
>> +					goto error;
>> +				}
>> +
>> +				/* Open events element */
>> +				ret = mi_lttng_events_open(writer);
>> +				if (ret) {
>> +					goto error;
>> +				}
>> +
>> +				pid_element_open = !pid_element_open;
>> +			}
>> +			free(cmdline);
>> +		}
>> +
>> +		/* Write an event */
>> +		ret = mi_lttng_event(writer, &events[i], 0);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +
>> +
>> +	/* Close pids */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +
>> +	/* Close domain, domains */
>> +	ret = mi_lttng_close_multi_element(writer, 2);
>> +end:
>> +	return ret;
>> +error:
>> +	free(cmdline);
>> +	return ret;
>> +}
>> +
>>   static int list_jul_events(void)
>>   {
>> -	int i, size;
>> +	int i, size, ret = CMD_SUCCESS;
>>   	struct lttng_domain domain;
>>   	struct lttng_handle *handle;
>>   	struct lttng_event *event_list;
>> @@ -349,42 +394,45 @@ static int list_jul_events(void)
>>
>>   	handle = lttng_create_handle(NULL, &domain);
>>   	if (handle == NULL) {
>> +		ret = -1;
>>   		goto error;
>>   	}
>>
>>   	size = lttng_list_tracepoints(handle, &event_list);
>>   	if (size < 0) {
>>   		ERR("Unable to list JUL events: %s", lttng_strerror(size));
>> -		lttng_destroy_handle(handle);
>> -		return size;
>> +		ret = size;
>> +		goto error;
>>   	}
>>
>> -	MSG("JUL events (Logger name):\n-------------------------");
>> -
>> -	if (size == 0) {
>> -		MSG("None");
>> -	}
>> +	if (lttng_opt_mi) {
>> +		/* Mi print */
>> +		ret = mi_list_jul_ust_events(event_list, size, &domain);
>> +	} else {
>> +		/* Pretty print */
>> +		MSG("JUL events (Logger name):\n-------------------------");
>>
>> -	for (i = 0; i < size; i++) {
>> -		if (cur_pid != event_list[i].pid) {
>> -			cur_pid = event_list[i].pid;
>> -			cmdline = get_cmdline_by_pid(cur_pid);
>> -			MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
>> -			free(cmdline);
>> +		if (size == 0) {
>> +			MSG("None");
>>   		}
>> -		MSG("%s- %s", indent6, event_list[i].name);
>> -	}
>>
>> -	MSG("");
>> +		for (i = 0; i < size; i++) {
>> +			if (cur_pid != event_list[i].pid) {
>> +				cur_pid = event_list[i].pid;
>> +				cmdline = get_cmdline_by_pid(cur_pid);
>> +				MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
>> +				free(cmdline);
>> +			}
>> +			MSG("%s- %s", indent6, event_list[i].name);
>> +		}
>>
>> +		MSG("");
>> +	}
>>   	free(event_list);
>> -	lttng_destroy_handle(handle);
>> -
>> -	return CMD_SUCCESS;
>>
>>   error:
>>   	lttng_destroy_handle(handle);
>> -	return -1;
>> +	return ret;
>>   }
>>
>>   /*
>> @@ -392,7 +440,7 @@ error:
>>    */
>>   static int list_ust_events(void)
>>   {
>> -	int i, size;
>> +	int i, size, ret = CMD_SUCCESS;
>>   	struct lttng_domain domain;
>>   	struct lttng_handle *handle;
>>   	struct lttng_event *event_list;
>> @@ -407,42 +455,162 @@ static int list_ust_events(void)
>>
>>   	handle = lttng_create_handle(NULL, &domain);
>>   	if (handle == NULL) {
>> +		ret = -1;
>>   		goto error;
>>   	}
>>
>>   	size = lttng_list_tracepoints(handle, &event_list);
>>   	if (size < 0) {
>>   		ERR("Unable to list UST events: %s", lttng_strerror(size));
>> -		lttng_destroy_handle(handle);
>> -		return size;
>> +		ret = size;
>> +		goto error;
>>   	}
>>
>> -	MSG("UST events:\n-------------");
>> +	if (lttng_opt_mi) {
>> +		/* Mi print */
>> +		ret = mi_list_jul_ust_events(event_list, size, &domain);
>> +	} else {
>> +		/* Pretty print */
>> +		MSG("UST events:\n-------------");
>> +
>> +		if (size == 0) {
>> +			MSG("None");
>> +		}
>> +
>> +		for (i = 0; i < size; i++) {
>> +			if (cur_pid != event_list[i].pid) {
>> +				cur_pid = event_list[i].pid;
>> +				cmdline = get_cmdline_by_pid(cur_pid);
>> +				MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
>> +				free(cmdline);
>> +			}
>> +			print_events(&event_list[i]);
>> +		}
>>
>> -	if (size == 0) {
>> -		MSG("None");
>> +		MSG("");
>>   	}
>> +	free(event_list);
>> +
>> +error:
>> +	lttng_destroy_handle(handle);
>> +	return ret;
>> +}
>> +
>> +/*
>> + * Machine interface
>> + * List all ust event with their fields
>> + */
>> +static int mi_list_ust_event_fields(struct lttng_event_field *fields, int count,
>> +		struct lttng_domain *domain)
>> +{
>> +	int ret, i;
>> +	pid_t cur_pid = 0;
>> +	char *cmdline = NULL;
>> +	int pid_element_open = 0;
>> +	int event_element_open = 0;
>>
>> -	for (i = 0; i < size; i++) {
>> -		if (cur_pid != event_list[i].pid) {
>> -			cur_pid = event_list[i].pid;
>> +	struct lttng_event cur_event;
>> +
>> +	/* Open domains element */
>> +	ret = mi_lttng_domains_open(writer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Write domain */
>> +	ret = mi_lttng_domain(writer, domain, 1);
>> +
>> +	/* Open pids element */
>> +	ret = mi_lttng_pids_open(writer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	for (i = 0; i < count; i++) {
>> +		if (cur_pid != fields[i].event.pid) {
>> +			if (pid_element_open) {
>> +				if (event_element_open) {
>> +					/* Close the previous fields element
>> +					 * and the previous event
>> +					 */
>> +					ret = mi_lttng_close_multi_element(writer, 2);
>> +					if (ret) {
>> +						goto end;
>> +					}
>> +					event_element_open = !event_element_open ;
>> +				}
>> +				/* Close the previous events, pid element */
>> +				ret = mi_lttng_close_multi_element(writer, 2);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +				pid_element_open = !pid_element_open;
>> +			}
>> +
>> +			cur_pid = fields[i].event.pid;
>>   			cmdline = get_cmdline_by_pid(cur_pid);
>> -			MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
>> +			if (!pid_element_open) {
>> +				/* Open and write a pid elemen */
>> +				ret = mi_lttng_pid(writer, cur_pid, cmdline, 1);
>> +				if (ret) {
>> +					goto error;
>> +				}
>> +
>> +				/* Open events element */
>> +				ret = mi_lttng_events_open(writer);
>> +				if (ret) {
>> +					goto error;
>> +				}
>> +				pid_element_open = !pid_element_open;
>> +			}
>>   			free(cmdline);
>> +			/* Wipe current event since we are about to print a new PID. */
>> +			memset(&cur_event, 0, sizeof(cur_event));
>>   		}
>> -		print_events(&event_list[i]);
>> -	}
>>
>> -	MSG("");
>> +		if (strcmp(cur_event.name, fields[i].event.name) != 0) {
>> +			if (event_element_open) {
>> +				/* Close the previous fields element and the previous event */
>> +				ret = mi_lttng_close_multi_element(writer, 2);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +				event_element_open = !event_element_open ;
>> +			}
>>
>> -	free(event_list);
>> -	lttng_destroy_handle(handle);
>> +			memcpy(&cur_event, &fields[i].event,
>> +					sizeof(cur_event));
>>
>> -	return CMD_SUCCESS;
>> +			if (!event_element_open) {
>> +				/* Open and write the event */
>> +				ret = mi_lttng_event(writer, &cur_event, 1);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +
>> +				/* Open a fields element */
>> +				ret = mi_lttng_event_fields_open(writer);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +				event_element_open = !event_element_open ;
>> +			}
>> +		}
>>
>> +		/* Print the event_field */
>> +		ret = mi_lttng_event_field(writer, &fields[i]);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +
>> +	/* Close pids, domain, domains */
>> +	ret = mi_lttng_close_multi_element(writer, 3);
>> +end:
>> +	return ret;
>>   error:
>> -	lttng_destroy_handle(handle);
>> -	return -1;
>> +	free(cmdline);
>> +	return ret;
>>   }
>>
>>   /*
>> @@ -450,7 +618,7 @@ error:
>>    */
>>   static int list_ust_event_fields(void)
>>   {
>> -	int i, size;
>> +	int i, size, ret = CMD_SUCCESS;
>>   	struct lttng_domain domain;
>>   	struct lttng_handle *handle;
>>   	struct lttng_event_field *event_field_list;
>> @@ -468,57 +636,104 @@ static int list_ust_event_fields(void)
>>
>>   	handle = lttng_create_handle(NULL, &domain);
>>   	if (handle == NULL) {
>> +		ret = -1;
>>   		goto error;
>>   	}
>>
>>   	size = lttng_list_tracepoint_fields(handle, &event_field_list);
>>   	if (size < 0) {
>>   		ERR("Unable to list UST event fields: %s", lttng_strerror(size));
>> -		lttng_destroy_handle(handle);
>> -		return size;
>> +		ret = size;
>> +		goto error;
>>   	}
>>
>> -	MSG("UST events:\n-------------");
>> -
>> -	if (size == 0) {
>> -		MSG("None");
>> -	}
>> +	if (lttng_opt_mi) {
>> +		/* Mi print */
>> +		ret = mi_list_ust_event_fields(event_field_list, size, &domain);
>> +	} else {
>> +		/* Pretty print */
>> +		MSG("UST events:\n-------------");
>>
>> -	for (i = 0; i < size; i++) {
>> -		if (cur_pid != event_field_list[i].event.pid) {
>> -			cur_pid = event_field_list[i].event.pid;
>> -			cmdline = get_cmdline_by_pid(cur_pid);
>> -			MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
>> -			free(cmdline);
>> -			/* Wipe current event since we are about to print a new PID. */
>> -			memset(&cur_event, 0, sizeof(cur_event));
>> +		if (size == 0) {
>> +			MSG("None");
>>   		}
>> -		if (strcmp(cur_event.name, event_field_list[i].event.name) != 0) {
>> -			print_events(&event_field_list[i].event);
>> -			memcpy(&cur_event, &event_field_list[i].event,
>> -				sizeof(cur_event));
>> -		}
>> -		print_event_field(&event_field_list[i]);
>> -	}
>>
>> -	MSG("");
>> +		for (i = 0; i < size; i++) {
>> +			if (cur_pid != event_field_list[i].event.pid) {
>> +				cur_pid = event_field_list[i].event.pid;
>> +				cmdline = get_cmdline_by_pid(cur_pid);
>> +				MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
>> +				free(cmdline);
>> +				/* Wipe current event since we are about to print a new PID. */
>> +				memset(&cur_event, 0, sizeof(cur_event));
>> +			}
>> +			if (strcmp(cur_event.name, event_field_list[i].event.name) != 0) {
>> +				print_events(&event_field_list[i].event);
>> +				memcpy(&cur_event, &event_field_list[i].event,
>> +						sizeof(cur_event));
>> +			}
>> +			print_event_field(&event_field_list[i]);
>> +		}
>>
>> +		MSG("");
>> +	}
>>   	free(event_field_list);
>> -	lttng_destroy_handle(handle);
>> -
>> -	return CMD_SUCCESS;
>>
>>   error:
>>   	lttng_destroy_handle(handle);
>> -	return -1;
>> +	return ret;
>>   }
>>
>>   /*
>> - * Ask for all trace events in the kernel and pretty print them.
>> + * Machine interface
>> + * Print a list of kernel events
>> + */
>> +static int mi_list_kernel_events(struct lttng_event *events, int count,
>> +		struct lttng_domain *domain)
>> +{
>> +	int ret, i;
>> +
>> +	/* Open domains element */
>> +	ret = mi_lttng_domains_open(writer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Write domain */
>> +	ret = mi_lttng_domain(writer, domain, 1);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Open events */
>> +	ret = mi_lttng_events_open(writer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	for (i = 0; i < count; i++) {
>> +		mi_lttng_event(writer, &events[i], 0);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +
>> +	/* close events, domain and domains */
>> +	ret = mi_lttng_close_multi_element(writer, 3);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +end:
>> +	return ret;
>> +}
>> +
>> +/*
>> + * Ask for all trace events in the kernel
>>    */
>>   static int list_kernel_events(void)
>>   {
>> -	int i, size;
>> +	int i, size, ret = CMD_SUCCESS;
>>   	struct lttng_domain domain;
>>   	struct lttng_handle *handle;
>>   	struct lttng_event *event_list;
>> @@ -541,18 +756,27 @@ static int list_kernel_events(void)
>>   		return size;
>>   	}
>>
>> -	MSG("Kernel events:\n-------------");
>> +	if (lttng_opt_mi) {
>> +		/* Mi print */
>> +		ret = mi_list_kernel_events(event_list, size, &domain);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	} else {
>> +		MSG("Kernel events:\n-------------");
>>
>> -	for (i = 0; i < size; i++) {
>> -		print_events(&event_list[i]);
>> -	}
>> +		for (i = 0; i < size; i++) {
>> +			print_events(&event_list[i]);
>> +		}
>>
>> -	MSG("");
>> +		MSG("");
>> +	}
>>
>> +end:
>>   	free(event_list);
>>
>>   	lttng_destroy_handle(handle);
>> -	return CMD_SUCCESS;
>> +	return ret;
>>
>>   error:
>>   	lttng_destroy_handle(handle);
>> @@ -560,13 +784,41 @@ error:
>>   }
>>
>>   /*
>> + * Machine Interface
>> + * Print a list of jul events
>> + */
>> +static int mi_list_session_jul_events(struct lttng_event *events, int count)
>> +{
>> +	int ret, i;
>> +
>> +	/* Open events element */
>> +	ret = mi_lttng_events_open(writer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	for (i = 0; i < count; i++) {
>> +		ret = mi_lttng_event(writer, &events[i], 0);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +
>> +	/* Close events element */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +
>> +end:
>> +	return ret;
>> +}
>> +
>> +/*
>>    * List JUL events for a specific session using the handle.
>>    *
>>    * Return CMD_SUCCESS on success else a negative value.
>>    */
>>   static int list_session_jul_events(void)
>>   {
>> -	int ret, count, i;
>> +	int ret = CMD_SUCCESS, count, i;
>>   	struct lttng_event *events = NULL;
>>
>>   	count = lttng_list_events(handle, "", &events);
>> @@ -576,24 +828,56 @@ static int list_session_jul_events(void)
>>   		goto error;
>>   	}
>>
>> -	MSG("Events (Logger name):\n---------------------");
>> -	if (count == 0) {
>> -		MSG("%sNone\n", indent6);
>> +	if (lttng_opt_mi) {
>> +		/* Mi print */
>> +		ret = mi_list_session_jul_events(events, count);
>> +	} else {
>> +		/* Pretty print */
>> +		MSG("Events (Logger name):\n---------------------");
>> +		if (count == 0) {
>> +			MSG("%sNone\n", indent6);
>> +			goto end;
>> +		}
>> +
>> +		for (i = 0; i < count; i++) {
>> +			MSG("%s- %s%s", indent4, events[i].name,
>> +					enabled_string(events[i].enabled));
>> +		}
>> +
>> +		MSG("");
>> +	}
>> +
>> +end:
>> +	free(events);
>> +error:
>> +	return ret;
>> +}
>> +
>> +/*
>> + * Machine interface
>> + * print a list of event
>> + */
>> +static int mi_list_events(struct lttng_event *events, int count)
>> +{
>> +	int ret, i;
>> +
>> +	/* Open events element */
>> +	ret = mi_lttng_events_open(writer);
>> +	if (ret) {
>>   		goto end;
>>   	}
>>
>>   	for (i = 0; i < count; i++) {
>> -		MSG("%s- %s%s", indent4, events[i].name,
>> -				enabled_string(events[i].enabled));
>> +		ret = mi_lttng_event(writer, &events[i], 0);
>> +		if (ret) {
>> +			goto end;
>> +		}
>>   	}
>>
>> -	MSG("");
>> +	/* Close events element */
>> +	ret = mi_lttng_writer_close_element(writer);
>>
>>   end:
>> -	free(events);
>> -	ret = CMD_SUCCESS;
>> -
>> -error:
>>   	return ret;
>>   }
>>
>> @@ -602,7 +886,7 @@ error:
>>    */
>>   static int list_events(const char *channel_name)
>>   {
>> -	int ret, count, i;
>> +	int ret = CMD_SUCCESS, count, i;
>>   	struct lttng_event *events = NULL;
>>
>>   	count = lttng_list_events(handle, channel_name, &events);
>> @@ -612,22 +896,25 @@ static int list_events(const char *channel_name)
>>   		goto error;
>>   	}
>>
>> -	MSG("\n%sEvents:", indent4);
>> -	if (count == 0) {
>> -		MSG("%sNone\n", indent6);
>> -		goto end;
>> -	}
>> -
>> -	for (i = 0; i < count; i++) {
>> -		print_events(&events[i]);
>> -	}
>> +	if (lttng_opt_mi) {
>> +		/* Mi print */
>> +		ret = mi_list_events(events, count);
>> +	} else {
>> +		/* Pretty print */
>> +		MSG("\n%sEvents:", indent4);
>> +		if (count == 0) {
>> +			MSG("%sNone\n", indent6);
>> +			goto end;
>> +		}
>>
>> -	MSG("");
>> +		for (i = 0; i < count; i++) {
>> +			print_events(&events[i]);
>> +		}
>>
>> +		MSG("");
>> +	}
>>   end:
>>   	free(events);
>> -	ret = CMD_SUCCESS;
>> -
>>   error:
>>   	return ret;
>>   }
>> @@ -656,6 +943,62 @@ static void print_channel(struct lttng_channel *channel)
>>   }
>>
>>   /*
>> + * Machine interface
>> + * Print a list of channel
>> + *
>> + */
>> +static int mi_list_channels(struct lttng_channel *channels, int count,
>> +		const char *channel_name)
>> +{
>> +	int i, ret;
>> +	unsigned int chan_found = 0;
>> +
>> +	/* Open channels element */
>> +	ret = mi_lttng_channels_open(writer);
>> +	if (ret) {
>> +		goto error;
>> +	}
>> +
>> +	for (i = 0; i < count; i++) {
>> +		if (channel_name != NULL) {
>> +			if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
>> +				chan_found = 1;
>> +			} else {
>> +				continue;
>> +			}
>> +		}
>> +
>> +		/* Write channel element  and leave it open */
>> +		ret = mi_lttng_channel(writer, &channels[i], 1);
>> +
>> +		/* Listing events per channel */
>> +		ret = list_events(channels[i].name);
>> +		if (ret) {
>> +			goto error;
>> +		}
>> +
>> +		/* Closing the channel element we opened earlier */
>> +		ret = mi_lttng_writer_close_element(writer);
>> +		if (ret) {
>> +			goto error;
>> +		}
>> +
>> +		if (chan_found) {
>> +			break;
>> +		}
>> +	}
>> +
>> +	/* Close channels element */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +	if (ret) {
>> +		goto error;
>> +	}
>> +
>> +error:
>> +	return ret;
>> +}
>> +
>> +/*
>>    * List channel(s) of session and domain.
>>    *
>>    * If channel_name is NULL, all channels are listed.
>> @@ -672,54 +1015,136 @@ static int list_channels(const char *channel_name)
>>   	if (count < 0) {
>>   		switch (-count) {
>>   		case LTTNG_ERR_KERN_CHAN_NOT_FOUND:
>> -			ret = CMD_SUCCESS;
>> -			WARN("No kernel channel");
>> +			if (lttng_opt_mi) {
>> +				/* When printing mi this is not an error
>> +				 * but an empty channels element */
>> +				count = 0;
>> +			} else {
>> +				ret = CMD_SUCCESS;
>> +				WARN("No kernel channel");
>> +				goto error_channels;
>> +			}
>>   			break;
>>   		default:
>>   			/* We had a real error */
>>   			ret = count;
>>   			ERR("%s", lttng_strerror(ret));
>> +			goto error_channels;
>>   			break;
>>   		}
>> -		goto error_channels;
>>   	}
>>
>> -	if (channel_name == NULL) {
>> -		MSG("Channels:\n-------------");
>> -	}
>> +	if (lttng_opt_mi) {
>> +		/* Mi print */
>> +		ret = mi_list_channels(channels, count, channel_name);
>> +	} else {
>> +		/* Pretty print */
>> +		if (channel_name == NULL) {
>> +			MSG("Channels:\n-------------");
>> +		}
>>
>> -	for (i = 0; i < count; i++) {
>> -		if (channel_name != NULL) {
>> -			if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
>> -				chan_found = 1;
>> -			} else {
>> -				continue;
>> +		for (i = 0; i < count; i++) {
>> +			if (channel_name != NULL) {
>> +				if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
>> +					chan_found = 1;
>> +				} else {
>> +					continue;
>> +				}
>>   			}
>> -		}
>> -		print_channel(&channels[i]);
>> +			print_channel(&channels[i]);
>>
>> -		/* Listing events per channel */
>> -		ret = list_events(channels[i].name);
>> -		if (ret < 0) {
>> -			ERR("%s", lttng_strerror(ret));
>> +			/* Listing events per channel */
>> +			ret = list_events(channels[i].name);
>> +			if (ret < 0) {
>> +				ERR("%s", lttng_strerror(ret));
>> +				goto error;
>> +			}
>> +
>> +			if (chan_found) {
>> +				break;
>> +			}
>>   		}
>>
>> -		if (chan_found) {
>> -			break;
>> +		if (!chan_found && channel_name != NULL) {
>> +			ERR("Channel %s not found", channel_name);
>> +			goto error;
>>   		}
>>   	}
>> +error:
>> +	free(channels);
>>
>> -	if (!chan_found && channel_name != NULL) {
>> -		ERR("Channel %s not found", channel_name);
>> -		goto error;
>> +error_channels:
>> +	return ret;
>> +}
>> +
>> +/*
>> + * Machine interface
>> + * Find the session with session_name as name
>> + * and print his informations.
>> + */
>> +static int mi_list_session(const char *session_name,
>> +		struct lttng_session *sessions, int count)
>> +{
>> +	int ret, i;
>> +	unsigned int session_found = 0;
>> +
>> +	if (session_name == NULL) {
>> +		ret = -LTTNG_ERR_SESS_NOT_FOUND;
>> +		goto end;
>> +	}
>> +
>> +	for (i = 0; i < count; i++) {
>> +			if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
>> +				/* We need to leave it open to append other informations
>> +				 * like domain, channel, events etc.*/
>> +				session_found = 1;
>> +				ret = mi_lttng_session(writer, &sessions[i], 1);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +				break;
>> +			}
>>   	}
>>
>> -	ret = CMD_SUCCESS;
>> +	if (!session_found) {
>> +		ERR("Session not found");
>> +		ret = -LTTNG_ERR_SESS_NOT_FOUND;
>> +		goto end;
>> +	}
>>
>> -error:
>> -	free(channels);
>> +end:
>> +	return ret;
>> +}
>>
>> -error_channels:
>> +/*
>> + * Machine interface
>> + * List all availables session
>> + */
>> +static int mi_list_sessions(struct lttng_session *sessions, int count)
>> +{
>> +	int ret, i;
>> +
>> +	/* Opening sessions element */
>> +	ret = mi_lttng_sessions_open(writer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Listing sessions */
>> +	for (i = 0; i < count; i++) {
>> +		ret = mi_lttng_session(writer, &sessions[i], 0);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +
>> +	/* Closing sessions element */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +end:
>>   	return ret;
>>   }
>>
>> @@ -730,7 +1155,8 @@ error_channels:
>>    */
>>   static int list_sessions(const char *session_name)
>>   {
>> -	int ret, count, i;
>> +	int ret = CMD_SUCCESS;
>> +	int count, i;
>>   	unsigned int session_found = 0;
>>   	struct lttng_session *sessions;
>>
>> @@ -740,48 +1166,85 @@ static int list_sessions(const char *session_name)
>>   		ret = count;
>>   		ERR("%s", lttng_strerror(ret));
>>   		goto error;
>> -	} else if (count == 0) {
>> -		MSG("Currently no available tracing session");
>> -		goto end;
>>   	}
>>
>> -	if (session_name == NULL) {
>> -		MSG("Available tracing sessions:");
>> -	}
>> +	if (lttng_opt_mi) {
>> +		/* Mi */
>> +		if (session_name == NULL) {
>> +			/* List all session */
>> +			ret = mi_list_sessions(sessions, count);
>> +		} else {
>> +			/* Note : this return an open session element */
>> +			ret = mi_list_session(session_name, sessions, count);
>> +		}
>> +	} else {
>> +		/* Pretty print */
>> +		if (count == 0) {
>> +			MSG("Currently no available tracing session");
>> +			goto end;
>> +		}
>>
>> -	for (i = 0; i < count; i++) {
>> -		if (session_name != NULL) {
>> -			if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
>> -				session_found = 1;
>> -				MSG("Tracing session %s: [%s%s]", session_name,
>> +		if (session_name == NULL) {
>> +			MSG("Available tracing sessions:");
>> +		}
>> +
>> +
>> +		for (i = 0; i < count; i++) {
>> +			if (session_name != NULL) {
>> +				if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
>> +					session_found = 1;
>> +					MSG("Tracing session %s: [%s%s]", session_name,
>> +							active_string(sessions[i].enabled),
>> +							snapshot_string(sessions[i].snapshot_mode));
>> +					MSG("%sTrace path: %s\n", indent4, sessions[i].path);
>> +					break;
>> +				}
>> +			} else {
>> +				MSG("  %d) %s (%s) [%s%s]", i + 1,
>> +						sessions[i].name, sessions[i].path,
>>   						active_string(sessions[i].enabled),
>>   						snapshot_string(sessions[i].snapshot_mode));
>> -				MSG("%sTrace path: %s\n", indent4, sessions[i].path);
>> -				break;
>>   			}
>> -		} else {
>> -			MSG("  %d) %s (%s) [%s%s]", i + 1, sessions[i].name, sessions[i].path,
>> -					active_string(sessions[i].enabled),
>> -					snapshot_string(sessions[i].snapshot_mode));
>> +		}
>> +
>> +		if (!session_found && session_name != NULL) {
>> +			ERR("Session '%s' not found", session_name);
>> +			ret = CMD_ERROR;
>> +			goto error;
>> +		}
>> +
>> +		if (session_name == NULL) {
>> +			MSG("\nUse lttng list <session_name> for more details");
>>   		}
>>   	}
>>
>> +error:
>>   	free(sessions);
>> +end:
>> +	return ret;
>> +}
>>
>> -	if (!session_found && session_name != NULL) {
>> -		ERR("Session '%s' not found", session_name);
>> -		ret = CMD_ERROR;
>> -		goto error;
>> +
>> +/*
>> + * Machine Interface
>> + * list available domain(s) for a session.
>> + */
>> +static int mi_list_domains(struct lttng_domain *domains, int count)
>> +{
>> +	int i, ret;
>> +	/* Open domains element */
>> +	ret = mi_lttng_domains_open(writer);
>> +	if (ret) {
>> +		goto end;
>>   	}
>>
>> -	if (session_name == NULL) {
>> -		MSG("\nUse lttng list <session_name> for more details");
>> +	for (i = 0; i < count; i++) {
>> +		ret = mi_lttng_domain(writer, &domains[i] , 0);
>>   	}
>>
>> +	/* Closing domains element */
>> +	ret = mi_lttng_writer_close_element(writer);
>>   end:
>> -	return CMD_SUCCESS;
>> -
>> -error:
>>   	return ret;
>>   }
>>
>> @@ -793,31 +1256,39 @@ static int list_domains(const char *session_name)
>>   	int i, count, ret = CMD_SUCCESS;
>>   	struct lttng_domain *domains = NULL;
>>
>> -	MSG("Domains:\n-------------");
>>
>>   	count = lttng_list_domains(session_name, &domains);
>>   	if (count < 0) {
>>   		ret = count;
>>   		ERR("%s", lttng_strerror(ret));
>>   		goto error;
>> -	} else if (count == 0) {
>> -		MSG("  None");
>> -		goto end;
>>   	}
>>
>> -	for (i = 0; i < count; i++) {
>> -		switch (domains[i].type) {
>> -		case LTTNG_DOMAIN_KERNEL:
>> -			MSG("  - Kernel");
>> -			break;
>> -		case LTTNG_DOMAIN_UST:
>> -			MSG("  - UST global");
>> -			break;
>> -		case LTTNG_DOMAIN_JUL:
>> -			MSG("  - JUL (Java Util Logging)");
>> -			break;
>> -		default:
>> -			break;
>> +	if (lttng_opt_mi) {
>> +		/* Mi output */
>> +		ret = mi_list_domains(domains, count);
>> +	} else {
>> +		/* Pretty print */
>> +		MSG("Domains:\n-------------");
>> +		if (count == 0) {
>> +			MSG("  None");
>> +			goto end;
>> +		}
>> +
>> +		for (i = 0; i < count; i++) {
>> +			switch (domains[i].type) {
>> +			case LTTNG_DOMAIN_KERNEL:
>> +				MSG("  - Kernel");
>> +				break;
>> +			case LTTNG_DOMAIN_UST:
>> +				MSG("  - UST global");
>> +				break;
>> +			case LTTNG_DOMAIN_JUL:
>> +				MSG("  - JUL (Java Util Logging)");
>> +				break;
>> +			default:
>> +				break;
>> +			}
>>   		}
>>   	}
>>
>> @@ -850,13 +1321,6 @@ int cmd_list(int argc, const char **argv)
>>   	pc = poptGetContext(NULL, argc, argv, long_options, 0);
>>   	poptReadDefaultConfig(pc, 0);
>>
>> -	/* TODO: mi support */
>> -	if (lttng_opt_mi) {
>> -		ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED;
>> -		ERR("mi option not supported");
>> -		goto end;
>> -	}
>> -
>>   	while ((opt = poptGetNextOpt(pc)) != -1) {
>>   		switch (opt) {
>>   		case OPT_HELP:
>> @@ -875,6 +1339,29 @@ int cmd_list(int argc, const char **argv)
>>   		}
>>   	}
>>
>> +	/* Mi check */
>> +	if (lttng_opt_mi) {
>> +		writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
>> +		if (!writer) {
>> +			ret = -LTTNG_ERR_NOMEM;
>> +			goto end;
>> +		}
>> +
>> +		/* Open command element */
>> +		ret = mi_lttng_writer_command_open(writer,
>> +				mi_lttng_element_command_list);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +
>> +		/* Open output element */
>> +		ret = mi_lttng_writer_open_element(writer,
>> +				mi_lttng_element_command_output);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +
>>   	/* Get session name (trailing argument) */
>>   	session_name = poptGetArg(pc);
>>   	DBG2("Session name: %s", session_name);
>> @@ -900,14 +1387,13 @@ int cmd_list(int argc, const char **argv)
>>   	if (session_name == NULL) {
>>   		if (!opt_kernel && !opt_userspace && !opt_jul) {
>>   			ret = list_sessions(NULL);
>> -			if (ret != 0) {
>> +			if (ret) {
>>   				goto end;
>>   			}
>>   		}
>>   		if (opt_kernel) {
>>   			ret = list_kernel_events();
>> -			if (ret < 0) {
>> -				ret = CMD_ERROR;
>> +			if (ret) {
>>   				goto end;
>>   			}
>>   		}
>> @@ -917,22 +1403,29 @@ int cmd_list(int argc, const char **argv)
>>   			} else {
>>   				ret = list_ust_events();
>>   			}
>> -			if (ret < 0) {
>> -				ret = CMD_ERROR;
>> +			if (ret) {
>>   				goto end;
>>   			}
>>   		}
>>   		if (opt_jul) {
>>   			ret = list_jul_events();
>> -			if (ret < 0) {
>> -				ret = CMD_ERROR;
>> +			if (ret) {
>>   				goto end;
>>   			}
>>   		}
>>   	} else {
>>   		/* List session attributes */
>> +		if (lttng_opt_mi) {
>> +			/* Open element sessions
>> +			 * Present for xml consistency */
>> +			ret = mi_lttng_sessions_open(writer);
>> +			if (ret) {
>> +				goto end;
>> +			}
>> +		}
>> +		/* MI: the ouptut of list_sessions is an unclosed session element */
>>   		ret = list_sessions(session_name);
>> -		if (ret != 0) {
>> +		if (ret) {
>>   			goto end;
>>   		}
>>
>> @@ -942,12 +1435,40 @@ int cmd_list(int argc, const char **argv)
>>   			goto end;
>>   		}
>>
>> +		/* Channel listing */
>>   		if (opt_kernel || opt_userspace) {
>> -			/* Channel listing */
>> +			if (lttng_opt_mi) {
>> +				/* Add of domains and domain element for xml
>> +				 * consistency and validation
>> +				 */
>> +				ret = mi_lttng_domains_open(writer);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +
>> +				/* Open domain and leave it open for
>> +				 * nested channels printing */
>> +				ret = mi_lttng_domain(writer, &domain, 1);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +
>> +			}
>> +
>>   			ret = list_channels(opt_channel);
>> -			if (ret < 0) {
>> +			if (ret) {
>> +				goto end;
>> +			}
>> +
>> +			if (lttng_opt_mi) {
>> +				/* Close domain and domain element */
>> +				ret = mi_lttng_close_multi_element(writer, 2);
>> +			}
>> +			if (ret) {
>>   				goto end;
>>   			}
>> +
>> +
>>   		} else {
>>   			int i, nb_domain;
>>
>> @@ -959,6 +1480,13 @@ int cmd_list(int argc, const char **argv)
>>   				goto end;
>>   			}
>>
>> +			if (lttng_opt_mi) {
>> +				ret = mi_lttng_domains_open(writer);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +			}
>> +
>>   			for (i = 0; i < nb_domain; i++) {
>>   				switch (domains[i].type) {
>>   				case LTTNG_DOMAIN_KERNEL:
>> @@ -978,6 +1506,13 @@ int cmd_list(int argc, const char **argv)
>>   					break;
>>   				}
>>
>> +				if (lttng_opt_mi) {
>> +					ret = mi_lttng_domain(writer, &domains[i], 1);
>> +					if (ret) {
>> +						goto end;
>> +					}
>> +				}
>> +
>>   				/* Clean handle before creating a new one */
>>   				if (handle) {
>>   					lttng_destroy_handle(handle);
>> @@ -991,21 +1526,57 @@ int cmd_list(int argc, const char **argv)
>>
>>   				if (domains[i].type == LTTNG_DOMAIN_JUL) {
>>   					ret = list_session_jul_events();
>> -					if (ret < 0) {
>> +					if (ret) {
>>   						goto end;
>>   					}
>>   					continue;
>>   				}
>>
>>   				ret = list_channels(opt_channel);
>> -				if (ret < 0) {
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +
>> +				if (lttng_opt_mi) {
>> +					/* Close domain element */
>> +					ret = mi_lttng_writer_close_element(writer);
>> +					if (ret) {
>> +						goto end;
>> +					}
>> +				}
>> +
>> +			}
>> +			if (lttng_opt_mi) {
>> +				/* Close the domains, session and sessions element */
>> +				ret = mi_lttng_close_multi_element(writer, 3);
>> +				if (ret) {
>>   					goto end;
>>   				}
>>   			}
>>   		}
>>   	}
>>
>> +	/* Mi closing */
>> +	if (lttng_opt_mi) {
>> +		/* Close  output element */
>> +		ret = mi_lttng_writer_close_element(writer);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +
>> +		/* Command element close */
>> +		ret = mi_lttng_writer_command_close(writer);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>>   end:
>> +	/* Mi clean-up */
>> +	if (writer && mi_lttng_writer_destroy(writer)) {
>> +		/* Preserve original error code */
>> +		ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
>> +	}
>> +
>>   	free(domains);
>>   	if (handle) {
>>   		lttng_destroy_handle(handle);
>> --
>> 1.9.1
>>
>
>>  From f478c2feebbf136bacf571e42054312a01ba6074 Mon Sep 17 00:00:00 2001
>> From: Jonathan Rajotte <jonathan.r.julien at gmail.com>
>> Date: Wed, 16 Apr 2014 17:14:08 -0400
>> Subject: [PATCH 3/5] Mi: mi xsd validation
>>
>> Command list and version supported
>>
>> Signed-off-by: Jonathan Rajotte <jonathan.r.julien at gmail.com>
>> ---
>>   src/common/mi_lttng.xsd | 320 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 320 insertions(+)
>>   create mode 100644 src/common/mi_lttng.xsd
>>
>> diff --git a/src/common/mi_lttng.xsd b/src/common/mi_lttng.xsd
>> new file mode 100644
>> index 0000000..6fc25c6
>> --- /dev/null
>> +++ b/src/common/mi_lttng.xsd
>> @@ -0,0 +1,320 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<!--
>> +Copyright (c) 2014 - Oliver Cotte <olivier.cotte at polymtl.ca>
>> +                   - Jonathan Rajotte <jonathan.r.julien at gmail.com>
>> +
>> +Permission is hereby granted, free of charge, to any person obtaining a copy
>> +of this software and associated documentation files (the "Software"), to deal
>> +in the Software without restriction, including without limitation the rights
>> +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>> +copies of the Software, and to permit persons to whom the Software is
>> +furnished to do so, subject to the following conditions:
>> +
>> +The above copyright notice and this permission notice shall be included in
>> +all copies or substantial portions of the Software.
>> +
>> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
>> +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>> +THE SOFTWARE.
>> +-->
>> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
>> +	elementFormDefault="qualified" version="2.5">
>> +
>> +	<!-- Maps to the uint32_t type -->
>> +	<xs:simpleType name="uint32_type">
>> +		<xs:restriction base="xs:integer">
>> +			<xs:minInclusive value="0" />
>> +			<xs:maxInclusive value="4294967295" />
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<!-- Maps to the uint64_t type -->
>> +	<xs:simpleType name="uint64_type">
>> +		<xs:restriction base="xs:integer">
>> +			<xs:minInclusive value="0" />
>> +			<xs:maxInclusive value="18446744073709551615" />
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<!-- Maps to the char name[LTTNG_SYMBOL_NAME_LEN] -->
>> +	<xs:simpleType name="name_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:maxLength value="255" />
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<!-- Maps to the lttng_event_type enum -->
>> +	<xs:simpleType name="event_type_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:enumeration value="ALL" />
>> +			<xs:enumeration value="TRACEPOINT" />
>> +			<xs:enumeration value="PROBE" />
>> +			<xs:enumeration value="FUNCTION" />
>> +			<xs:enumeration value="FUNCTION_ENTRY" />
>> +			<xs:enumeration value="NOOP" />
>> +			<xs:enumeration value="SYSCALL" />
>> +			<xs:enumeration value="KPROBE" />
>> +			<xs:enumeration value="KRETPROBE" />
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<!-- Maps to the lttng_event_field_type enum -->
>> +	<xs:simpleType name="event_field_type_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:enumeration value="OTHER" />
>> +			<xs:enumeration value="INTEGER" />
>> +			<xs:enumeration value="ENUM" />
>> +			<xs:enumeration value="FLOAT" />
>> +			<xs:enumeration value="STRING" />
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<!-- Maps to the lttng_loglevel_type enum -->
>> +	<xs:simpleType name="loglevel_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:enumeration value="ALL" />
>> +			<xs:enumeration value="RANGE" />
>> +			<xs:enumeration value="SINGLE" />
>> +			<xs:enumeration value="UNKNOWN" />
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<!-- Maps to loglevel_string char * -->
>> +	<xs:simpleType name="loglevel_string_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:enumeration value="" />
>> +			<xs:enumeration value="TRACE_EMERG" />
>> +			<xs:enumeration value="TRACE_ALERT" />
>> +			<xs:enumeration value="TRACE_CRIT" />
>> +			<xs:enumeration value="TRACE_ERR" />
>> +			<xs:enumeration value="TRACE_WARNING" />
>> +			<xs:enumeration value="TRACE_NOTICE" />
>> +			<xs:enumeration value="TRACE_INFO" />
>> +			<xs:enumeration value="TRACE_DEBUG_SYSTEM" />
>> +			<xs:enumeration value="TRACE_DEBUG_PROGRAM" />
>> +			<xs:enumeration value="TRACE_DEBUG_PROCESS" />
>> +			<xs:enumeration value="TRACE_DEBUG_MODULE" />
>> +			<xs:enumeration value="TRACE_DEBUG_UNIT" />
>> +			<xs:enumeration value="TRACE_DEBUG_FUNCTION" />
>> +			<xs:enumeration value="TRACE_DEBUG_LINE" />
>> +			<xs:enumeration value="TRACE_DEBUG" />
>> +			<xs:enumeration value="UNKNOWN" />
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<!-- Maps to the lttng_event_probe_attr struct -->
>> +	<xs:complexType name="event_probe_attributes_type">
>> +		<xs:all>
>> +			<xs:element name="address" type="uint64_type" />
>> +			<xs:element name="offset" type="uint64_type" />
>> +			<xs:element name="symbol_name" type="name_type" />
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +	<!-- Maps to the lttng_event_function_attr struct -->
>> +	<xs:complexType name="event_ftrace_attributes_type">
>> +		<xs:all>
>> +			<xs:element name="symbol_name" type="name_type" />
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +	<!-- Maps to per event type configuration -->
>> +	<xs:complexType name="event_attributes_type">
>> +		<xs:choice>
>> +			<xs:element name="probe_attributes" type="event_probe_attributes_type" />
>> +			<xs:element name="function_attributes" type="event_ftrace_attributes_type" />
>> +		</xs:choice>
>> +	</xs:complexType>
>> +
>> +	<!-- Maps to lttng_event struct -->
>> +	<xs:complexType name="event_type">
>> +		<xs:all>
>> +			<xs:element name="type" type="event_type_type" default="TRACEPOINT" minOccurs="0" />
>> +			<xs:element name="name" type="name_type" minOccurs="0" />
>> +			<xs:element name="loglevel_type" type="loglevel_type" default="ALL" minOccurs="0" />
>> +			<xs:element name="loglevel" type="loglevel_string_type" default="" minOccurs="0" />
>> +			<xs:element name="enabled" type="xs:boolean" default="false" minOccurs="0" />
>> +			<xs:element name="filter" type="xs:boolean" minOccurs="0" />
>> +			<xs:element name="exclusion" type="xs:boolean" minOccurs="0" />
>> +			<xs:element name="attributes" type="event_attributes_type" minOccurs="0" />
>> +			<xs:element name="event_fields" type="event_fields_type" minOccurs="0" />
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +	<!-- Maps to mi_lttng_version struct -->
>> +	<xs:complexType name="version_type">
>> +		<xs:all>
>> +			<xs:element name="name" type="name_type" />
>> +			<xs:element name="string" type="name_type" />
>> +			<xs:element name="major" type="uint32_type" />
>> +			<xs:element name="url" type="xs:string" />
>> +			<xs:element name="minor" type="uint32_type" />
>> +			<xs:element name="license" type="xs:string" />
>> +			<xs:element name="patchLevel" type="uint32_type" />
>> +			<xs:element name="description" type="xs:string" />
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +	<xs:complexType name="event_list_type">
>> +		<xs:sequence>
>> +			<xs:element name="event" type="event_type" minOccurs="0" maxOccurs="unbounded" />
>> +		</xs:sequence>
>> +	</xs:complexType>
>> +
>> +	<!-- Maps to the lttng_domain_type enum -->
>> +	<xs:simpleType name="domain_type_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:enumeration value="KERNEL"/>
>> +			<xs:enumeration value="UST"/>
>> +			<xs:enumeration value="JUL"/>
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<!-- Maps to the lttng_buffer_type enum -->
>> +	<xs:simpleType name="domain_buffer_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:enumeration value="PER_PID"/>
>> +			<xs:enumeration value="PER_UID"/>
>> +			<xs:enumeration value="GLOBAL"/>
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<xs:simpleType name="channel_overwrite_mode_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:enumeration value="DISCARD" />
>> +			<xs:enumeration value="OVERWRITE" />
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<!-- Maps to the lttng_event_output enum -->
>> +	<xs:simpleType name="event_output_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:enumeration value="SPLICE" />
>> +			<xs:enumeration value="MMAP" />
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<xs:complexType name="pid_type">
>> +		<xs:all>
>> +			<xs:element name="id" type="xs:int"/>
>> +			<xs:element name="name" type="name_type"/>
>> +			<xs:element name="events" type="event_list_type" minOccurs="0" />
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +	<xs:complexType name="pids_type">
>> +		<xs:sequence>
>> +			<xs:element name="pid" type="pid_type" minOccurs="0" maxOccurs="unbounded" />
>> +		</xs:sequence>
>> +	</xs:complexType>
>> +
>> +	<!-- Maps to struct lttng_domain and contains channels -->
>> +	<xs:complexType name="domain_type">
>> +		<xs:all>
>> +			<xs:element name="type" type="domain_type_type"/>
>> +			<xs:element name="buffer_type" type="domain_buffer_type"/>
>> +			<xs:element name="pids" type="pids_type" minOccurs="0" />
>> +			<xs:element name="channels" type="channels_type" minOccurs="0" />
>> +			<xs:element name="events" type="event_list_type" minOccurs="0" />
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +	<!-- Maps to struct lttng_channel -->
>> +	<xs:complexType name="channel_type">
>> +		<xs:all>
>> +			<xs:element name="name" type="name_type"/>
>> +			<xs:element name="enabled" type="xs:boolean" default="true" minOccurs="0"/>
>> +			<xs:element name="attributes" type="channel_attributes_type" minOccurs="0"/>
>> +			<xs:element name="events" type="event_list_type"/>
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +	<!-- Maps to struct lttng_channel_attr -->
>> +	<xs:complexType name="channel_attributes_type">
>> +		<xs:all>
>> +			<xs:element name="overwrite_mode" type="channel_overwrite_mode_type" default="DISCARD" minOccurs="0"/>
>> +			<xs:element name="subbuffer_size" type="uint64_type" minOccurs="0"/> <!-- bytes -->
>> +			<xs:element name="subbuffer_count" type="uint64_type" default="4" minOccurs="0"/>
>> +			<xs:element name="switch_timer_interval" type="uint32_type" default="0" minOccurs="0"/>  <!-- usec -->
>> +			<xs:element name="read_timer_interval" type="uint32_type"/>  <!-- usec -->
>> +			<xs:element name="output_type" type="event_output_type"/>
>> +			<xs:element name="tracefile_size" type="uint64_type" default="0" minOccurs="0"/> <!-- bytes -->
>> +			<xs:element name="tracefile_count" type="uint64_type" default="0" minOccurs="0"/>
>> +			<xs:element name="live_timer_interval" type="uint32_type" default="0" minOccurs="0"/> <!-- usec -->
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +	<xs:complexType name="channels_type">
>> +		<xs:sequence>
>> +			<xs:element name="channel" type="channel_type" minOccurs="0" maxOccurs="unbounded" />
>> +		</xs:sequence>
>> +	</xs:complexType>
>> +
>> +	<xs:complexType name="session_type">
>> +		<xs:all>
>> +			<xs:element name="name" type="name_type" />
>> +			<xs:element name="path" type="name_type" />
>> +			<xs:element name="enabled" type="xs:boolean" default="false" />
>> +			<xs:element name="snapshot_mode" type="uint32_type" />
>> +			<xs:element name="live_timer_interval" type="uint32_type" />
>> +			<xs:element name="channels" type="channels_type" minOccurs="0" />
>> +			<xs:element name="domains" type="domains_type" minOccurs="0" />
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +	<xs:complexType name="event_field_type">
>> +		<xs:all>
>> +			<xs:element name="name" type="name_type" />
>> +			<xs:element name="type" type="event_field_type_type"/>
>> +			<xs:element name="nowrite" type="xs:int"/>
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +
>> +	<xs:complexType name="domains_type">
>> +		<xs:sequence>
>> +			<xs:element name="domain" type="domain_type" minOccurs="0" maxOccurs="unbounded" />
>> +		</xs:sequence>
>> +	</xs:complexType>
>> +
>> +	<xs:complexType name="sessions_type">
>> +		<xs:sequence>
>> +			<xs:element name="session" type="session_type" minOccurs="0" maxOccurs="unbounded" />
>> +		</xs:sequence>
>> +	</xs:complexType>
>> +
>> +	<xs:complexType name="event_fields_type">
>> +		<xs:sequence>
>> +			<xs:element name="event_field" type="event_field_type" minOccurs="0" maxOccurs="unbounded" />
>> +		</xs:sequence>
>> +	</xs:complexType>
>> +
>> +	<xs:complexType name="output_type">
>> +		<xs:choice>
>> +			<xs:element name="domains" type="domains_type" minOccurs="0" />
>> +			<xs:element name="sessions" type="sessions_type" minOccurs="0" />
>> +			<xs:element name="version" type="version_type" minOccurs="0" />
>> +		</xs:choice>
>> +	</xs:complexType>
>> +
>> +	<!-- Maps to the mi_lttng commands -->
>> +	<xs:simpleType name="command_string_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:enumeration value="list" />
>> +			<xs:enumeration value="version" />
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>> +	<xs:element name="command">
>> +		<xs:complexType>
>> +			<xs:all>
>> +				<xs:element name="name" type="command_string_type" maxOccurs="1" />
>> +				<xs:element name="output" type="output_type" maxOccurs="1" />
>> +			</xs:all>
>> +		</xs:complexType>
>> +	</xs:element>
>> +</xs:schema>
>> --
>> 1.9.1
>>
>
>>  From 06fd69b77160dc43c01597796048c88b9ddcd18e Mon Sep 17 00:00:00 2001
>> From: Jonathan Rajotte <jonathan.r.julien at gmail.com>
>> Date: Thu, 17 Apr 2014 15:32:40 -0400
>> Subject: [PATCH 5/5] Mi: add mi to snapshot command
>>
>> Signed-off-by: Jonathan Rajotte <jonathan.r.julien at gmail.com>
>> ---
>>   src/bin/lttng/commands/snapshot.c | 244 +++++++++++++++++++++++++++++++++++--
>>   src/common/mi-lttng.c             | 247 +++++++++++++++++++++++++++++++++++++-
>>   src/common/mi-lttng.h             | 130 ++++++++++++++++++++
>>   src/common/mi_lttng.xsd           |  34 ++++++
>>   4 files changed, 641 insertions(+), 14 deletions(-)
>>
>> diff --git a/src/bin/lttng/commands/snapshot.c b/src/bin/lttng/commands/snapshot.c
>> index 21b5a05..46a863d 100644
>> --- a/src/bin/lttng/commands/snapshot.c
>> +++ b/src/bin/lttng/commands/snapshot.c
>> @@ -27,6 +27,7 @@
>>   #include <unistd.h>
>>
>>   #include <common/utils.h>
>> +#include <common/mi-lttng.h>
>>   #include <lttng/snapshot.h>
>>
>>   #include "../command.h"
>> @@ -53,6 +54,8 @@ enum {
>>   	OPT_LIST_COMMANDS,
>>   };
>>
>> +static struct mi_writer *writer;
>> +
>>   static struct poptOption snapshot_opts[] = {
>>   	/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
>>   	{"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
>> @@ -181,6 +184,44 @@ error_create:
>>   	return NULL;
>>   }
>>
>> +static int mi_list_output(void)
>> +{
>> +	int ret;
>> +	struct lttng_snapshot_output *s_iter;
>> +	struct lttng_snapshot_output_list *list;
>> +
>> +	ret = lttng_snapshot_list_output(current_session_name, &list);
>> +	if (ret < 0) {
>> +		goto error;
>> +	}
>> +
>> +	ret = mi_lttng_snapshot_output_session_name(writer, current_session_name);
>> +	if (ret) {
>> +		goto error;
>> +	}
>> +
>> +	while ((s_iter = lttng_snapshot_output_list_get_next(list)) != NULL) {
>> +		ret = mi_lttng_snapshot_list_output(writer, s_iter);
>> +		if (ret) {
>> +			goto error;
>> +		}
>> +	}
>> +
>> +	lttng_snapshot_output_list_destroy(list);
>> +
>> +	/* Close snapshot snapshots element */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +	if (ret) {
>> +		goto error;
>> +	}
>> +
>> +	/* Close snapshot session element */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +
>> +error:
>> +	return ret;
>> +}
>> +
>>   static int list_output(void)
>>   {
>>   	int ret, output_seen = 0;
>> @@ -213,6 +254,45 @@ error:
>>   }
>>
>>   /*
>> + * Delete output by ID (machine interface version).
>> + */
>> +static int mi_del_output(uint32_t id, const char *name)
>> +{
>> +	int ret;
>> +	struct lttng_snapshot_output *output = NULL;
>> +
>> +	output = lttng_snapshot_output_create();
>> +	if (!output) {
>> +		ret = CMD_FATAL;
>> +		goto error;
>> +	}
>> +
>> +	if (name) {
>> +		ret = lttng_snapshot_output_set_name(name, output);
>> +	} else if (id != UINT32_MAX) {
>> +		ret = lttng_snapshot_output_set_id(id, output);
>> +	} else {
>> +		ret = CMD_ERROR;
>> +		goto error;
>> +	}
>> +	if (ret < 0) {
>> +		ret = CMD_FATAL;
>> +		goto error;
>> +	}
>> +
>> +	ret = lttng_snapshot_del_output(current_session_name, output);
>> +	if (ret < 0) {
>> +		goto error;
>> +	}
>> +
>> +	ret = mi_lttng_snapshot_del_output(writer, id, name, current_session_name);
>> +
>> +error:
>> +	lttng_snapshot_output_destroy(output);
>> +	return ret;
>> +}
>> +
>> +/*
>>    * Delete output by ID.
>>    */
>>   static int del_output(uint32_t id, const char *name)
>> @@ -258,6 +338,52 @@ error:
>>   }
>>
>>   /*
>> + * Add output from the user URL (machine interface).
>> + */
>> +static int mi_add_output(const char *url)
>> +{
>> +	int ret;
>> +	struct lttng_snapshot_output *output = NULL;
>> +	char name[NAME_MAX];
>> +	const char *n_ptr;
>> +
>> +	if (!url && (!opt_data_url || !opt_ctrl_url)) {
>> +		ret = CMD_ERROR;
>> +		goto error;
>> +	}
>> +
>> +	output = create_output_from_args(url);
>> +	if (!output) {
>> +		ret = CMD_FATAL;
>> +		goto error;
>> +	}
>> +
>> +	/* This call, if successful, populates the id of the output object. */
>> +	ret = lttng_snapshot_add_output(current_session_name, output);
>> +	if (ret < 0) {
>> +		goto error;
>> +	}
>> +
>> +	n_ptr = lttng_snapshot_output_get_name(output);
>> +	if (*n_ptr == '\0') {
>> +		int pret;
>> +		pret = snprintf(name, sizeof(name), DEFAULT_SNAPSHOT_NAME "-%" PRIu32,
>> +				lttng_snapshot_output_get_id(output));
>> +		if (pret < 0) {
>> +			PERROR("snprintf add output name");
>> +		}
>> +		n_ptr = name;
>> +	}
>> +
>> +	ret = mi_lttng_snapshot_add_output(writer, current_session_name, n_ptr,
>> +			output);
>> +
>> +error:
>> +	lttng_snapshot_output_destroy(output);
>> +	return ret;
>> +}
>> +
>> +/*
>>    * Add output from the user URL.
>>    */
>>   static int add_output(const char *url)
>> @@ -308,7 +434,7 @@ error:
>>
>>   static int cmd_add_output(int argc, const char **argv)
>>   {
>> -	int ret = CMD_SUCCESS;
>> +	int ret;
>>
>>   	if (argc < 2 && (!opt_data_url || !opt_ctrl_url)) {
>>   		usage(stderr);
>> @@ -316,7 +442,11 @@ static int cmd_add_output(int argc, const char **argv)
>>   		goto end;
>>   	}
>>
>> -	ret = add_output(argv[1]);
>> +	if (lttng_opt_mi) {
>> +		ret = mi_add_output(argv[1]);
>> +	} else {
>> +		ret = add_output(argv[1]);
>> +	}
>>
>>   end:
>>   	return ret;
>> @@ -324,7 +454,7 @@ end:
>>
>>   static int cmd_del_output(int argc, const char **argv)
>>   {
>> -	int ret = CMD_SUCCESS;
>> +	int ret;
>>   	char *name;
>>   	long id;
>>
>> @@ -337,9 +467,17 @@ static int cmd_del_output(int argc, const char **argv)
>>   	errno = 0;
>>   	id = strtol(argv[1], &name, 10);
>>   	if (id == 0 && errno == 0) {
>> -		ret = del_output(UINT32_MAX, name);
>> +		if (lttng_opt_mi) {
>> +			ret = mi_del_output(UINT32_MAX, name);
>> +		} else {
>> +			ret = del_output(UINT32_MAX, name);
>> +		}
>>   	} else if (errno == 0 && *name == '\0') {
>> -		ret = del_output(id, NULL);
>> +		if (lttng_opt_mi) {
>> +			ret = mi_del_output(id, NULL);
>> +		} else {
>> +			ret = del_output(id, NULL);
>> +		}
>>   	} else {
>>   		ERR("Argument %s not recognized", argv[1]);
>>   		ret = -1;
>> @@ -352,7 +490,42 @@ end:
>>
>>   static int cmd_list_output(int argc, const char **argv)
>>   {
>> -	return list_output();
>> +	int ret;
>> +
>> +	if (lttng_opt_mi) {
>> +		ret = mi_list_output();
>> +	} else {
>> +		ret = list_output();
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +/*
>> + * Do a snapshot record with the URL if one is given (machine interface).
>> + */
>> +static int mi_record(const char *url)
>> +{
>> +	int ret;
>> +	struct lttng_snapshot_output *output = NULL;
>> +
>> +	output = create_output_from_args(url);
>> +	if (!output) {
>> +		ret = CMD_FATAL;
>> +		goto error;
>> +	}
>> +
>> +	ret = lttng_snapshot_record(current_session_name, output, 0);
>> +	if (ret < 0) {
>> +		goto error;
>> +	}
>> +
>> +	ret = mi_lttng_snapshot_record(writer, current_session_name, url,
>> +			opt_ctrl_url, opt_data_url);
>> +
>> +error:
>> +	lttng_snapshot_output_destroy(output);
>> +	return ret;
>>   }
>>
>>   /*
>> @@ -394,9 +567,17 @@ static int cmd_record(int argc, const char **argv)
>>
>>   	if (argc == 2) {
>>   		/* With a given URL */
>> -		ret = record(argv[1]);
>> +		if (lttng_opt_mi) {
>> +			ret = mi_record(argv[1]);
>> +		} else {
>> +			ret = record(argv[1]);
>> +		}
>>   	} else {
>> -		ret = record(NULL);
>> +		if (lttng_opt_mi) {
>> +			ret = mi_record(NULL);
>> +		} else {
>> +			ret = record(NULL);
>> +		}
>>   	}
>>
>>   	return ret;
>> @@ -420,6 +601,23 @@ static int handle_command(const char **argv)
>>   	while (cmd->func != NULL) {
>>   		/* Find command */
>>   		if (strcmp(argv[0], cmd->name) == 0) {
>> +			if (lttng_opt_mi) {
>> +				/* Type of the action */
>> +				ret = mi_lttng_writer_write_element_string(writer,
>> +						mi_lttng_element_command_action,
>> +						argv[0]);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +
>> +				/* Open output element */
>> +				ret = mi_lttng_writer_open_element(writer,
>> +						mi_lttng_element_command_output);
>> +				if (ret) {
>> +					goto end;
>> +				}
>> +			}
>> +
>>   			ret = cmd->func(argc, argv);
>>   			goto end;
>>   		}
>> @@ -431,6 +629,11 @@ static int handle_command(const char **argv)
>>   	ret = CMD_UNDEFINED;
>>
>>   end:
>> +	if (lttng_opt_mi) {
>> +		/* Close output element */
>> +		ret = mi_lttng_writer_close_element(writer);
>> +	}
>> +
>>   	return ret;
>>   }
>>
>> @@ -439,18 +642,27 @@ end:
>>    */
>>   int cmd_snapshot(int argc, const char **argv)
>>   {
>> -	int opt, ret = CMD_SUCCESS;
>> +	int opt, ret;
>>   	char *session_name = NULL;
>>   	static poptContext pc;
>>
>>   	pc = poptGetContext(NULL, argc, argv, snapshot_opts, 0);
>>   	poptReadDefaultConfig(pc, 0);
>>
>> -	/* TODO: mi support */
>> +	/* Mi check */
>>   	if (lttng_opt_mi) {
>> -		ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED;
>> -		ERR("mi option not supported");
>> -		goto end;
>> +		writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
>> +		if (!writer) {
>> +			ret = -LTTNG_ERR_NOMEM;
>> +			goto end;
>> +		}
>> +
>> +		/* Open command element */
>> +		ret = mi_lttng_writer_command_open(writer,
>> +				mi_lttng_element_command_snapshot);
>> +		if (ret) {
>> +			goto end;
>> +		}
>>   	}
>>
>>   	while ((opt = poptGetNextOpt(pc)) != -1) {
>> @@ -514,6 +726,12 @@ int cmd_snapshot(int argc, const char **argv)
>>   	}
>>
>>   end:
>> +	/* Mi clean-up */
>> +	if (writer && mi_lttng_writer_destroy(writer)) {
>> +		/* Preserve original error code */
>> +		ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
>> +	}
>> +
>>   	if (!opt_session_name) {
>>   		free(session_name);
>>   	}
>> diff --git a/src/common/mi-lttng.c b/src/common/mi-lttng.c
>> index 2e4c366..ff689f5 100644
>> --- a/src/common/mi-lttng.c
>> +++ b/src/common/mi-lttng.c
>> @@ -19,12 +19,14 @@
>>
>>   #include <include/config.h>
>>   #include <common/config/config.h>
>> +#include <lttng/snapshot-internal.h>
>>   #include "mi-lttng.h"
>>
>>   #include <assert.h>
>>
>>   /* Strings related to command */
>>   const char * const mi_lttng_element_command = "command";
>> +const char * const mi_lttng_element_command_action = "action";
>>   const char * const mi_lttng_element_command_version = "version";
>>   const char * const mi_lttng_element_command_list = "list";
>>   const char * const mi_lttng_element_command_name = "name";
>> @@ -39,6 +41,11 @@ const char * const mi_lttng_element_version_minor = "minor";
>>   const char * const mi_lttng_element_version_license = "license";
>>   const char * const mi_lttng_element_version_patch_level = "patchLevel";
>>   const char * const mi_lttng_element_version_description = "description";
>> +const char * const mi_lttng_element_command_snapshot = "snapshot";
>> +const char * const mi_lttng_element_command_list_snapshot = "list_snapshot";
>> +const char * const mi_lttng_element_command_del_snapshot = "del_snapshot";
>> +const char * const mi_lttng_element_command_add_snapshot = "add_snapshot";
>> +const char * const mi_lttng_element_command_record_snapshot = "record_snapshot";
>>
>>   /* Strings related to pid */
>>   const char * const mi_lttng_element_pids = "pids";
>> @@ -56,9 +63,18 @@ const char * const mi_lttng_element_type_enum = "ENUM";
>>   const char * const mi_lttng_element_type_float = "FLOAT";
>>   const char * const mi_lttng_element_type_string = "STRING";
>>   const char * const mi_lttng_element_nowrite = "nowrite";
>> -
>> +const char * const mi_lttng_element_id = "id";
>>   const char * const mi_lttng_element_empty = "";
>>
>> +/* String related to a lttng_snapshot_output */
>> +const char * const mi_lttng_element_snapshots = "snapshots";
>> +const char * const mi_lttng_element_snapshot_session_name = "session_name";
>> +const char * const mi_lttng_element_snapshot_n_ptr = "n_ptr";
>> +const char * const mi_lttng_element_snapshot_data_url = "data_url";
>> +const char * const mi_lttng_element_snapshot_ctrl_url = "ctrl_url";
>> +const char * const mi_lttng_element_snapshot_max_size = "max_size";
>> +
>> +
>>   const char *mi_lttng_loglevel_string(int value)
>>   {
>>   	switch (value) {
>> @@ -936,3 +952,232 @@ close:
>>   end:
>>   	return ret;
>>   }
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_snapshot_output_session_name(struct mi_writer *writer,
>> +		const char *session_name)
>> +{
>> +	int ret;
>> +
>> +	/* Open session element */
>> +	ret = mi_lttng_writer_open_element(writer, config_element_session);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Snapshot output list for current session name */
>> +	ret = mi_lttng_writer_write_element_string(writer, config_element_name,
>> +			session_name);
>> +
>> +	/* Open element snapshots (sequence one snapshot) */
>> +	ret = mi_lttng_writer_open_element(writer, mi_lttng_element_snapshots);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_snapshot_list_output(struct mi_writer *writer,
>> +		struct lttng_snapshot_output *output)
>> +{
>> +	int ret;
>> +
>> +	/* Open element snapshot output */
>> +	ret = mi_lttng_writer_open_element(writer, mi_lttng_element_command_snapshot);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* ID of the snapshot output */
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +			mi_lttng_element_id, output->id);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Name of the output */
>> +	ret = mi_lttng_writer_write_element_string(writer, config_element_name,
>> +			output->name);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Destination of the output (ctrl_url)*/
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			mi_lttng_element_snapshot_ctrl_url, output->ctrl_url);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Destination of the output (data_url) */
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			mi_lttng_element_snapshot_data_url, output->data_url);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* total size of all stream combined */
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +			mi_lttng_element_snapshot_max_size, output->max_size);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Close snapshot output element */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_snapshot_del_output(struct mi_writer *writer, int id,
>> +		const char *name, const char *current_session_name)
>> +{
>> +	int ret;
>> +
>> +	/* Open element del_snapshot */
>> +	ret = mi_lttng_writer_open_element(writer,
>> +			mi_lttng_element_command_snapshot);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +
>> +	if (id != UINT32_MAX) {
>> +		/* "Snapshot output "id" successfully deleted for "current_session_name" */
>> +		/* ID of the snapshot output */
>> +		ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +				mi_lttng_element_id, id);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	} else {
>> +		/* "Snapshot output "name" successfully deleted for session "current_session_name" */
>> +		/* Name of the output */
>> +		ret = mi_lttng_writer_write_element_string(writer, config_element_name,
>> +				name);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +
>> +	/* Snapshot was deleted for session "current_session_name"*/
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			mi_lttng_element_snapshot_session_name,
>> +			current_session_name);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Close snapshot element */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_snapshot_add_output(struct mi_writer *writer,
>> +		const char *current_session_name, const char *n_ptr,
>> +		struct lttng_snapshot_output *output)
>> +{
>> +	int ret;
>> +
>> +	/* Open element snapshot */
>> +	ret = mi_lttng_writer_open_element(writer,
>> +			mi_lttng_element_command_snapshot);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Snapshot output id */
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer, mi_lttng_element_id,
>> +			output->id);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Snapshot output names */
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			config_element_name, n_ptr);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Destination of the output (ctrl_url)*/
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			mi_lttng_element_snapshot_ctrl_url, output->ctrl_url);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Snapshot added for session "current_session_name"*/
>> +	ret = mi_lttng_writer_write_element_string(writer,
>> +			mi_lttng_element_snapshot_session_name, current_session_name);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* total size of all stream combined */
>> +	ret = mi_lttng_writer_write_element_unsigned_int(writer,
>> +			mi_lttng_element_snapshot_max_size, output->max_size);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* Close snapshot element */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +
>> +end:
>> +	return ret;
>> +}
>> +
>> +LTTNG_HIDDEN
>> +int mi_lttng_snapshot_record(struct mi_writer *writer,
>> +		const char *current_session_name, const char *url,
>> +		const char *cmdline_ctrl_url, const char *cmdline_data_url)
>> +{
>> +	int ret;
>> +
>> +	/* Open element snapshot */
>> +	ret = mi_lttng_writer_open_element(writer,
>> +			mi_lttng_element_command_snapshot);
>> +	if (ret) {
>> +		goto end;
>> +	}
>> +
>> +	/* If a valid an url was given, serialize it,
>> +	 * else take the command line data and ctrl urls*/
>> +	if (url) {
>> +		/* Destination of the output (ctrl_url)*/
>> +		ret = mi_lttng_writer_write_element_string(writer,
>> +				mi_lttng_element_snapshot_ctrl_url, url);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	} else if (cmdline_ctrl_url) {
>> +		/* Destination of the output (ctrl_url)*/
>> +		ret = mi_lttng_writer_write_element_string(writer,
>> +				mi_lttng_element_snapshot_ctrl_url, cmdline_ctrl_url);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +
>> +		/* Destination of the output (data_url) */
>> +		ret = mi_lttng_writer_write_element_string(writer,
>> +				mi_lttng_element_snapshot_data_url, cmdline_data_url);
>> +		if (ret) {
>> +			goto end;
>> +		}
>> +	}
>> +
>> +	/* Close record_snapshot element */
>> +	ret = mi_lttng_writer_close_element(writer);
>> +
>> +end:
>> +	return ret;
>> +}
>> diff --git a/src/common/mi-lttng.h b/src/common/mi-lttng.h
>> index 2dca80c..faa6d38 100644
>> --- a/src/common/mi-lttng.h
>> +++ b/src/common/mi-lttng.h
>> @@ -26,6 +26,11 @@
>>   #include <common/config/config.h>
>>   #include <lttng/lttng.h>
>>
>> +#include <stdint.h>
>> +
>> +/* Don't want to reference snapshot-internal.h here */
>> +struct lttng_snapshot_output;
>> +
>>   /* Instance of a machine interface writer. */
>>   struct mi_writer {
>>   	struct config_writer *writer;
>> @@ -46,10 +51,16 @@ struct mi_lttng_version {
>>
>>   /* Strings related to command */
>>   const char * const mi_lttng_element_command;
>> +const char * const mi_lttng_element_command_action;
>>   const char * const mi_lttng_element_command_version;
>>   const char * const mi_lttng_element_command_list;
>>   const char * const mi_lttng_element_command_name;
>>   const char * const mi_lttng_element_command_output;
>> +const char * const mi_lttng_element_command_snapshot;
>> +const char * const mi_lttng_element_command_list_snapshot;
>> +const char * const mi_lttng_element_command_del_snapshot;
>> +const char * const mi_lttng_element_command_add_snapshot;
>> +const char * const mi_lttng_element_command_record_snapshot;
>>
>>   /* Strings related to command: version */
>>   const char * const mi_lttng_element_version;
>> @@ -78,6 +89,14 @@ const char * const mi_lttng_element_type_float;
>>   const char * const mi_lttng_element_type_string;
>>   const char * const mi_lttng_element_nowrite;
>>
>> +/* String related to a lttng_snashot */
>> +const char * const mi_lttng_element_snapshots;
>> +const char * const mi_lttng_element_snapshot_session_name;
>> +const char * const mi_lttng_element_snapshot_n_ptr;
>> +const char * const mi_lttng_element_snapshot_data_url;
>> +const char * const mi_lttng_element_snapshot_ctrl_url;
>> +const char * const mi_lttng_element_snapshot_max_size;
>> +
>>   /* Utility string function  */
>>   const char *mi_lttng_loglevel_string(int value);
>>   const char *mi_lttng_logleveltype_string(enum lttng_loglevel_type value);
>> @@ -507,4 +526,115 @@ int mi_lttng_pids_open(struct mi_writer *writer);
>>   int mi_lttng_pid(struct mi_writer *writer, pid_t pid , const char *cmdline,
>>   		int is_open);
>>
>> +/*
>> + * Machine interface of the snapshot list_output. It specify the session for which
>> + * we are listing snapshots, and it open a snapshots element to list a sequence
>> + * of snapshot.
>> + *
>> + * writer An instance of a machine interface writer.
>> + *
>> + * session_name: Snapshot output for session "session_name".
>> + *
>> + * Note: The client has to close the session and the snapshots elements after
>> + * having list every lttng_snapshot_output.
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_snapshot_output_session_name(struct mi_writer *writer,
>> +		const char *session_name);
>> +
>> +/*
>> + * Machine interface of the snapshot output.
>> + * The machine interface serialize the following attribute:
>> + * 	- id: ID of the snapshot output.
>> + * 	- name: Name of the output.
>> + * 	- data_url : Destination of the output.
>> + * 	- ctrl_url: Destination of the output.
>> + * 	- max_size: total size of all stream combined.
>> + *
>> + * writer An instance of a machine interface writer.
>> + *
>> + * output: iterator over a lttng_snapshot_output_list.
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_snapshot_list_output(struct mi_writer *writer,
>> +		struct lttng_snapshot_output *output);
>> +
>> +/*
>> + * Machine interface of the output of the command snapshot del output
>> + * when deleting a snapshot either by id or by name.
>> + * If the snapshot was founded and successfully deleted using its id,
>> + * we return the id of the snapshot and the current session name on which it
>> + * was attached.
>> + *
>> + * Otherwise, We  do the same process with the name of the snapshot, if the
>> + * snapshot output id is undefined.
>> + *
>> + * writer An instance of a machine interface writer.
>> + *
>> + * id: ID of the snapshot output.
>> + *
>> + * name: Name of the snapshot.
>> + *
>> + * current_session_name: Session which the snapshot belong to.
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_snapshot_del_output(struct mi_writer *writer, int id,
>> +		const char *name, const char *current_session_name);
>> +
>> +/*
>> + * Machine interface of the output of the command snapshot add output
>> + * when adding a snapshot from a user URL.
>> + *
>> + * If the snapshot was successfully added, the machine interface list
>> + * these informations:
>> + * - id: ID of the newly add snapshot output.
>> + * - current_session_name: Name of the session to which the output was added.
>> + * - ctrl_url: Destination of the output.
>> + * - max_size: total size of all stream combined.
>> + *
>> + * writer An instance of a machine interface writer.
>> + *
>> + * current_session_name: Session which the snapshot belong to.
>> + *
>> + * n_ptr:
>> + *
>> + * output: iterator over a lttng_snapshot_output_list which contain the snapshot
>> + * output informations.
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_snapshot_add_output(struct mi_writer *writer,
>> +		const char *current_session_name, const char *n_ptr,
>> +		struct lttng_snapshot_output *output);
>> +
>> +/*
>> + * Machine interface of the output of the command snapshot record  from a URL (if given).
>> + *
>> + * If the snapshot is successfully record from a url, the machine interface
>> + * output the following informations:
>> + * - url: Destination of the output store in the snapshot.
>> + *
>> + * Otherwise, the machine interface output the data and ctrl url receive
>> + * from the command-line.
>> + *
>> + * writer An instance of a machine interface writer.
>> + *
>> + * current_session_name: Snapshot record for session "current_session_name".
>> + *
>> + * ctrl_url, data_url: Destination of the output receive from the command-line.
>> + *
>> + * Returns zero if the element's value could be written.
>> + * Negative values indicate an error.
>> + */
>> +int mi_lttng_snapshot_record(struct mi_writer *writer,
>> +		const char *current_session_name, const char *url,
>> +		const char *cmdline_ctrl_url, const char *cmdline_data_url);
>> +
>>   #endif /* _MI_LTTNG_H */
>> diff --git a/src/common/mi_lttng.xsd b/src/common/mi_lttng.xsd
>> index 6fc25c6..e47f4d4 100644
>> --- a/src/common/mi_lttng.xsd
>> +++ b/src/common/mi_lttng.xsd
>> @@ -248,6 +248,24 @@ THE SOFTWARE.
>>   		</xs:all>
>>   	</xs:complexType>
>>
>> +	<!-- Maps to struct lttng_snapshot_output -->
>> +	<xs:complexType name="snapshot_type">
>> +		<xs:all>
>> +			<xs:element name="id" type="uint32_type" minOccurs="0" />
>> +			<xs:element name="max_size" type="uint64_type" minOccurs="0" />
>> +			<xs:element name="name" type="name_type" minOccurs="0" />
>> +			<xs:element name="session_name" type="name_type" minOccurs="0" />
>> +			<xs:element name="ctrl_url" type="name_type" minOccurs="0"/>
>> +			<xs:element name="data_url" type="name_type" minOccurs="0"/>
>> +		</xs:all>
>> +	</xs:complexType>
>> +
>> +	<xs:complexType name="snapshots_type">
>> +		<xs:sequence>
>> +			<xs:element name="snapshot" type="snapshot_type" minOccurs="0" maxOccurs="unbounded" />
>> +		</xs:sequence>
>> +	</xs:complexType>
>> +
>>   	<xs:complexType name="channels_type">
>>   		<xs:sequence>
>>   			<xs:element name="channel" type="channel_type" minOccurs="0" maxOccurs="unbounded" />
>> @@ -263,6 +281,7 @@ THE SOFTWARE.
>>   			<xs:element name="live_timer_interval" type="uint32_type" />
>>   			<xs:element name="channels" type="channels_type" minOccurs="0" />
>>   			<xs:element name="domains" type="domains_type" minOccurs="0" />
>> +			<xs:element name="snapshots" type="snapshots_type" minOccurs="0" />
>>   		</xs:all>
>>   	</xs:complexType>
>>
>> @@ -293,10 +312,23 @@ THE SOFTWARE.
>>   		</xs:sequence>
>>   	</xs:complexType>
>>
>> +
>> +	<!-- Type of snapshot commands -->
>> +	<xs:simpleType name="snapshot_action_type">
>> +		<xs:restriction base="xs:string">
>> +			<xs:enumeration value="list-output"/>
>> +			<xs:enumeration value="del-output"/>
>> +			<xs:enumeration value="add-output"/>
>> +			<xs:enumeration value="record-output"/>
>> +		</xs:restriction>
>> +	</xs:simpleType>
>> +
>>   	<xs:complexType name="output_type">
>>   		<xs:choice>
>>   			<xs:element name="domains" type="domains_type" minOccurs="0" />
>> +			<xs:element name="session" type="session_type" minOccurs="0" />
>>   			<xs:element name="sessions" type="sessions_type" minOccurs="0" />
>> +			<xs:element name="snapshot" type="snapshot_type" minOccurs="0" />
>>   			<xs:element name="version" type="version_type" minOccurs="0" />
>>   		</xs:choice>
>>   	</xs:complexType>
>> @@ -305,6 +337,7 @@ THE SOFTWARE.
>>   	<xs:simpleType name="command_string_type">
>>   		<xs:restriction base="xs:string">
>>   			<xs:enumeration value="list" />
>> +			<xs:enumeration value="snapshot" />
>>   			<xs:enumeration value="version" />
>>   		</xs:restriction>
>>   	</xs:simpleType>
>> @@ -313,6 +346,7 @@ THE SOFTWARE.
>>   		<xs:complexType>
>>   			<xs:all>
>>   				<xs:element name="name" type="command_string_type" maxOccurs="1" />
>> +				<xs:element name="action" type="snapshot_action_type" minOccurs="0" />
>>   				<xs:element name="output" type="output_type" maxOccurs="1" />
>>   			</xs:all>
>>   		</xs:complexType>
>> --
>> 1.9.1
>>
>
>
>
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
>




More information about the lttng-dev mailing list