+void ustctl_clear_buffer(struct ustctl_consumer_stream *stream)
+{
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
+
+ assert(stream);
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE,
+ consumer_chan->chan->handle);
+ lib_ring_buffer_clear_reader(buf, consumer_chan->chan->handle);
+}
+
+static
+struct lttng_ust_client_lib_ring_buffer_client_cb *get_client_cb(
+ struct lttng_ust_lib_ring_buffer *buf,
+ struct lttng_ust_shm_handle *handle)
+{
+ struct channel *chan;
+ const struct lttng_ust_lib_ring_buffer_config *config;
+ struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb;
+
+ chan = shmp(handle, buf->backend.chan);
+ if (!chan)
+ return NULL;
+ config = &chan->backend.config;
+ if (!config->cb_ptr)
+ return NULL;
+ client_cb = caa_container_of(config->cb_ptr,
+ struct lttng_ust_client_lib_ring_buffer_client_cb,
+ parent);
+ return client_cb;
+}
+
+int ustctl_get_timestamp_begin(struct ustctl_consumer_stream *stream,
+ uint64_t *timestamp_begin)
+{
+ struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct lttng_ust_shm_handle *handle;
+
+ if (!stream || !timestamp_begin)
+ return -EINVAL;
+ buf = stream->buf;
+ handle = stream->chan->chan->handle;
+ client_cb = get_client_cb(buf, handle);
+ if (!client_cb)
+ return -ENOSYS;
+ return client_cb->timestamp_begin(buf, handle, timestamp_begin);
+}
+
+int ustctl_get_timestamp_end(struct ustctl_consumer_stream *stream,
+ uint64_t *timestamp_end)
+{
+ struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct lttng_ust_shm_handle *handle;
+
+ if (!stream || !timestamp_end)
+ return -EINVAL;
+ buf = stream->buf;
+ handle = stream->chan->chan->handle;
+ client_cb = get_client_cb(buf, handle);
+ if (!client_cb)
+ return -ENOSYS;
+ return client_cb->timestamp_end(buf, handle, timestamp_end);
+}
+
+int ustctl_get_events_discarded(struct ustctl_consumer_stream *stream,
+ uint64_t *events_discarded)
+{
+ struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct lttng_ust_shm_handle *handle;
+
+ if (!stream || !events_discarded)
+ return -EINVAL;
+ buf = stream->buf;
+ handle = stream->chan->chan->handle;
+ client_cb = get_client_cb(buf, handle);
+ if (!client_cb)
+ return -ENOSYS;
+ return client_cb->events_discarded(buf, handle, events_discarded);
+}
+
+int ustctl_get_content_size(struct ustctl_consumer_stream *stream,
+ uint64_t *content_size)
+{
+ struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct lttng_ust_shm_handle *handle;
+
+ if (!stream || !content_size)
+ return -EINVAL;
+ buf = stream->buf;
+ handle = stream->chan->chan->handle;
+ client_cb = get_client_cb(buf, handle);
+ if (!client_cb)
+ return -ENOSYS;
+ return client_cb->content_size(buf, handle, content_size);
+}
+
+int ustctl_get_packet_size(struct ustctl_consumer_stream *stream,
+ uint64_t *packet_size)
+{
+ struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct lttng_ust_shm_handle *handle;
+
+ if (!stream || !packet_size)
+ return -EINVAL;
+ buf = stream->buf;
+ handle = stream->chan->chan->handle;
+ client_cb = get_client_cb(buf, handle);
+ if (!client_cb)
+ return -ENOSYS;
+ return client_cb->packet_size(buf, handle, packet_size);
+}
+
+int ustctl_get_stream_id(struct ustctl_consumer_stream *stream,
+ uint64_t *stream_id)
+{
+ struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct lttng_ust_shm_handle *handle;
+
+ if (!stream || !stream_id)
+ return -EINVAL;
+ buf = stream->buf;
+ handle = stream->chan->chan->handle;
+ client_cb = get_client_cb(buf, handle);
+ if (!client_cb)
+ return -ENOSYS;
+ return client_cb->stream_id(buf, handle, stream_id);
+}
+
+int ustctl_get_current_timestamp(struct ustctl_consumer_stream *stream,
+ uint64_t *ts)
+{
+ struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct lttng_ust_shm_handle *handle;
+
+ if (!stream || !ts)
+ return -EINVAL;
+ buf = stream->buf;
+ handle = stream->chan->chan->handle;
+ client_cb = get_client_cb(buf, handle);
+ if (!client_cb || !client_cb->current_timestamp)
+ return -ENOSYS;
+ return client_cb->current_timestamp(buf, handle, ts);
+}
+
+int ustctl_get_sequence_number(struct ustctl_consumer_stream *stream,
+ uint64_t *seq)
+{
+ struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct lttng_ust_shm_handle *handle;
+
+ if (!stream || !seq)
+ return -EINVAL;
+ buf = stream->buf;
+ handle = stream->chan->chan->handle;
+ client_cb = get_client_cb(buf, handle);
+ if (!client_cb || !client_cb->sequence_number)
+ return -ENOSYS;
+ return client_cb->sequence_number(buf, handle, seq);
+}
+
+int ustctl_get_instance_id(struct ustctl_consumer_stream *stream,
+ uint64_t *id)
+{
+ struct lttng_ust_client_lib_ring_buffer_client_cb *client_cb;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct lttng_ust_shm_handle *handle;
+
+ if (!stream || !id)
+ return -EINVAL;
+ buf = stream->buf;
+ handle = stream->chan->chan->handle;
+ client_cb = get_client_cb(buf, handle);
+ if (!client_cb)
+ return -ENOSYS;
+ return client_cb->instance_id(buf, handle, id);
+}
+
+#ifdef LTTNG_UST_HAVE_PERF_EVENT
+
+int ustctl_has_perf_counters(void)
+{
+ return 1;
+}
+
+#else
+
+int ustctl_has_perf_counters(void)
+{
+ return 0;
+}
+
+#endif
+
+#ifdef __linux__
+/*
+ * Override application pid/uid/gid with unix socket credentials. If
+ * the application announced a pid matching our view, it means it is
+ * within the same pid namespace, so expose the ppid provided by the
+ * application.
+ */
+static
+int get_cred(int sock,
+ const struct ustctl_reg_msg *reg_msg,
+ uint32_t *pid,
+ uint32_t *ppid,
+ uint32_t *uid,
+ uint32_t *gid)
+{
+ struct ucred ucred;
+ socklen_t ucred_len = sizeof(struct ucred);
+ int ret;
+
+ ret = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len);
+ if (ret) {
+ return -LTTNG_UST_ERR_PEERCRED;
+ }
+ DBG("Unix socket peercred [ pid: %u, uid: %u, gid: %u ], "
+ "application registered claiming [ pid: %u, ppid: %u, uid: %u, gid: %u ]",
+ ucred.pid, ucred.uid, ucred.gid,
+ reg_msg->pid, reg_msg->ppid, reg_msg->uid, reg_msg->gid);
+ if (!ucred.pid) {
+ ERR("Unix socket credential pid=0. Refusing application in distinct, non-nested pid namespace.");
+ return -LTTNG_UST_ERR_PEERCRED_PID;
+ }
+ *pid = ucred.pid;
+ *uid = ucred.uid;
+ *gid = ucred.gid;
+ if (ucred.pid == reg_msg->pid) {
+ *ppid = reg_msg->ppid;
+ } else {
+ *ppid = 0;
+ }
+ return 0;
+}
+#elif defined(__FreeBSD__)
+#include <sys/ucred.h>
+#include <sys/un.h>
+
+/*
+ * Override application uid/gid with unix socket credentials. Use the
+ * first group of the cr_groups.
+ * Use the pid and ppid provided by the application on registration.
+ */
+static
+int get_cred(int sock,
+ const struct ustctl_reg_msg *reg_msg,
+ uint32_t *pid,
+ uint32_t *ppid,
+ uint32_t *uid,
+ uint32_t *gid)
+{
+ struct xucred xucred;
+ socklen_t xucred_len = sizeof(struct xucred);
+ int ret;
+
+ ret = getsockopt(sock, SOL_SOCKET, LOCAL_PEERCRED, &xucred, &xucred_len);
+ if (ret) {
+ return -LTTNG_UST_ERR_PEERCRED;
+ }
+ if (xucred.cr_version != XUCRED_VERSION || xucred.cr_ngroups < 1) {
+ return -LTTNG_UST_ERR_PEERCRED;
+ }
+ DBG("Unix socket peercred [ uid: %u, gid: %u ], "
+ "application registered claiming [ pid: %d, ppid: %d, uid: %u, gid: %u ]",
+ xucred.cr_uid, xucred.cr_groups[0],
+ reg_msg->pid, reg_msg->ppid, reg_msg->uid, reg_msg->gid);
+ *pid = reg_msg->pid;
+ *ppid = reg_msg->ppid;
+ *uid = xucred.cr_uid;
+ *gid = xucred.cr_groups[0];
+ return 0;
+}
+#else
+#warning "Using insecure fallback: trusting user id provided by registered applications. Please consider implementing use of unix socket credentials on your platform."
+static
+int get_cred(int sock,
+ const struct ustctl_reg_msg *reg_msg,
+ uint32_t *pid,
+ uint32_t *ppid,
+ uint32_t *uid,
+ uint32_t *gid)
+{
+ DBG("Application registered claiming [ pid: %u, ppid: %d, uid: %u, gid: %u ]",
+ reg_msg->pid, reg_msg->ppid, reg_msg->uid, reg_msg->gid);
+ *pid = reg_msg->pid;
+ *ppid = reg_msg->ppid;
+ *uid = reg_msg->uid;
+ *gid = reg_msg->gid;
+ return 0;
+}
+#endif
+