X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust-ctl%2Fustctl.c;h=c9e930d045916b82eb7234ca80c07532aab0126e;hb=616d3093e1c34557aca7e9f6149338f43cf91886;hp=83c60034edd713fca7e048b40e572987993353b8;hpb=b728d87e617189fe9898a9492a559ecf949d2348;p=lttng-ust.git diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index 83c60034..c9e930d0 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -2,27 +2,28 @@ * Copyright (C) 2011 - Julien Desfossez * Mathieu Desnoyers * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; only version 2 - * of the License. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License only. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#define _GNU_SOURCE #include #include #include -#include #include #include + +#include #include #include "../libringbuffer/backend.h" @@ -30,37 +31,85 @@ volatile enum ust_loglevel ust_loglevel; +static int dummy_pipe[2]; + +static +void __attribute__((constructor)) setup_dummy_pipe(void) +{ + pipe(dummy_pipe); + /* Only dummy_pipe[0] is used */ + close(dummy_pipe[1]); + /* FIXME: Handle pipe() failure */ +} + +static +inline int get_dummy_fd(void) +{ + return dup(dummy_pipe[0]); +} + static void init_object(struct lttng_ust_object_data *data) { data->handle = -1; data->shm_fd = -1; + data->shm_path = NULL; data->wait_fd = -1; + data->wait_pipe_path = NULL; data->memory_map_size = 0; } -/* - * If sock is negative, it means we don't have to notify the other side - * (e.g. application has already vanished). - */ -void ustctl_release_object(int sock, struct lttng_ust_object_data *data) +int ustctl_release_handle(int sock, int handle) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; int ret; - if (data->shm_fd >= 0) - close(data->shm_fd); - if (data->wait_fd >= 0) - close(data->wait_fd); if (sock >= 0) { memset(&lum, 0, sizeof(lum)); - lum.handle = data->handle; + lum.handle = handle; lum.cmd = LTTNG_UST_RELEASE; ret = ustcomm_send_app_cmd(sock, &lum, &lur); - assert(!ret); + if (ret < 0) { + return ret; + } + } + return 0; +} +/* + * If sock is negative, it means we don't have to notify the other side + * (e.g. application has already vanished). + */ +int ustctl_release_object(int sock, struct lttng_ust_object_data *data) +{ + int ret; + + if (!data) + return -EINVAL; + + if (data->shm_fd >= 0) { + ret = close(data->shm_fd); + if (ret < 0) { + return ret; + } + } + + if (data->shm_path) { + free(data->shm_path); + } + + if (data->wait_fd >= 0) { + ret = close(data->wait_fd); + if (ret < 0) { + return ret; + } + } + + if (data->wait_pipe_path) { + free(data->wait_pipe_path); } - free(data); + + return ustctl_release_handle(sock, data->handle); } /* @@ -118,7 +167,11 @@ int ustctl_open_metadata(int sock, int session_handle, struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; struct lttng_ust_object_data *metadata_data; - int ret; + int ret, err = 0; + char *shm_path, *wait_pipe_path; + + if (!chops || !_metadata_data) + return -EINVAL; metadata_data = malloc(sizeof(*metadata_data)); if (!metadata_data) @@ -146,24 +199,74 @@ int ustctl_open_metadata(int sock, int session_handle, metadata_data->handle = lur.ret_val; DBG("received metadata handle %u", metadata_data->handle); metadata_data->memory_map_size = lur.u.channel.memory_map_size; - /* get shm fd */ - ret = ustcomm_recv_fd(sock); - if (ret < 0) - goto error; - metadata_data->shm_fd = ret; - /* get wait fd */ - ret = ustcomm_recv_fd(sock); - if (ret < 0) + /* get shm path */ + shm_path = ustcomm_recv_string(sock); + if (!shm_path) { + err = 1; + } else { + DBG("Received shm path: %s\n", shm_path); + metadata_data->shm_fd = get_dummy_fd(); + metadata_data->shm_path = shm_path; + } + + /* + * We need to get the second FD even if the first fails, because + * libust expects us to read the two FDs. + */ + + /* get wait pipe path */ + wait_pipe_path = ustcomm_recv_string(sock); + if (!wait_pipe_path) { + free(shm_path); + err = 1; + } else { + DBG("Received wait pipe path: %s\n", wait_pipe_path); + metadata_data->wait_fd = get_dummy_fd(); + metadata_data->wait_pipe_path = wait_pipe_path; + } + + + if (err) goto error; - metadata_data->wait_fd = ret; *_metadata_data = metadata_data; return 0; error: - ustctl_release_object(sock, metadata_data); + (void) ustctl_release_object(sock, metadata_data); + free(metadata_data); return -EINVAL; } +int ustctl_open_wait_pipe(int sock, + struct lttng_ust_object_data *channel_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + if (!channel_data) + return -EINVAL; + + /* Create metadata channel */ + memset(&lum, 0, sizeof(lum)); + lum.handle = channel_data->handle; + lum.cmd = LTTNG_UST_STREAM_PIPE; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + + if (ret) { + goto error; + } + if (lur.ret_code != USTCOMM_OK) { + ret = lur.ret_code; + goto error; + } + + return 0; + +error: + return ret; +} + int ustctl_create_channel(int sock, int session_handle, struct lttng_ust_channel_attr *chops, struct lttng_ust_object_data **_channel_data) @@ -171,7 +274,11 @@ int ustctl_create_channel(int sock, int session_handle, struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; struct lttng_ust_object_data *channel_data; - int ret; + int ret, err = 0; + char *shm_path, *wait_pipe_path; + + if (!chops || !_channel_data) + return -EINVAL; channel_data = malloc(sizeof(*channel_data)); if (!channel_data) @@ -199,21 +306,39 @@ int ustctl_create_channel(int sock, int session_handle, channel_data->handle = lur.ret_val; DBG("received channel handle %u", channel_data->handle); channel_data->memory_map_size = lur.u.channel.memory_map_size; - /* get shm fd */ - ret = ustcomm_recv_fd(sock); - if (ret < 0) - goto error; - channel_data->shm_fd = ret; - /* get wait fd */ - ret = ustcomm_recv_fd(sock); - if (ret < 0) + /* get shm path */ + shm_path = ustcomm_recv_string(sock); + if (!shm_path) { + err = 1; + } else { + DBG("Received shm path: %s\n", shm_path); + channel_data->shm_fd = get_dummy_fd(); + channel_data->shm_path = shm_path; + } + + /* + * We need to get the second FD even if the first fails, because + * libust expects us to read the two FDs. + */ + /* get wait pipe path */ + wait_pipe_path = ustcomm_recv_string(sock); + if (!wait_pipe_path) { + free(shm_path); + err = 1; + } else { + DBG("Received wait pipe path: %s\n", wait_pipe_path); + channel_data->wait_fd = get_dummy_fd(); + channel_data->wait_pipe_path = wait_pipe_path; + } + + if (err) goto error; - channel_data->wait_fd = ret; *_channel_data = channel_data; return 0; error: - ustctl_release_object(sock, channel_data); + (void) ustctl_release_object(sock, channel_data); + free(channel_data); return -EINVAL; } @@ -228,7 +353,11 @@ int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data, struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; struct lttng_ust_object_data *stream_data; - int ret, fd; + int ret, err = 0; + char *shm_path, *wait_pipe_path; + + if (!channel_data || !_stream_data) + return -EINVAL; stream_data = malloc(sizeof(*stream_data)); if (!stream_data) @@ -250,21 +379,39 @@ int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data, stream_data->handle = lur.ret_val; DBG("received stream handle %u", stream_data->handle); stream_data->memory_map_size = lur.u.stream.memory_map_size; - /* get shm fd */ - fd = ustcomm_recv_fd(sock); - if (fd < 0) - goto error; - stream_data->shm_fd = fd; - /* get wait fd */ - fd = ustcomm_recv_fd(sock); - if (fd < 0) + /* get shm path */ + shm_path = ustcomm_recv_string(sock); + if (!shm_path) { + err = 1; + } else { + DBG("Received shm path: %s\n", shm_path); + stream_data->shm_fd = get_dummy_fd(); + stream_data->shm_path = shm_path; + } + + /* + * We need to get the second FD even if the first fails, because + * libust expects us to read the two FDs. + */ + /* get wait pipe path */ + wait_pipe_path = ustcomm_recv_string(sock); + if (!wait_pipe_path) { + free(shm_path); + err = 1; + } else { + DBG("Received wait pipe path: %s\n", wait_pipe_path); + stream_data->wait_fd = get_dummy_fd(); + stream_data->wait_pipe_path = wait_pipe_path; + } + + if (err) goto error; - stream_data->wait_fd = fd; *_stream_data = stream_data; return ret; error: - ustctl_release_object(sock, stream_data); + (void) ustctl_release_object(sock, stream_data); + free(stream_data); return -EINVAL; } @@ -277,6 +424,9 @@ int ustctl_create_event(int sock, struct lttng_ust_event *ev, struct lttng_ust_object_data *event_data; int ret; + if (!channel_data || !_event_data) + return -EINVAL; + event_data = malloc(sizeof(*event_data)); if (!event_data) return -ENOMEM; @@ -287,6 +437,8 @@ int ustctl_create_event(int sock, struct lttng_ust_event *ev, strncpy(lum.u.event.name, ev->name, LTTNG_UST_SYM_NAME_LEN); lum.u.event.instrumentation = ev->instrumentation; + lum.u.event.loglevel_type = ev->loglevel_type; + lum.u.event.loglevel = ev->loglevel; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) { free(event_data); @@ -307,6 +459,9 @@ int ustctl_add_context(int sock, struct lttng_ust_context *ctx, struct lttng_ust_object_data *context_data; int ret; + if (!obj_data || !_context_data) + return -EINVAL; + context_data = malloc(sizeof(*context_data)); if (!context_data) return -ENOMEM; @@ -333,6 +488,9 @@ int ustctl_enable(int sock, struct lttng_ust_object_data *object) struct ustcomm_ust_reply lur; int ret; + if (!object) + return -EINVAL; + memset(&lum, 0, sizeof(lum)); lum.handle = object->handle; lum.cmd = LTTNG_UST_ENABLE; @@ -350,6 +508,9 @@ int ustctl_disable(int sock, struct lttng_ust_object_data *object) struct ustcomm_ust_reply lur; int ret; + if (!object) + return -EINVAL; + memset(&lum, 0, sizeof(lum)); lum.handle = object->handle; lum.cmd = LTTNG_UST_DISABLE; @@ -394,20 +555,25 @@ int ustctl_tracepoint_list(int sock) } int ustctl_tracepoint_list_get(int sock, int tp_list_handle, - char iter[LTTNG_UST_SYM_NAME_LEN]) + struct lttng_ust_tracepoint_iter *iter) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; int ret; + if (!iter) + return -EINVAL; + memset(&lum, 0, sizeof(lum)); lum.handle = tp_list_handle; lum.cmd = LTTNG_UST_TRACEPOINT_LIST_GET; ret = ustcomm_send_app_cmd(sock, &lum, &lur); if (ret) return ret; - DBG("received tracepoint list entry %s", lur.u.tracepoint_list_entry); - memcpy(iter, lur.u.tracepoint_list_entry, LTTNG_UST_SYM_NAME_LEN); + DBG("received tracepoint list entry name %s loglevel %d", + lur.u.tracepoint.name, + lur.u.tracepoint.loglevel); + memcpy(iter, &lur.u.tracepoint, sizeof(*iter)); return 0; } @@ -417,6 +583,9 @@ int ustctl_tracer_version(int sock, struct lttng_ust_tracer_version *v) struct ustcomm_ust_reply lur; int ret; + if (!v) + return -EINVAL; + memset(&lum, 0, sizeof(lum)); lum.handle = LTTNG_UST_ROOT_HANDLE; lum.cmd = LTTNG_UST_TRACER_VERSION; @@ -446,9 +615,31 @@ int ustctl_wait_quiescent(int sock) int ustctl_calibrate(int sock, struct lttng_ust_calibrate *calibrate) { + if (!calibrate) + return -EINVAL; + return -ENOSYS; } +int ustctl_sock_flush_buffer(int sock, struct lttng_ust_object_data *object) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + if (!object) + return -EINVAL; + + memset(&lum, 0, sizeof(lum)); + lum.handle = object->handle; + lum.cmd = LTTNG_UST_FLUSH_BUFFER; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) + return ret; + DBG("flushed buffer handle %u", object->handle); + return 0; +} + /* Buffer operations */ /* Map channel shm into process memory */ @@ -460,6 +651,9 @@ struct lttng_ust_shm_handle *ustctl_map_channel(struct lttng_ust_object_data *ch struct lttng_ust_lib_ring_buffer_config *config; int ret; + if (!chan_data) + return NULL; + handle = channel_handle_create(chan_data->shm_fd, chan_data->wait_fd, chan_data->memory_map_size); @@ -468,12 +662,24 @@ struct lttng_ust_shm_handle *ustctl_map_channel(struct lttng_ust_object_data *ch return NULL; } /* - * Set to -1 because the lttng_ust_shm_handle destruction will take care - * of closing shm_fd and wait_fd. + * Set to -1, and then close the shm fd, and set the handle shm + * fd to -1 too. We don't need the shm fds after they have been + * mapped. + * The wait_fd is set to -1 in chan_data because it is now owned + * by the handle. */ chan_data->shm_fd = -1; chan_data->wait_fd = -1; + /* chan is object 0. This is hardcoded. */ + if (handle->table->objects[0].shm_fd >= 0) { + ret = close(handle->table->objects[0].shm_fd); + if (ret) { + perror("Error closing shm_fd"); + } + handle->table->objects[0].shm_fd = -1; + } + /* * TODO: add consistency checks to be resilient if the * application try to feed us with incoherent channel structure @@ -529,6 +735,9 @@ int ustctl_add_stream(struct lttng_ust_shm_handle *handle, { int ret; + if (!handle || !stream_data) + return -EINVAL; + if (!stream_data->handle) return -ENOENT; /* map stream */ @@ -553,32 +762,55 @@ void ustctl_unmap_channel(struct lttng_ust_shm_handle *handle) { struct channel *chan; + assert(handle); chan = shmp(handle, handle->chan); channel_destroy(chan, handle, 1); } +/* + * ustctl closes the shm_fd fds after mapping it. + */ struct lttng_ust_lib_ring_buffer *ustctl_open_stream_read(struct lttng_ust_shm_handle *handle, int cpu) { - struct channel *chan = handle->shadow_chan; - int shm_fd, wait_fd; - uint64_t memory_map_size; + struct channel *chan; + int *shm_fd, *wait_fd; + char *shm_path, *wait_pipe_path; + uint64_t *memory_map_size; struct lttng_ust_lib_ring_buffer *buf; int ret; + if (!handle) + return NULL; + + chan = handle->shadow_chan; buf = channel_get_ring_buffer(&chan->backend.config, - chan, cpu, handle, &shm_fd, &wait_fd, &memory_map_size); + chan, cpu, handle, + &shm_fd, &shm_path, + &wait_fd, &wait_pipe_path, + &memory_map_size); if (!buf) return NULL; ret = lib_ring_buffer_open_read(buf, handle, 1); if (ret) return NULL; + /* + * We can close shm_fd early, right after is has been mapped. + */ + if (*shm_fd >= 0) { + ret = close(*shm_fd); + if (ret) { + perror("Error closing shm_fd"); + } + *shm_fd = -1; + } return buf; } void ustctl_close_stream_read(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf) { + assert(handle && buf); lib_ring_buffer_release_read(buf, handle, 1); } @@ -587,6 +819,8 @@ void ustctl_close_stream_read(struct lttng_ust_shm_handle *handle, void *ustctl_get_mmap_base(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf) { + if (!handle || !buf) + return NULL; return shmp(handle, buf->backend.memory_map); } @@ -596,8 +830,12 @@ int ustctl_get_mmap_len(struct lttng_ust_shm_handle *handle, unsigned long *len) { unsigned long mmap_buf_len; - struct channel *chan = handle->shadow_chan; + struct channel *chan; + if (!handle || !buf || !len) + return -EINVAL; + + chan = handle->shadow_chan; if (chan->backend.config.output != RING_BUFFER_MMAP) return -EINVAL; mmap_buf_len = chan->backend.buf_size; @@ -614,8 +852,12 @@ int ustctl_get_max_subbuf_size(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) { - struct channel *chan = handle->shadow_chan; + struct channel *chan; + if (!handle || !buf || !len) + return -EINVAL; + + chan = handle->shadow_chan; *len = chan->backend.subbuf_size; return 0; } @@ -629,9 +871,13 @@ int ustctl_get_max_subbuf_size(struct lttng_ust_shm_handle *handle, int ustctl_get_mmap_read_offset(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf, unsigned long *off) { - struct channel *chan = handle->shadow_chan; + struct channel *chan; unsigned long sb_bindex; + if (!handle || !buf || !off) + return -EINVAL; + + chan = handle->shadow_chan; if (chan->backend.config.output != RING_BUFFER_MMAP) return -EINVAL; sb_bindex = subbuffer_id_get_index(&chan->backend.config, @@ -644,8 +890,12 @@ int ustctl_get_mmap_read_offset(struct lttng_ust_shm_handle *handle, int ustctl_get_subbuf_size(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) { - struct channel *chan = handle->shadow_chan; + struct channel *chan; + + if (!handle || !buf || !len) + return -EINVAL; + chan = handle->shadow_chan; *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, handle); return 0; @@ -655,8 +905,12 @@ int ustctl_get_subbuf_size(struct lttng_ust_shm_handle *handle, int ustctl_get_padded_subbuf_size(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) { - struct channel *chan = handle->shadow_chan; + struct channel *chan; + + if (!handle || !buf || !len) + return -EINVAL; + chan = handle->shadow_chan; *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, handle); *len = PAGE_ALIGN(*len); @@ -667,6 +921,9 @@ int ustctl_get_padded_subbuf_size(struct lttng_ust_shm_handle *handle, int ustctl_get_next_subbuf(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf) { + if (!handle || !buf) + return -EINVAL; + return lib_ring_buffer_get_next_subbuf(buf, handle); } @@ -675,6 +932,9 @@ int ustctl_get_next_subbuf(struct lttng_ust_shm_handle *handle, int ustctl_put_next_subbuf(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf) { + if (!handle || !buf) + return -EINVAL; + lib_ring_buffer_put_next_subbuf(buf, handle); return 0; } @@ -685,6 +945,9 @@ int ustctl_put_next_subbuf(struct lttng_ust_shm_handle *handle, int ustctl_snapshot(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf) { + if (!handle || !buf) + return -EINVAL; + return lib_ring_buffer_snapshot(buf, &buf->cons_snapshot, &buf->prod_snapshot, handle); } @@ -693,6 +956,9 @@ int ustctl_snapshot(struct lttng_ust_shm_handle *handle, int ustctl_snapshot_get_consumed(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) { + if (!handle || !buf || !pos) + return -EINVAL; + *pos = buf->cons_snapshot; return 0; } @@ -701,6 +967,9 @@ int ustctl_snapshot_get_consumed(struct lttng_ust_shm_handle *handle, int ustctl_snapshot_get_produced(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) { + if (!handle || !buf || !pos) + return -EINVAL; + *pos = buf->prod_snapshot; return 0; } @@ -709,6 +978,9 @@ int ustctl_snapshot_get_produced(struct lttng_ust_shm_handle *handle, int ustctl_get_subbuf(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) { + if (!handle || !buf || !pos) + return -EINVAL; + return lib_ring_buffer_get_subbuf(buf, *pos, handle); } @@ -716,6 +988,9 @@ int ustctl_get_subbuf(struct lttng_ust_shm_handle *handle, int ustctl_put_subbuf(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf) { + if (!handle || !buf) + return -EINVAL; + lib_ring_buffer_put_subbuf(buf, handle); return 0; } @@ -724,6 +999,7 @@ void ustctl_flush_buffer(struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf, int producer_active) { + assert(handle && buf); lib_ring_buffer_switch_slow(buf, producer_active ? SWITCH_ACTIVE : SWITCH_FLUSH, handle);