Fix: FD leak in liblttng-ust-ctl
[lttng-ust.git] / liblttng-ust-ctl / ustctl.c
index aed40f26382ac94f4ad38ec26cea3a350774e9be..c22f578536e873873a1b813efe8b311d39d74e29 100644 (file)
@@ -22,6 +22,7 @@
 #include <lttng/ust-abi.h>
 #include <lttng/ust-events.h>
 #include <sys/mman.h>
+#include <byteswap.h>
 
 #include <usterr-signal-safe.h>
 #include <ust-comm.h>
 
 #include "../libringbuffer/backend.h"
 #include "../libringbuffer/frontend.h"
+#include "../liblttng-ust/wait.h"
+
+/*
+ * Number of milliseconds to retry before failing metadata writes on
+ * buffer full condition. (10 seconds)
+ */
+#define LTTNG_METADATA_TIMEOUT_MSEC    10000
 
 /*
  * Channel representation within consumer.
@@ -38,6 +46,8 @@ struct ustctl_consumer_channel {
 
        /* initial attributes */
        struct ustctl_consumer_channel_attr attr;
+       int wait_fd;                            /* monitor close() */
+       int wakeup_fd;                          /* monitor close() */
 };
 
 /*
@@ -53,10 +63,14 @@ struct ustctl_consumer_stream {
 };
 
 extern void lttng_ring_buffer_client_overwrite_init(void);
+extern void lttng_ring_buffer_client_overwrite_rt_init(void);
 extern void lttng_ring_buffer_client_discard_init(void);
+extern void lttng_ring_buffer_client_discard_rt_init(void);
 extern void lttng_ring_buffer_metadata_client_init(void);
 extern void lttng_ring_buffer_client_overwrite_exit(void);
+extern void lttng_ring_buffer_client_overwrite_rt_exit(void);
 extern void lttng_ring_buffer_client_discard_exit(void);
+extern void lttng_ring_buffer_client_discard_rt_exit(void);
 extern void lttng_ring_buffer_metadata_client_exit(void);
 
 volatile enum ust_loglevel ust_loglevel;
@@ -87,6 +101,13 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data)
 
        switch (data->type) {
        case LTTNG_UST_OBJECT_TYPE_CHANNEL:
+               if (data->u.channel.wakeup_fd >= 0) {
+                       ret = close(data->u.channel.wakeup_fd);
+                       if (ret < 0) {
+                               ret = -errno;
+                               return ret;
+                       }
+               }
                free(data->u.channel.data);
                break;
        case LTTNG_UST_OBJECT_TYPE_STREAM:
@@ -105,6 +126,9 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data)
                        }
                }
                break;
+       case LTTNG_UST_OBJECT_TYPE_EVENT:
+       case LTTNG_UST_OBJECT_TYPE_CONTEXT:
+               break;
        default:
                assert(0);
        }
@@ -166,6 +190,7 @@ int ustctl_create_event(int sock, struct lttng_ust_event *ev,
        event_data = zmalloc(sizeof(*event_data));
        if (!event_data)
                return -ENOMEM;
+       event_data->type = LTTNG_UST_OBJECT_TYPE_EVENT;
        memset(&lum, 0, sizeof(lum));
        lum.handle = channel_data->handle;
        lum.cmd = LTTNG_UST_EVENT;
@@ -200,6 +225,7 @@ int ustctl_add_context(int sock, struct lttng_ust_context *ctx,
        context_data = zmalloc(sizeof(*context_data));
        if (!context_data)
                return -ENOMEM;
+       context_data->type = LTTNG_UST_OBJECT_TYPE_CONTEXT;
        memset(&lum, 0, sizeof(lum));
        lum.handle = obj_data->handle;
        lum.cmd = LTTNG_UST_CONTEXT;
@@ -209,8 +235,8 @@ int ustctl_add_context(int sock, struct lttng_ust_context *ctx,
                free(context_data);
                return ret;
        }
-       context_data->handle = lur.ret_val;
-       DBG("received context handle %u", context_data->handle);
+       context_data->handle = -1;
+       DBG("Context created successfully");
        *_context_data = context_data;
        return ret;
 }
@@ -239,8 +265,6 @@ int ustctl_set_filter(int sock, struct lttng_ust_filter_bytecode *bytecode,
        ret = ustcomm_send_unix_sock(sock, bytecode->data,
                                bytecode->len);
        if (ret < 0) {
-               if (ret == -ECONNRESET)
-                       fprintf(stderr, "remote end closed connection\n");
                return ret;
        }
        if (ret != bytecode->len)
@@ -458,6 +482,7 @@ int ustctl_send_channel(int sock,
                enum lttng_ust_chan_type type,
                void *data,
                uint64_t size,
+               int wakeup_fd,
                int send_fd_only)
 {
        ssize_t len;
@@ -491,6 +516,14 @@ int ustctl_send_channel(int sock,
                        return -EIO;
        }
 
+       /* Send wakeup fd */
+       len = ustcomm_send_fds_unix_sock(sock, &wakeup_fd, 1);
+       if (len <= 0) {
+               if (len < 0)
+                       return len;
+               else
+                       return -EIO;
+       }
        return 0;
 }
 
@@ -558,6 +591,7 @@ int ustctl_recv_channel_from_consumer(int sock,
 {
        struct lttng_ust_object_data *channel_data;
        ssize_t len;
+       int wakeup_fd;
        int ret;
 
        channel_data = zmalloc(sizeof(*channel_data));
@@ -566,6 +600,7 @@ int ustctl_recv_channel_from_consumer(int sock,
                goto error_alloc;
        }
        channel_data->type = LTTNG_UST_OBJECT_TYPE_CHANNEL;
+       channel_data->handle = -1;
 
        /* recv mmap size */
        len = ustcomm_recv_unix_sock(sock, &channel_data->size,
@@ -604,7 +639,18 @@ int ustctl_recv_channel_from_consumer(int sock,
                        ret = -EINVAL;
                goto error_recv_data;
        }
-
+       /* recv wakeup fd */
+       len = ustcomm_recv_fds_unix_sock(sock, &wakeup_fd, 1);
+       if (len <= 0) {
+               if (len < 0) {
+                       ret = len;
+                       goto error_recv_data;
+               } else {
+                       ret = -EIO;
+                       goto error_recv_data;
+               }
+       }
+       channel_data->u.channel.wakeup_fd = wakeup_fd;
        *_channel_data = channel_data;
        return 0;
 
@@ -704,14 +750,13 @@ int ustctl_send_channel_to_ust(int sock, int session_handle,
                        channel_data->u.channel.type,
                        channel_data->u.channel.data,
                        channel_data->size,
+                       channel_data->u.channel.wakeup_fd,
                        1);
        if (ret)
                return ret;
        ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd);
        if (!ret) {
-               if (lur.ret_val >= 0) {
-                       channel_data->handle = lur.ret_val;
-               }
+               channel_data->handle = lur.ret_val;
        }
        return ret;
 }
@@ -746,6 +791,119 @@ int ustctl_send_stream_to_ust(int sock,
        return ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd);
 }
 
+int ustctl_duplicate_ust_object_data(struct lttng_ust_object_data **dest,
+                struct lttng_ust_object_data *src)
+{
+       struct lttng_ust_object_data *obj;
+       int ret;
+
+       if (src->handle != -1) {
+               ret = -EINVAL;
+               goto error;
+       }
+
+       obj = zmalloc(sizeof(*obj));
+       if (!obj) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       obj->type = src->type;
+       obj->handle = src->handle;
+       obj->size = src->size;
+
+       switch (obj->type) {
+       case LTTNG_UST_OBJECT_TYPE_CHANNEL:
+       {
+               obj->u.channel.type = src->u.channel.type;
+               if (src->u.channel.wakeup_fd >= 0) {
+                       obj->u.channel.wakeup_fd =
+                               dup(src->u.channel.wakeup_fd);
+                       if (obj->u.channel.wakeup_fd < 0) {
+                               ret = errno;
+                               goto chan_error_wakeup_fd;
+                       }
+               } else {
+                       obj->u.channel.wakeup_fd =
+                               src->u.channel.wakeup_fd;
+               }
+               obj->u.channel.data = zmalloc(obj->size);
+               if (!obj->u.channel.data) {
+                       ret = -ENOMEM;
+                       goto chan_error_alloc;
+               }
+               memcpy(obj->u.channel.data, src->u.channel.data, obj->size);
+               break;
+
+       chan_error_alloc:
+               if (src->u.channel.wakeup_fd >= 0) {
+                       int closeret;
+
+                       closeret = close(obj->u.channel.wakeup_fd);
+                       if (closeret) {
+                               PERROR("close");
+                       }
+               }
+       chan_error_wakeup_fd:
+               goto error_type;
+
+       }
+
+       case LTTNG_UST_OBJECT_TYPE_STREAM:
+       {
+               obj->u.stream.stream_nr = src->u.stream.stream_nr;
+               if (src->u.stream.wakeup_fd >= 0) {
+                       obj->u.stream.wakeup_fd =
+                               dup(src->u.stream.wakeup_fd);
+                       if (obj->u.stream.wakeup_fd < 0) {
+                               ret = errno;
+                               goto stream_error_wakeup_fd;
+                       }
+               } else {
+                       obj->u.stream.wakeup_fd =
+                               src->u.stream.wakeup_fd;
+               }
+
+               if (src->u.stream.shm_fd >= 0) {
+                       obj->u.stream.shm_fd =
+                               dup(src->u.stream.shm_fd);
+                       if (obj->u.stream.shm_fd < 0) {
+                               ret = errno;
+                               goto stream_error_shm_fd;
+                       }
+               } else {
+                       obj->u.stream.shm_fd =
+                               src->u.stream.shm_fd;
+               }
+               break;
+
+       stream_error_shm_fd:
+               if (src->u.stream.wakeup_fd >= 0) {
+                       int closeret;
+
+                       closeret = close(obj->u.stream.wakeup_fd);
+                       if (closeret) {
+                               PERROR("close");
+                       }
+               }
+       stream_error_wakeup_fd:
+               goto error_type;
+       }
+
+       default:
+               ret = -EINVAL;
+               goto error_type;
+       }
+
+       *dest = obj;
+       return 0;
+
+error_type:
+       free(obj);
+error:
+       return ret;
+}
+
 
 /* Buffer operations */
 
@@ -759,8 +917,19 @@ struct ustctl_consumer_channel *
        switch (attr->type) {
        case LTTNG_UST_CHAN_PER_CPU:
                if (attr->output == LTTNG_UST_MMAP) {
-                       transport_name = attr->overwrite ?
-                               "relay-overwrite-mmap" : "relay-discard-mmap";
+                       if (attr->overwrite) {
+                               if (attr->read_timer_interval == 0) {
+                                       transport_name = "relay-overwrite-mmap";
+                               } else {
+                                       transport_name = "relay-overwrite-rt-mmap";
+                               }
+                       } else {
+                               if (attr->read_timer_interval == 0) {
+                                       transport_name = "relay-discard-mmap";
+                               } else {
+                                       transport_name = "relay-discard-rt-mmap";
+                               }
+                       }
                } else {
                        return NULL;
                }
@@ -779,7 +948,7 @@ struct ustctl_consumer_channel *
        transport = lttng_transport_find(transport_name);
        if (!transport) {
                DBG("LTTng transport %s not found\n",
-                      transport_name);
+                       transport_name);
                return NULL;
        }
 
@@ -788,15 +957,17 @@ struct ustctl_consumer_channel *
                return NULL;
 
        chan->chan = transport->ops.channel_create(transport_name, NULL,
-                        attr->subbuf_size, attr->num_subbuf,
+                       attr->subbuf_size, attr->num_subbuf,
                        attr->switch_timer_interval,
-                        attr->read_timer_interval,
-                       attr->uuid);
+                       attr->read_timer_interval,
+                       attr->uuid, attr->chan_id);
        if (!chan->chan) {
                goto chan_error;
        }
        chan->chan->ops = &transport->ops;
        memcpy(&chan->attr, attr, sizeof(chan->attr));
+       chan->wait_fd = ustctl_channel_get_wait_fd(chan);
+       chan->wakeup_fd = ustctl_channel_get_wakeup_fd(chan);
        return chan;
 
 chan_error:
@@ -806,6 +977,8 @@ chan_error:
 
 void ustctl_destroy_channel(struct ustctl_consumer_channel *chan)
 {
+       (void) ustctl_channel_close_wait_fd(chan);
+       (void) ustctl_channel_close_wakeup_fd(chan);
        chan->chan->ops->channel_destroy(chan->chan);
        free(chan);
 }
@@ -822,6 +995,7 @@ int ustctl_send_channel_to_sessiond(int sock,
                        channel->attr.type,
                        table->objects[0].memory_map,
                        table->objects[0].memory_map_size,
+                       channel->wakeup_fd,
                        0);
 }
 
@@ -838,12 +1012,82 @@ int ustctl_send_stream_to_sessiond(int sock,
                        0);
 }
 
+int ustctl_write_metadata_to_channel(
+               struct ustctl_consumer_channel *channel,
+               const char *metadata_str,       /* NOT null-terminated */
+               size_t len)                     /* metadata length */
+{
+       struct lttng_ust_lib_ring_buffer_ctx ctx;
+       struct lttng_channel *chan = channel->chan;
+       const char *str = metadata_str;
+       int ret = 0, waitret;
+       size_t reserve_len, pos;
+
+       for (pos = 0; pos < len; pos += reserve_len) {
+               reserve_len = min_t(size_t,
+                               chan->ops->packet_avail_size(chan->chan, chan->handle),
+                               len - pos);
+               lib_ring_buffer_ctx_init(&ctx, chan->chan, NULL, reserve_len,
+                                        sizeof(char), -1, chan->handle);
+               /*
+                * We don't care about metadata buffer's records lost
+                * count, because we always retry here. Report error if
+                * we need to bail out after timeout or being
+                * interrupted.
+                */
+               waitret = wait_cond_interruptible_timeout(
+                       ({
+                               ret = chan->ops->event_reserve(&ctx, 0);
+                               ret != -ENOBUFS || !ret;
+                       }),
+                       LTTNG_METADATA_TIMEOUT_MSEC);
+               if (waitret == -ETIMEDOUT || waitret == -EINTR || ret) {
+                       DBG("LTTng: Failure to write metadata to buffers (%s)\n",
+                               waitret == -EINTR ? "interrupted" :
+                                       (ret == -ENOBUFS ? "timeout" : "I/O error"));
+                       if (waitret == -EINTR)
+                               ret = waitret;
+                       goto end;
+               }
+               chan->ops->event_write(&ctx, &str[pos], reserve_len);
+               chan->ops->event_commit(&ctx);
+       }
+end:
+       return ret;
+}
+
+int ustctl_channel_close_wait_fd(struct ustctl_consumer_channel *consumer_chan)
+{
+       struct channel *chan;
+       int ret;
+
+       chan = consumer_chan->chan->chan;
+       ret = ring_buffer_channel_close_wait_fd(&chan->backend.config,
+                       chan, chan->handle);
+       if (!ret)
+               consumer_chan->wait_fd = -1;
+       return ret;
+}
+
+int ustctl_channel_close_wakeup_fd(struct ustctl_consumer_channel *consumer_chan)
+{
+       struct channel *chan;
+       int ret;
+
+       chan = consumer_chan->chan->chan;
+       ret = ring_buffer_channel_close_wakeup_fd(&chan->backend.config,
+                       chan, chan->handle);
+       if (!ret)
+               consumer_chan->wakeup_fd = -1;
+       return ret;
+}
+
 int ustctl_stream_close_wait_fd(struct ustctl_consumer_stream *stream)
 {
        struct channel *chan;
 
        chan = stream->chan->chan->chan;
-       return ring_buffer_close_wait_fd(&chan->backend.config,
+       return ring_buffer_stream_close_wait_fd(&chan->backend.config,
                        chan, stream->handle, stream->cpu);
 }
 
@@ -852,7 +1096,7 @@ int ustctl_stream_close_wakeup_fd(struct ustctl_consumer_stream *stream)
        struct channel *chan;
 
        chan = stream->chan->chan->chan;
-       return ring_buffer_close_wakeup_fd(&chan->backend.config,
+       return ring_buffer_stream_close_wakeup_fd(&chan->backend.config,
                        chan, stream->handle, stream->cpu);
 }
 
@@ -909,11 +1153,29 @@ void ustctl_destroy_stream(struct ustctl_consumer_stream *stream)
        assert(stream);
        buf = stream->buf;
        consumer_chan = stream->chan;
+       (void) ustctl_stream_close_wait_fd(stream);
+       (void) ustctl_stream_close_wakeup_fd(stream);
        lib_ring_buffer_release_read(buf, consumer_chan->chan->handle);
        free(stream);
 }
 
-int ustctl_get_wait_fd(struct ustctl_consumer_stream *stream)
+int ustctl_channel_get_wait_fd(struct ustctl_consumer_channel *chan)
+{
+       if (!chan)
+               return -EINVAL;
+       return shm_get_wait_fd(chan->chan->handle,
+               &chan->chan->handle->chan._ref);
+}
+
+int ustctl_channel_get_wakeup_fd(struct ustctl_consumer_channel *chan)
+{
+       if (!chan)
+               return -EINVAL;
+       return shm_get_wakeup_fd(chan->chan->handle,
+               &chan->chan->handle->chan._ref);
+}
+
+int ustctl_stream_get_wait_fd(struct ustctl_consumer_stream *stream)
 {
        struct lttng_ust_lib_ring_buffer *buf;
        struct ustctl_consumer_channel *consumer_chan;
@@ -925,7 +1187,7 @@ int ustctl_get_wait_fd(struct ustctl_consumer_stream *stream)
        return shm_get_wait_fd(consumer_chan->chan->handle, &buf->self._ref);
 }
 
-int ustctl_get_wakeup_fd(struct ustctl_consumer_stream *stream)
+int ustctl_stream_get_wakeup_fd(struct ustctl_consumer_stream *stream)
 {
        struct lttng_ust_lib_ring_buffer *buf;
        struct ustctl_consumer_channel *consumer_chan;
@@ -1011,7 +1273,7 @@ int ustctl_get_mmap_read_offset(struct ustctl_consumer_stream *stream,
        if (chan->backend.config.output != RING_BUFFER_MMAP)
                return -EINVAL;
        sb_bindex = subbuffer_id_get_index(&chan->backend.config,
-                                          buf->backend.buf_rsb.id);
+                                       buf->backend.buf_rsb.id);
        *off = shmp(consumer_chan->chan->handle,
                shmp_index(consumer_chan->chan->handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset;
        return 0;
@@ -1169,19 +1431,362 @@ void ustctl_flush_buffer(struct ustctl_consumer_stream *stream,
                consumer_chan->chan->handle);
 }
 
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int ustctl_recv_reg_msg(int sock,
+       enum ustctl_socket_type *type,
+       uint32_t *major,
+       uint32_t *minor,
+       uint32_t *pid,
+       uint32_t *ppid,
+       uint32_t *uid,
+       uint32_t *gid,
+       uint32_t *bits_per_long,
+       uint32_t *uint8_t_alignment,
+       uint32_t *uint16_t_alignment,
+       uint32_t *uint32_t_alignment,
+       uint32_t *uint64_t_alignment,
+       uint32_t *long_alignment,
+       int *byte_order,
+       char *name)
+{
+       ssize_t len;
+       struct ustctl_reg_msg reg_msg;
+
+       len = ustcomm_recv_unix_sock(sock, &reg_msg, sizeof(reg_msg));
+       if (len > 0 && len != sizeof(reg_msg))
+               return -EIO;
+       if (len == 0)
+               return -EPIPE;
+       if (len < 0)
+               return len;
+
+       if (reg_msg.magic == LTTNG_UST_COMM_MAGIC) {
+               *byte_order = BYTE_ORDER == BIG_ENDIAN ?
+                               BIG_ENDIAN : LITTLE_ENDIAN;
+       } else if (reg_msg.magic == bswap_32(LTTNG_UST_COMM_MAGIC)) {
+               *byte_order = BYTE_ORDER == BIG_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN;
+       } else {
+               return -LTTNG_UST_ERR_INVAL_MAGIC;
+       }
+       switch (reg_msg.socket_type) {
+       case 0: *type = USTCTL_SOCKET_CMD;
+               break;
+       case 1: *type = USTCTL_SOCKET_NOTIFY;
+               break;
+       default:
+               return -LTTNG_UST_ERR_INVAL_SOCKET_TYPE;
+       }
+       *major = reg_msg.major;
+       *minor = reg_msg.minor;
+       *pid = reg_msg.pid;
+       *ppid = reg_msg.ppid;
+       *uid = reg_msg.uid;
+       *gid = reg_msg.gid;
+       *bits_per_long = reg_msg.bits_per_long;
+       *uint8_t_alignment = reg_msg.uint8_t_alignment;
+       *uint16_t_alignment = reg_msg.uint16_t_alignment;
+       *uint32_t_alignment = reg_msg.uint32_t_alignment;
+       *uint64_t_alignment = reg_msg.uint64_t_alignment;
+       *long_alignment = reg_msg.long_alignment;
+       memcpy(name, reg_msg.name, LTTNG_UST_ABI_PROCNAME_LEN);
+       if (reg_msg.major != LTTNG_UST_ABI_MAJOR_VERSION) {
+               return -LTTNG_UST_ERR_UNSUP_MAJOR;
+       }
+
+       return 0;
+}
+
+int ustctl_recv_notify(int sock, enum ustctl_notify_cmd *notify_cmd)
+{
+       struct ustcomm_notify_hdr header;
+       ssize_t len;
+
+       len = ustcomm_recv_unix_sock(sock, &header, sizeof(header));
+       if (len > 0 && len != sizeof(header))
+               return -EIO;
+       if (len == 0)
+               return -EPIPE;
+       if (len < 0)
+               return len;
+       switch (header.notify_cmd) {
+       case 0:
+               *notify_cmd = USTCTL_NOTIFY_CMD_EVENT;
+               break;
+       case 1:
+               *notify_cmd = USTCTL_NOTIFY_CMD_CHANNEL;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int ustctl_recv_register_event(int sock,
+       int *session_objd,
+       int *channel_objd,
+       char *event_name,
+       int *loglevel,
+       char **signature,
+       size_t *nr_fields,
+       struct ustctl_field **fields,
+       char **model_emf_uri)
+{
+       ssize_t len;
+       struct ustcomm_notify_event_msg msg;
+       size_t signature_len, fields_len, model_emf_uri_len;
+       char *a_sign = NULL, *a_model_emf_uri = NULL;
+       struct ustctl_field *a_fields = NULL;
+
+       len = ustcomm_recv_unix_sock(sock, &msg, sizeof(msg));
+       if (len > 0 && len != sizeof(msg))
+               return -EIO;
+       if (len == 0)
+               return -EPIPE;
+       if (len < 0)
+               return len;
+
+       *session_objd = msg.session_objd;
+       *channel_objd = msg.channel_objd;
+       strncpy(event_name, msg.event_name, LTTNG_UST_SYM_NAME_LEN);
+       event_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+       *loglevel = msg.loglevel;
+       signature_len = msg.signature_len;
+       fields_len = msg.fields_len;
+
+       if (fields_len % sizeof(*a_fields) != 0) {
+               return -EINVAL;
+       }
+
+       model_emf_uri_len = msg.model_emf_uri_len;
+
+       /* recv signature. contains at least \0. */
+       a_sign = zmalloc(signature_len);
+       if (!a_sign)
+               return -ENOMEM;
+       len = ustcomm_recv_unix_sock(sock, a_sign, signature_len);
+       if (len > 0 && len != signature_len) {
+               len = -EIO;
+               goto signature_error;
+       }
+       if (len == 0) {
+               len = -EPIPE;
+               goto signature_error;
+       }
+       if (len < 0) {
+               goto signature_error;
+       }
+       /* Enforce end of string */
+       a_sign[signature_len - 1] = '\0';
+
+       /* recv fields */
+       if (fields_len) {
+               a_fields = zmalloc(fields_len);
+               if (!a_fields) {
+                       len = -ENOMEM;
+                       goto signature_error;
+               }
+               len = ustcomm_recv_unix_sock(sock, a_fields, fields_len);
+               if (len > 0 && len != fields_len) {
+                       len = -EIO;
+                       goto fields_error;
+               }
+               if (len == 0) {
+                       len = -EPIPE;
+                       goto fields_error;
+               }
+               if (len < 0) {
+                       goto fields_error;
+               }
+       }
+
+       if (model_emf_uri_len) {
+               /* recv model_emf_uri_len */
+               a_model_emf_uri = zmalloc(model_emf_uri_len);
+               if (!a_model_emf_uri) {
+                       len = -ENOMEM;
+                       goto fields_error;
+               }
+               len = ustcomm_recv_unix_sock(sock, a_model_emf_uri,
+                               model_emf_uri_len);
+               if (len > 0 && len != model_emf_uri_len) {
+                       len = -EIO;
+                       goto model_error;
+               }
+               if (len == 0) {
+                       len = -EPIPE;
+                       goto model_error;
+               }
+               if (len < 0) {
+                       goto model_error;
+               }
+               /* Enforce end of string */
+               a_model_emf_uri[model_emf_uri_len - 1] = '\0';
+       }
+
+       *signature = a_sign;
+       *nr_fields = fields_len / sizeof(*a_fields);
+       *fields = a_fields;
+       *model_emf_uri = a_model_emf_uri;
+
+       return 0;
+
+model_error:
+       free(a_model_emf_uri);
+fields_error:
+       free(a_fields);
+signature_error:
+       free(a_sign);
+       return len;
+}
+
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int ustctl_reply_register_event(int sock,
+       uint32_t id,
+       int ret_code)
+{
+       ssize_t len;
+       struct {
+               struct ustcomm_notify_hdr header;
+               struct ustcomm_notify_event_reply r;
+       } reply;
+
+       memset(&reply, 0, sizeof(reply));
+       reply.header.notify_cmd = USTCTL_NOTIFY_CMD_EVENT;
+       reply.r.ret_code = ret_code;
+       reply.r.event_id = id;
+       len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply));
+       if (len > 0 && len != sizeof(reply))
+               return -EIO;
+       if (len < 0)
+               return len;
+       return 0;
+}
+
+/*
+ * Returns 0 on success, negative UST or system error value on error.
+ */
+int ustctl_recv_register_channel(int sock,
+       int *session_objd,              /* session descriptor (output) */
+       int *channel_objd,              /* channel descriptor (output) */
+       size_t *nr_fields,
+       struct ustctl_field **fields)
+{
+       ssize_t len;
+       struct ustcomm_notify_channel_msg msg;
+       size_t fields_len;
+       struct ustctl_field *a_fields;
+
+       len = ustcomm_recv_unix_sock(sock, &msg, sizeof(msg));
+       if (len > 0 && len != sizeof(msg))
+               return -EIO;
+       if (len == 0)
+               return -EPIPE;
+       if (len < 0)
+               return len;
+
+       *session_objd = msg.session_objd;
+       *channel_objd = msg.channel_objd;
+       fields_len = msg.ctx_fields_len;
+
+       if (fields_len % sizeof(*a_fields) != 0) {
+               return -EINVAL;
+       }
+
+       /* recv fields */
+       if (fields_len) {
+               a_fields = zmalloc(fields_len);
+               if (!a_fields) {
+                       len = -ENOMEM;
+                       goto alloc_error;
+               }
+               len = ustcomm_recv_unix_sock(sock, a_fields, fields_len);
+               if (len > 0 && len != fields_len) {
+                       len = -EIO;
+                       goto fields_error;
+               }
+               if (len == 0) {
+                       len = -EPIPE;
+                       goto fields_error;
+               }
+               if (len < 0) {
+                       goto fields_error;
+               }
+               *fields = a_fields;
+       } else {
+               *fields = NULL;
+       }
+       *nr_fields = fields_len / sizeof(*a_fields);
+       return 0;
+
+fields_error:
+       free(a_fields);
+alloc_error:
+       return len;
+}
+
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int ustctl_reply_register_channel(int sock,
+       uint32_t chan_id,
+       enum ustctl_channel_header header_type,
+       int ret_code)
+{
+       ssize_t len;
+       struct {
+               struct ustcomm_notify_hdr header;
+               struct ustcomm_notify_channel_reply r;
+       } reply;
+
+       memset(&reply, 0, sizeof(reply));
+       reply.header.notify_cmd = USTCTL_NOTIFY_CMD_CHANNEL;
+       reply.r.ret_code = ret_code;
+       reply.r.chan_id = chan_id;
+       switch (header_type) {
+       case USTCTL_CHANNEL_HEADER_COMPACT:
+               reply.r.header_type = 1;
+               break;
+       case USTCTL_CHANNEL_HEADER_LARGE:
+               reply.r.header_type = 2;
+               break;
+       default:
+               reply.r.header_type = 0;
+               break;
+       }
+       len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply));
+       if (len > 0 && len != sizeof(reply))
+               return -EIO;
+       if (len < 0)
+               return len;
+       return 0;
+}
+
 static __attribute__((constructor))
 void ustctl_init(void)
 {
        init_usterr();
        lttng_ring_buffer_metadata_client_init();
        lttng_ring_buffer_client_overwrite_init();
+       lttng_ring_buffer_client_overwrite_rt_init();
        lttng_ring_buffer_client_discard_init();
+       lttng_ring_buffer_client_discard_rt_init();
+       lib_ringbuffer_signal_init();
 }
 
 static __attribute__((destructor))
 void ustctl_exit(void)
 {
+       lttng_ring_buffer_client_discard_rt_exit();
        lttng_ring_buffer_client_discard_exit();
+       lttng_ring_buffer_client_overwrite_rt_exit();
        lttng_ring_buffer_client_overwrite_exit();
        lttng_ring_buffer_metadata_client_exit();
 }
This page took 0.032984 seconds and 4 git commands to generate.