X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=liblttng-ust-ctl%2Fustctl.c;h=c22f578536e873873a1b813efe8b311d39d74e29;hb=1584cac2fb5dea4531f529b73a62eaccb95da897;hp=aed40f26382ac94f4ad38ec26cea3a350774e9be;hpb=74d81a6cca2cd4a7718bba9368f382f9f2fbba84;p=lttng-ust.git diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index aed40f26..c22f5785 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,13 @@ #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, ®_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(); }