+ strncpy(ua_event->name, uevent->attr.name, sizeof(ua_event->name));
+ ua_event->name[sizeof(ua_event->name) - 1] = '\0';
+
+ /* Copy event attributes */
+ memcpy(&ua_event->attr, &uevent->attr, sizeof(ua_event->attr));
+
+ cds_lfht_for_each_entry(uevent->ctx, &iter, uctx, node) {
+ ua_ctx = alloc_ust_app_ctx(&uctx->ctx);
+ if (ua_ctx == NULL) {
+ continue;
+ }
+ hashtable_node_init(&ua_ctx->node,
+ (void *)((unsigned long) ua_ctx->ctx.ctx), sizeof(void *));
+ hashtable_add_unique(ua_event->ctx, &ua_ctx->node);
+ }
+}
+
+/*
+ * Copy data between an UST app channel and a LTT channel.
+ */
+static void shadow_copy_channel(struct ust_app_channel *ua_chan,
+ struct ltt_ust_channel *uchan)
+{
+ struct cds_lfht_iter iter;
+ struct cds_lfht_node *ua_event_node;
+ struct ltt_ust_event *uevent;
+ struct ltt_ust_context *uctx;
+ struct ust_app_event *ua_event;
+ struct ust_app_ctx *ua_ctx;
+
+ DBG2("Shadow copy of UST app channel %s", ua_chan->name);
+
+ strncpy(ua_chan->name, uchan->name, sizeof(ua_chan->name));
+ ua_chan->name[sizeof(ua_chan->name) - 1] = '\0';
+ /* Copy event attributes */
+ memcpy(&ua_chan->attr, &uchan->attr, sizeof(ua_chan->attr));
+
+ cds_lfht_for_each_entry(uchan->ctx, &iter, uctx, node) {
+ ua_ctx = alloc_ust_app_ctx(&uctx->ctx);
+ if (ua_ctx == NULL) {
+ continue;
+ }
+ hashtable_node_init(&ua_ctx->node,
+ (void *)((unsigned long) ua_ctx->ctx.ctx), sizeof(void *));
+ hashtable_add_unique(ua_chan->ctx, &ua_ctx->node);
+ }
+
+ /* Copy all events from ltt ust channel to ust app channel */
+ cds_lfht_for_each_entry(uchan->events, &iter, uevent, node) {
+ struct cds_lfht_iter uiter;
+
+ ua_event_node = hashtable_lookup(ua_chan->events,
+ (void *) uevent->attr.name, strlen(uevent->attr.name),
+ &uiter);
+ if (ua_event_node == NULL) {
+ DBG2("UST event %s not found on shadow copy channel",
+ uevent->attr.name);
+ ua_event = alloc_ust_app_event(uevent->attr.name, &uevent->attr);
+ if (ua_event == NULL) {
+ continue;
+ }
+ shadow_copy_event(ua_event, uevent);
+ hashtable_add_unique(ua_chan->events, &ua_event->node);
+ }
+ }
+
+ DBG3("Shadow copy channel done");
+}
+
+/*
+ * Copy data between a UST app session and a regular LTT session.
+ */
+static void shadow_copy_session(struct ust_app_session *ua_sess,
+ struct ltt_ust_session *usess,
+ struct ust_app *app)
+{
+ struct cds_lfht_node *ua_chan_node;
+ struct cds_lfht_iter iter;
+ struct ltt_ust_channel *uchan;
+ struct ust_app_channel *ua_chan;
+ time_t rawtime;
+ struct tm *timeinfo;
+ char datetime[16];
+ int ret;
+
+ /* Get date and time for unique app path */
+ time(&rawtime);
+ timeinfo = localtime(&rawtime);
+ strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
+
+ DBG2("Shadow copy of session handle %d", ua_sess->handle);
+
+ ua_sess->uid = usess->uid;
+
+ ret = snprintf(ua_sess->path, PATH_MAX,
+ "%s/%s-%d-%s",
+ usess->pathname, app->name, app->key.pid,
+ datetime);
+ if (ret < 0) {
+ PERROR("asprintf UST shadow copy session");
+ /* TODO: We cannot return an error from here.. */
+ assert(0);
+ }
+
+ /* TODO: support all UST domain */
+
+ /* Iterate over all channels in global domain. */
+ cds_lfht_for_each_entry(usess->domain_global.channels, &iter,
+ uchan, node) {
+ struct cds_lfht_iter uiter;
+
+ ua_chan_node = hashtable_lookup(ua_sess->channels,
+ (void *)uchan->name, strlen(uchan->name),
+ &uiter);
+ if (ua_chan_node != NULL) {
+ continue;
+ }
+
+ DBG2("Channel %s not found on shadow session copy, creating it",
+ uchan->name);
+ ua_chan = alloc_ust_app_channel(uchan->name, &uchan->attr);
+ if (ua_chan == NULL) {
+ /* malloc failed... continuing */
+ continue;
+ }
+
+ shadow_copy_channel(ua_chan, uchan);
+ hashtable_add_unique(ua_sess->channels, &ua_chan->node);
+ }
+}
+
+/*
+ * Lookup sesison wrapper.
+ */
+static
+void __lookup_session_by_app(struct ltt_ust_session *usess,
+ struct ust_app *app, struct cds_lfht_iter *iter)
+{
+ /* Get right UST app session from app */
+ (void) hashtable_lookup(app->sessions,
+ (void *) ((unsigned long) usess->uid), sizeof(void *),
+ iter);
+}
+
+/*
+ * Return ust app session from the app session hashtable using the UST session
+ * uid.
+ */
+static struct ust_app_session *lookup_session_by_app(
+ struct ltt_ust_session *usess, struct ust_app *app)
+{
+ struct cds_lfht_iter iter;
+ struct cds_lfht_node *node;
+
+ __lookup_session_by_app(usess, app, &iter);
+ node = hashtable_iter_get_node(&iter);
+ if (node == NULL) {
+ goto error;
+ }
+
+ return caa_container_of(node, struct ust_app_session, node);
+
+error:
+ return NULL;
+}
+
+/*
+ * Create a UST session onto the tracer of app and add it the session
+ * hashtable.
+ *
+ * Return ust app session or NULL on error.
+ */
+static struct ust_app_session *create_ust_app_session(
+ struct ltt_ust_session *usess, struct ust_app *app)
+{
+ int ret;
+ struct ust_app_session *ua_sess;
+
+ ua_sess = lookup_session_by_app(usess, app);
+ if (ua_sess == NULL) {
+ DBG2("UST app pid: %d session uid %d not found, creating it",
+ app->key.pid, usess->uid);
+ ua_sess = alloc_ust_app_session();
+ if (ua_sess == NULL) {
+ /* Only malloc can failed so something is really wrong */
+ goto error;
+ }
+ shadow_copy_session(ua_sess, usess, app);
+ }
+
+ if (ua_sess->handle == -1) {
+ ret = ustctl_create_session(app->key.sock);
+ if (ret < 0) {
+ ERR("Error creating session for app pid %d, sock %d",
+ app->key.pid, app->key.sock);
+ /* TODO: free() ua_sess */
+ goto error;
+ }
+
+ DBG2("UST app ustctl create session handle %d", ret);
+ ua_sess->handle = ret;
+
+ /* Add ust app session to app's HT */
+ hashtable_node_init(&ua_sess->node,
+ (void *)((unsigned long) ua_sess->uid), sizeof(void *));
+ hashtable_add_unique(app->sessions, &ua_sess->node);
+
+ DBG2("UST app session created successfully with handle %d", ret);
+ }
+
+ return ua_sess;
+
+error:
+ return NULL;
+}
+
+/*
+ * Create a context for the channel on the tracer.
+ */
+static
+int create_ust_app_channel_context(struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan, struct lttng_ust_context *uctx,
+ struct ust_app *app)
+{
+ int ret = 0;
+ struct cds_lfht_iter iter;
+ struct cds_lfht_node *node;
+ struct ust_app_ctx *ua_ctx;
+
+ DBG2("UST app adding context to channel %s", ua_chan->name);
+
+ node = hashtable_lookup(ua_chan->ctx, (void *)((unsigned long)uctx->ctx),
+ sizeof(void *), &iter);
+ if (node != NULL) {
+ ret = -EEXIST;
+ goto error;
+ }
+
+ ua_ctx = alloc_ust_app_ctx(uctx);
+ if (ua_ctx == NULL) {
+ /* malloc failed */
+ ret = -1;
+ goto error;
+ }
+
+ hashtable_node_init(&ua_ctx->node,
+ (void *)((unsigned long) ua_ctx->ctx.ctx), sizeof(void *));
+ hashtable_add_unique(ua_chan->ctx, &ua_ctx->node);
+
+ ret = create_ust_channel_context(ua_chan, ua_ctx, app);
+ if (ret < 0) {
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Create an UST context and enable it for the event on the tracer.
+ */
+static
+int create_ust_app_event_context(struct ust_app_session *ua_sess,
+ struct ust_app_event *ua_event, struct lttng_ust_context *uctx,
+ struct ust_app *app)
+{
+ int ret = 0;
+ struct cds_lfht_iter iter;
+ struct cds_lfht_node *node;
+ struct ust_app_ctx *ua_ctx;
+
+ DBG2("UST app adding context to event %s", ua_event->name);
+
+ node = hashtable_lookup(ua_event->ctx, (void *)((unsigned long)uctx->ctx),
+ sizeof(void *), &iter);
+ if (node != NULL) {
+ ret = -EEXIST;
+ goto error;
+ }
+
+ ua_ctx = alloc_ust_app_ctx(uctx);
+ if (ua_ctx == NULL) {
+ /* malloc failed */
+ ret = -1;
+ goto error;
+ }
+
+ hashtable_node_init(&ua_ctx->node,
+ (void *)((unsigned long) ua_ctx->ctx.ctx), sizeof(void *));
+ hashtable_add_unique(ua_event->ctx, &ua_ctx->node);
+
+ ret = create_ust_event_context(ua_event, ua_ctx, app);
+ if (ret < 0) {
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Enable on the tracer side a ust app event for the session and channel.
+ */
+static
+int enable_ust_app_event(struct ust_app_session *ua_sess,
+ struct ust_app_event *ua_event, struct ust_app *app)
+{
+ int ret;
+
+ ret = enable_ust_event(app, ua_sess, ua_event);
+ if (ret < 0) {
+ goto error;
+ }
+
+ ua_event->enabled = 1;
+
+error:
+ return ret;
+}
+
+/*
+ * Disable on the tracer side a ust app event for the session and channel.
+ */
+static int disable_ust_app_event(struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan, struct ust_app_event *ua_event,
+ struct ust_app *app)
+{
+ int ret;
+
+ ret = disable_ust_event(app, ua_sess, ua_event);
+ if (ret < 0) {
+ goto error;
+ }
+
+ ua_event->enabled = 0;
+
+error:
+ return ret;
+}
+
+/*
+ * Lookup ust app channel for session and disable it on the tracer side.
+ */
+static
+int disable_ust_app_channel(struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan, struct ust_app *app)
+{
+ int ret;
+
+ ret = disable_ust_channel(app, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+
+ ua_chan->enabled = 0;
+
+error:
+ return ret;
+}
+
+/*
+ * Lookup ust app channel for session and enable it on the tracer side.
+ */
+static int enable_ust_app_channel(struct ust_app_session *ua_sess,
+ struct ltt_ust_channel *uchan, struct ust_app *app)
+{
+ int ret = 0;
+ struct cds_lfht_iter iter;
+ struct cds_lfht_node *ua_chan_node;
+ struct ust_app_channel *ua_chan;
+
+ ua_chan_node = hashtable_lookup(ua_sess->channels,
+ (void *)uchan->name, strlen(uchan->name), &iter);
+ if (ua_chan_node == NULL) {
+ DBG2("Unable to find channel %s in ust session uid %u",
+ uchan->name, ua_sess->uid);
+ goto error;
+ }
+
+ ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+
+ ret = enable_ust_channel(app, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Create UST app channel and create it on the tracer.
+ */
+static struct ust_app_channel *create_ust_app_channel(
+ struct ust_app_session *ua_sess, struct ltt_ust_channel *uchan,
+ struct ust_app *app)
+{
+ int ret = 0;
+ struct cds_lfht_iter iter;
+ struct cds_lfht_node *ua_chan_node;
+ struct ust_app_channel *ua_chan;
+
+ /* Lookup channel in the ust app session */
+ ua_chan_node = hashtable_lookup(ua_sess->channels,
+ (void *)uchan->name, strlen(uchan->name), &iter);
+ if (ua_chan_node == NULL) {
+ DBG2("Unable to find channel %s in ust session uid %u",
+ uchan->name, ua_sess->uid);
+ ua_chan = alloc_ust_app_channel(uchan->name, &uchan->attr);
+ if (ua_chan == NULL) {
+ goto error;
+ }
+ shadow_copy_channel(ua_chan, uchan);
+
+ hashtable_add_unique(ua_sess->channels, &ua_chan->node);
+ } else {
+ ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+ }
+
+ ret = create_ust_channel(app, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+
+ return ua_chan;
+
+error:
+ return NULL;
+}
+
+/*
+ * Create UST app event and create it on the tracer side.
+ */
+static
+int create_ust_app_event(struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan, struct ltt_ust_event *uevent,
+ struct ust_app *app)
+{
+ int ret = 0;
+ struct cds_lfht_iter iter;
+ struct cds_lfht_node *ua_event_node;
+ struct ust_app_event *ua_event;
+
+ /* Get event node */
+ ua_event_node = hashtable_lookup(ua_chan->events,
+ (void *)uevent->attr.name, strlen(uevent->attr.name), &iter);
+ if (ua_event_node != NULL) {
+ ERR("UST app event %s already exist. Stopping creation.",
+ uevent->attr.name);
+ goto end;
+ }
+
+ /* Does not exist so create one */
+ ua_event = alloc_ust_app_event(uevent->attr.name, &uevent->attr);
+ if (ua_event == NULL) {
+ /* Only malloc can failed so something is really wrong */
+ ret = -ENOMEM;
+ goto error;
+ }
+ shadow_copy_event(ua_event, uevent);
+
+ /* Create it on the tracer side */
+ ret = create_ust_event(app, ua_sess, ua_chan, ua_event);
+ if (ret < 0) {
+ rcu_read_lock();
+ delete_ust_app_event(app->key.sock, ua_event);
+ rcu_read_unlock();
+ goto error;
+ }
+
+ ua_event->enabled = 1;
+
+ hashtable_add_unique(ua_chan->events, &ua_event->node);
+
+end:
+error:
+ return ret;
+}
+
+/*
+ * Create UST metadata and open it on the tracer side.
+ */
+static int create_ust_app_metadata(struct ust_app_session *ua_sess,
+ char *pathname, struct ust_app *app)
+{
+ int ret = 0;
+
+ if (ua_sess->metadata == NULL) {
+ /* Allocate UST metadata */
+ ua_sess->metadata = trace_ust_create_metadata(pathname);
+ if (ua_sess->metadata == NULL) {