blob: 6ca92ef2ef04fc6ce2a145d8a50d3be474072d56 [file] [log] [blame]
Pekka Paalanena5630ea2017-10-12 13:13:42 +02001/*
2 * Copyright © 2017 Pekka Paalanen <pq@iki.fi>
3 * Copyright © 2018 Zodiac Inflight Innovations
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27#include "config.h"
28
Marius Vladf4f4c2b2019-04-29 13:27:47 +030029#include <libweston/weston-debug.h>
Pekka Paalanena5630ea2017-10-12 13:13:42 +020030#include "helpers.h"
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020031#include <libweston/libweston.h>
Pekka Paalanena5630ea2017-10-12 13:13:42 +020032
Marius Vlade0a858a2019-06-25 12:48:56 +030033#include "weston-log-internal.h"
34
Pekka Paalanena5630ea2017-10-12 13:13:42 +020035#include "weston-debug-server-protocol.h"
36
37#include <assert.h>
38#include <unistd.h>
39#include <stdarg.h>
40#include <string.h>
41#include <errno.h>
42#include <sys/time.h>
43
Marius Vlad3d7d9782019-04-17 12:35:38 +030044/** Main weston-log context
Pekka Paalanena5630ea2017-10-12 13:13:42 +020045 *
Marius Vlade0a858a2019-06-25 12:48:56 +030046 * One per weston_compositor. Stores list of scopes created and a list pending
47 * subscriptions.
Pekka Paalanena5630ea2017-10-12 13:13:42 +020048 *
Marius Vlade0a858a2019-06-25 12:48:56 +030049 * A pending subscription is a subscription to a scope which hasn't been
50 * created. When the scope is finally created the pending subscription will be
51 * removed from the pending subscription list, but not before was added in the
52 * scope's subscription list and that of the subscriber list.
53 *
54 * Pending subscriptions only make sense for other types of streams, other than
55 * those created by weston-debug protocol. In the case of the weston-debug
56 * protocol, the subscription processes is done automatically whenever a client
57 * connects and subscribes to a scope which was previously advertised by the
58 * compositor.
59 *
60 * @internal
Pekka Paalanena5630ea2017-10-12 13:13:42 +020061 */
Marius Vlad3d7d9782019-04-17 12:35:38 +030062struct weston_log_context {
Pekka Paalanena5630ea2017-10-12 13:13:42 +020063 struct wl_listener compositor_destroy_listener;
64 struct wl_global *global;
Marius Vlad5d5e3352019-04-17 13:05:38 +030065 struct wl_list scope_list; /**< weston_log_scope::compositor_link */
Marius Vlade0a858a2019-06-25 12:48:56 +030066 struct wl_list pending_subscription_list; /**< weston_log_subscription::source_link */
Pekka Paalanena5630ea2017-10-12 13:13:42 +020067};
68
Marius Vlad5d5e3352019-04-17 13:05:38 +030069/** weston-log message scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +020070 *
Marius Vlad7e4db952019-04-17 13:47:06 +030071 * This is used for scoping logging/debugging messages. Clients can subscribe
72 * to only the scopes they are interested in. A scope is identified by its name
Pekka Paalanena5630ea2017-10-12 13:13:42 +020073 * (also referred to as debug stream name).
74 */
Marius Vlad5d5e3352019-04-17 13:05:38 +030075struct weston_log_scope {
Pekka Paalanena5630ea2017-10-12 13:13:42 +020076 char *name;
77 char *desc;
Marius Vlad5d5e3352019-04-17 13:05:38 +030078 weston_log_scope_cb begin_cb;
Pekka Paalanena5630ea2017-10-12 13:13:42 +020079 void *user_data;
Pekka Paalanena5630ea2017-10-12 13:13:42 +020080 struct wl_list compositor_link;
Marius Vlade0a858a2019-06-25 12:48:56 +030081 struct wl_list subscription_list; /**< weston_log_subscription::source_link */
Pekka Paalanena5630ea2017-10-12 13:13:42 +020082};
83
Marius Vlade0a858a2019-06-25 12:48:56 +030084/** Ties a subscriber to a scope
85 *
86 * A subscription is created each time we'd want to subscribe to a scope. From
87 * the stream type we can retrieve the subscriber and from the subscriber we
88 * reach each of the streams callbacks. See also weston_log_subscriber object.
89 *
90 * When a subscription has been created we store it in the scope's subscription
91 * list and in the subscriber's subscription list. The subscription might be a
92 * pending subscription until the scope for which there's was a subscribe has
93 * been created. The scope creation will take of looking through the pending
94 * subscription list.
95 *
96 * A subscription can reached from a subscriber subscription list by using the
97 * streams base class.
98 *
99 * @internal
100 */
101struct weston_log_subscription {
102 struct weston_log_subscriber *owner;
103 struct wl_list owner_link; /**< weston_log_subscriber::subscription_list */
104
105 char *scope_name;
106 struct weston_log_scope *source;
107 struct wl_list source_link; /**< weston_log_scope::subscription_list or
108 weston_log_context::pending_subscription_list */
109};
110
111
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200112/** A debug stream created by a client
113 *
114 * A client provides a file descriptor for the server to write debug
115 * messages into. A weston_debug_stream is associated to one
Marius Vlad5d5e3352019-04-17 13:05:38 +0300116 * weston_log_scope via the scope name, and the scope provides the messages.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200117 * There can be several streams for the same scope, all streams getting the
118 * same messages.
119 */
120struct weston_debug_stream {
Marius Vlad7814f302019-06-21 14:20:15 +0300121 struct weston_log_subscriber base;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200122 int fd; /**< client provided fd */
123 struct wl_resource *resource; /**< weston_debug_stream_v1 object */
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200124};
125
Marius Vlad7814f302019-06-21 14:20:15 +0300126static struct weston_debug_stream *
127to_weston_debug_stream(struct weston_log_subscriber *sub)
128{
129 return container_of(sub, struct weston_debug_stream, base);
130}
131
Marius Vlade0a858a2019-06-25 12:48:56 +0300132/** Creates a new subscription using the subscriber by \c owner.
133 *
134 * The subscription created is added to the \c owner subscription list.
135 * Destroying the subscription using weston_log_subscription_destroy() will
136 * remove the link from the subscription list and free storage alloc'ed.
137 *
138 * @param owner the subscriber owner, must be created before creating a
139 * subscription
140 * @param scope_name the scope for which to create this subscription
141 * @returns a weston_log_subscription object in case of success, or NULL
142 * otherwise
143 *
144 * @internal
145 * @sa weston_log_subscription_destroy, weston_log_subscription_remove,
146 * weston_log_subscription_add
147 */
148struct weston_log_subscription *
149weston_log_subscription_create(struct weston_log_subscriber *owner,
150 const char *scope_name)
151{
152 struct weston_log_subscription *sub;
153 assert(owner);
154 assert(scope_name);
155
156 sub = zalloc(sizeof(*sub));
157 if (!sub)
158 return NULL;
159
160 sub->owner = owner;
161 sub->scope_name = strdup(scope_name);
162
163 wl_list_insert(&sub->owner->subscription_list, &sub->owner_link);
164 return sub;
165}
166
167/** Destroys the subscription
168 *
169 * @param sub
170 * @internal
171 */
172void
173weston_log_subscription_destroy(struct weston_log_subscription *sub)
174{
175 if (sub->owner)
176 wl_list_remove(&sub->owner_link);
177 free(sub->scope_name);
178 free(sub);
179}
180
181/** Retrieve a subscription by using the subscriber
182 *
183 * This is useful when trying to find a subscription from the subscriber by
184 * having only access to the stream.
185 *
186 * @param subscriber the subscriber in question
187 * @returns a weston_log_subscription object
188 *
189 * @internal
190 */
191struct weston_log_subscription *
192weston_log_subscriber_get_only_subscription(struct weston_log_subscriber *subscriber)
193{
194 struct weston_log_subscription *sub;
195 /* unlikely, but can happen */
196 if (wl_list_length(&subscriber->subscription_list) == 0)
197 return NULL;
198
199 assert(wl_list_length(&subscriber->subscription_list) == 1);
200
201 return wl_container_of(subscriber->subscription_list.prev,
202 sub, owner_link);
203}
204
205/** Adds the subscription \c sub to the subscription list of the
206 * scope.
207 *
208 * This should used when the scope has been created, and the subscription \c
209 * sub has be created before calling this function.
210 *
211 * @param scope the scope
212 * @param sub the subscription, it must be created before, see
213 * weston_log_subscription_create()
214 *
215 * @internal
216 */
217void
218weston_log_subscription_add(struct weston_log_scope *scope,
219 struct weston_log_subscription *sub)
220{
221 assert(scope);
222 assert(sub);
223 /* don't allow subscriptions to have a source already! */
224 assert(!sub->source);
225
226 sub->source = scope;
227 wl_list_insert(&scope->subscription_list, &sub->source_link);
228}
229
230/** Removes the subscription from the scope's subscription list
231 *
232 * @internal
233 */
234void
235weston_log_subscription_remove(struct weston_log_subscription *sub)
236{
237 assert(sub);
238 if (sub->source)
239 wl_list_remove(&sub->source_link);
240 sub->source = NULL;
241}
242
243
Marius Vlad5d5e3352019-04-17 13:05:38 +0300244static struct weston_log_scope *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300245get_scope(struct weston_log_context *log_ctx, const char *name)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200246{
Marius Vlad5d5e3352019-04-17 13:05:38 +0300247 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200248
Marius Vlad3d7d9782019-04-17 12:35:38 +0300249 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200250 if (strcmp(name, scope->name) == 0)
251 return scope;
252
253 return NULL;
254}
255
256static void
257stream_close_unlink(struct weston_debug_stream *stream)
258{
259 if (stream->fd != -1)
260 close(stream->fd);
261 stream->fd = -1;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200262}
263
264static void WL_PRINTF(2, 3)
265stream_close_on_failure(struct weston_debug_stream *stream,
266 const char *fmt, ...)
267{
268 char *msg;
269 va_list ap;
270 int ret;
271
272 stream_close_unlink(stream);
273
274 va_start(ap, fmt);
275 ret = vasprintf(&msg, fmt, ap);
276 va_end(ap);
277
278 if (ret > 0) {
279 weston_debug_stream_v1_send_failure(stream->resource, msg);
280 free(msg);
281 } else {
282 weston_debug_stream_v1_send_failure(stream->resource,
283 "MEMFAIL");
284 }
285}
286
Marius Vlad7814f302019-06-21 14:20:15 +0300287/** Write data into a specific debug stream
288 *
289 * \param sub The subscriber's stream to write into; must not be NULL.
290 * \param[in] data Pointer to the data to write.
291 * \param len Number of bytes to write.
292 *
293 * Writes the given data (binary verbatim) into the debug stream.
294 * If \c len is zero or negative, the write is silently dropped.
295 *
296 * Writing is continued until all data has been written or
297 * a write fails. If the write fails due to a signal, it is re-tried.
298 * Otherwise on failure, the stream is closed and
299 * \c weston_debug_stream_v1.failure event is sent to the client.
300 *
301 * \memberof weston_debug_stream
302 */
303static void
304weston_debug_stream_write(struct weston_log_subscriber *sub,
305 const char *data, size_t len)
306{
307 ssize_t len_ = len;
308 ssize_t ret;
309 int e;
310 struct weston_debug_stream *stream = to_weston_debug_stream(sub);
311
312 if (stream->fd == -1)
313 return;
314
315 while (len_ > 0) {
316 ret = write(stream->fd, data, len_);
317 e = errno;
318 if (ret < 0) {
319 if (e == EINTR)
320 continue;
321
322 stream_close_on_failure(stream,
323 "Error writing %zd bytes: %s (%d)",
324 len_, strerror(e), e);
325 break;
326 }
327
328 len_ -= ret;
329 data += ret;
330 }
331}
332
333/** Close the debug stream and send success event
334 *
335 * \param sub Subscriber's stream to close.
336 *
337 * Closes the debug stream and sends \c weston_debug_stream_v1.complete
338 * event to the client. This tells the client the debug information dump
339 * is complete.
340 *
341 * \memberof weston_debug_stream
342 */
343static void
344weston_debug_stream_complete(struct weston_log_subscriber *sub)
345{
346 struct weston_debug_stream *stream = to_weston_debug_stream(sub);
347
348 stream_close_unlink(stream);
349 weston_debug_stream_v1_send_complete(stream->resource);
350}
351
352static void
353weston_debug_stream_to_destroy(struct weston_log_subscriber *sub)
354{
355 struct weston_debug_stream *stream = to_weston_debug_stream(sub);
356 stream_close_on_failure(stream, "debug name removed");
357}
358
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200359static struct weston_debug_stream *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300360stream_create(struct weston_log_context *log_ctx, const char *name,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200361 int32_t streamfd, struct wl_resource *stream_resource)
362{
363 struct weston_debug_stream *stream;
Marius Vlad5d5e3352019-04-17 13:05:38 +0300364 struct weston_log_scope *scope;
Marius Vlad7814f302019-06-21 14:20:15 +0300365 struct weston_log_subscription *sub;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200366
367 stream = zalloc(sizeof *stream);
368 if (!stream)
369 return NULL;
370
Marius Vlad7814f302019-06-21 14:20:15 +0300371
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200372 stream->fd = streamfd;
373 stream->resource = stream_resource;
374
Marius Vlad7814f302019-06-21 14:20:15 +0300375 stream->base.write = weston_debug_stream_write;
376 stream->base.destroy = weston_debug_stream_to_destroy;
377 stream->base.complete = weston_debug_stream_complete;
378 wl_list_init(&stream->base.subscription_list);
379
380 sub = weston_log_subscription_create(&stream->base, name);
381
Marius Vlad3d7d9782019-04-17 12:35:38 +0300382 scope = get_scope(log_ctx, name);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200383 if (scope) {
Marius Vlad7814f302019-06-21 14:20:15 +0300384 weston_log_subscription_add(scope, sub);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200385 if (scope->begin_cb)
Marius Vlad7814f302019-06-21 14:20:15 +0300386 scope->begin_cb(scope, scope->user_data);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200387 } else {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200388 stream_close_on_failure(stream,
389 "Debug stream name '%s' is unknown.",
390 name);
391 }
392
393 return stream;
394}
395
396static void
397stream_destroy(struct wl_resource *stream_resource)
398{
399 struct weston_debug_stream *stream;
Marius Vlad7814f302019-06-21 14:20:15 +0300400 struct weston_log_subscription *sub = NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200401
402 stream = wl_resource_get_user_data(stream_resource);
403
404 if (stream->fd != -1)
405 close(stream->fd);
Marius Vlad7814f302019-06-21 14:20:15 +0300406
407 sub = weston_log_subscriber_get_only_subscription(&stream->base);
408 weston_log_subscription_remove(sub);
409 weston_log_subscription_destroy(sub);
410
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200411 free(stream);
412}
413
414static void
415weston_debug_stream_destroy(struct wl_client *client,
416 struct wl_resource *stream_resource)
417{
418 wl_resource_destroy(stream_resource);
419}
420
421static const struct weston_debug_stream_v1_interface
422 weston_debug_stream_impl = {
423 weston_debug_stream_destroy
424};
425
426static void
427weston_debug_destroy(struct wl_client *client,
428 struct wl_resource *global_resource)
429{
430 wl_resource_destroy(global_resource);
431}
432
433static void
434weston_debug_subscribe(struct wl_client *client,
435 struct wl_resource *global_resource,
436 const char *name,
437 int32_t streamfd,
438 uint32_t new_stream_id)
439{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300440 struct weston_log_context *log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200441 struct wl_resource *stream_resource;
442 uint32_t version;
443 struct weston_debug_stream *stream;
444
Marius Vlad3d7d9782019-04-17 12:35:38 +0300445 log_ctx = wl_resource_get_user_data(global_resource);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200446 version = wl_resource_get_version(global_resource);
447
448 stream_resource = wl_resource_create(client,
449 &weston_debug_stream_v1_interface,
450 version, new_stream_id);
451 if (!stream_resource)
452 goto fail;
453
Marius Vlad3d7d9782019-04-17 12:35:38 +0300454 stream = stream_create(log_ctx, name, streamfd, stream_resource);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200455 if (!stream)
456 goto fail;
457
458 wl_resource_set_implementation(stream_resource,
459 &weston_debug_stream_impl,
460 stream, stream_destroy);
461 return;
462
463fail:
464 close(streamfd);
465 wl_client_post_no_memory(client);
466}
467
468static const struct weston_debug_v1_interface weston_debug_impl = {
469 weston_debug_destroy,
470 weston_debug_subscribe
471};
472
473static void
474bind_weston_debug(struct wl_client *client,
475 void *data, uint32_t version, uint32_t id)
476{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300477 struct weston_log_context *log_ctx = data;
Marius Vlad5d5e3352019-04-17 13:05:38 +0300478 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200479 struct wl_resource *resource;
480
481 resource = wl_resource_create(client,
482 &weston_debug_v1_interface,
483 version, id);
484 if (!resource) {
485 wl_client_post_no_memory(client);
486 return;
487 }
488 wl_resource_set_implementation(resource, &weston_debug_impl,
Marius Vlad3d7d9782019-04-17 12:35:38 +0300489 log_ctx, NULL);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200490
Marius Vlad3d7d9782019-04-17 12:35:38 +0300491 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link) {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200492 weston_debug_v1_send_available(resource, scope->name,
493 scope->desc);
494 }
495}
496
Marius Vlad880b4852019-04-07 17:07:58 +0300497/**
Marius Vlad3d7d9782019-04-17 12:35:38 +0300498 * Connect weston_compositor structure to weston_log_context structure.
Marius Vlad880b4852019-04-07 17:07:58 +0300499 *
500 * \param compositor
Marius Vlad3d7d9782019-04-17 12:35:38 +0300501 * \param log_ctx
Marius Vlad880b4852019-04-07 17:07:58 +0300502 * \return 0 on success, -1 on failure
503 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300504 * Sets weston_compositor::weston_log_ctx.
Marius Vlad880b4852019-04-07 17:07:58 +0300505 */
506int
Marius Vlad3d7d9782019-04-17 12:35:38 +0300507weston_log_ctx_compositor_setup(struct weston_compositor *compositor,
508 struct weston_log_context *log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300509{
Marius Vlad6f098662019-04-17 13:50:28 +0300510 assert(!compositor->weston_log_ctx);
511 assert(log_ctx);
Marius Vlad880b4852019-04-07 17:07:58 +0300512
Marius Vlad3d7d9782019-04-17 12:35:38 +0300513 compositor->weston_log_ctx = log_ctx;
Marius Vlad880b4852019-04-07 17:07:58 +0300514 return 0;
515}
516
Marius Vlada2dace22019-06-12 16:05:44 +0300517/** Creates weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200518 *
Marius Vlada2dace22019-06-12 16:05:44 +0300519 * \return NULL in case of failure, or a weston_log_context object in case of
520 * success
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200521 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300522 * weston_log_context is a singleton for each weston_compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200523 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200524 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300525WL_EXPORT struct weston_log_context *
526weston_log_ctx_compositor_create(void)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200527{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300528 struct weston_log_context *log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200529
Marius Vlad3d7d9782019-04-17 12:35:38 +0300530 log_ctx = zalloc(sizeof *log_ctx);
531 if (!log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300532 return NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200533
Marius Vlad3d7d9782019-04-17 12:35:38 +0300534 wl_list_init(&log_ctx->scope_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200535
Marius Vlad3d7d9782019-04-17 12:35:38 +0300536 return log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200537}
538
Marius Vlad3d7d9782019-04-17 12:35:38 +0300539/** Destroy weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200540 *
541 * \param compositor The libweston compositor whose weston-debug to tear down.
542 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300543 * Clears weston_compositor::weston_log_ctx.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200544 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200545 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300546WL_EXPORT void
547weston_log_ctx_compositor_destroy(struct weston_compositor *compositor)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200548{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300549 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
Marius Vlad5d5e3352019-04-17 13:05:38 +0300550 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200551
Marius Vlad3d7d9782019-04-17 12:35:38 +0300552 if (log_ctx->global)
553 wl_global_destroy(log_ctx->global);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200554
Marius Vlad3d7d9782019-04-17 12:35:38 +0300555 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200556 weston_log("Internal warning: debug scope '%s' has not been destroyed.\n",
557 scope->name);
558
559 /* Remove head to not crash if scope removed later. */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300560 wl_list_remove(&log_ctx->scope_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200561
Marius Vlad3d7d9782019-04-17 12:35:38 +0300562 free(log_ctx);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200563
Marius Vlad3d7d9782019-04-17 12:35:38 +0300564 compositor->weston_log_ctx = NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200565}
566
567/** Enable weston-debug protocol extension
568 *
569 * \param compositor The libweston compositor where to enable.
570 *
571 * This enables the weston_debug_v1 Wayland protocol extension which any client
Emmanuel Gil Peyrot426c2462019-02-20 16:33:32 +0100572 * can use to get debug messages from the compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200573 *
574 * WARNING: This feature should not be used in production. If a client
575 * provides a file descriptor that blocks writes, it will block the whole
576 * compositor indefinitely.
577 *
578 * There is no control on which client is allowed to subscribe to debug
579 * messages. Any and all clients are allowed.
580 *
581 * The debug extension is disabled by default, and once enabled, cannot be
582 * disabled again.
583 */
584WL_EXPORT void
585weston_compositor_enable_debug_protocol(struct weston_compositor *compositor)
586{
Marius Vlad1e2fda22019-04-07 19:07:16 +0300587 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
588 assert(log_ctx);
589 if (log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200590 return;
591
Marius Vlad1e2fda22019-04-07 19:07:16 +0300592 log_ctx->global = wl_global_create(compositor->wl_display,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200593 &weston_debug_v1_interface, 1,
Marius Vlad1e2fda22019-04-07 19:07:16 +0300594 log_ctx, bind_weston_debug);
595 if (!log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200596 return;
597
598 weston_log("WARNING: debug protocol has been enabled. "
599 "This is a potential denial-of-service attack vector and "
600 "information leak.\n");
601}
602
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200603/** Determine if the debug protocol has been enabled
604 *
605 * \param wc The libweston compositor to verify if debug protocol has been enabled
606 */
607WL_EXPORT bool
608weston_compositor_is_debug_protocol_enabled(struct weston_compositor *wc)
609{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300610 return wc->weston_log_ctx->global != NULL;
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200611}
612
Marius Vlad7e4db952019-04-17 13:47:06 +0300613/** Register a new debug stream name, creating a log scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200614 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300615 * \param log_ctx The weston_log_context where to add.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200616 * \param name The debug stream/scope name; must not be NULL.
Marius Vlada2dace22019-06-12 16:05:44 +0300617 * \param description The debug scope description for humans; must not be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200618 * \param begin_cb Optional callback when a client subscribes to this scope.
619 * \param user_data Optional user data pointer for the callback.
620 * \return A valid pointer on success, NULL on failure.
621 *
622 * This function is used to create a debug scope. All debug message printing
623 * happens for a scope, which allows clients to subscribe to the kind of
624 * debug messages they want by \c name.
625 *
626 * \c name must be unique in the \c weston_compositor instance. \c name and
627 * \c description must both be provided. The description is printed when a
628 * client asks for a list of supported debug scopes.
629 *
630 * \c begin_cb, if not NULL, is called when a client subscribes to the
631 * debug scope creating a debug stream. This is for debug scopes that need
632 * to print messages as a response to a client appearing, e.g. printing a
633 * list of windows on demand or a static preamble. The argument \c user_data
634 * is passed in to the callback and is otherwise unused.
635 *
636 * For one-shot debug streams, \c begin_cb should finally call
637 * weston_debug_stream_complete() to close the stream and tell the client
638 * the printing is complete. Otherwise the client expects more to be written
639 * to its file descriptor.
640 *
641 * The debug scope must be destroyed before destroying the
642 * \c weston_compositor.
643 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300644 * \memberof weston_log_scope
645 * \sa weston_debug_stream, weston_log_scope_cb
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200646 */
Marius Vlad5d5e3352019-04-17 13:05:38 +0300647WL_EXPORT struct weston_log_scope *
Marius Vlad7e4db952019-04-17 13:47:06 +0300648weston_compositor_add_log_scope(struct weston_log_context *log_ctx,
649 const char *name,
650 const char *description,
651 weston_log_scope_cb begin_cb,
652 void *user_data)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200653{
Marius Vlad5d5e3352019-04-17 13:05:38 +0300654 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200655
Marius Vlad1e2fda22019-04-07 19:07:16 +0300656 if (!name || !description) {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200657 weston_log("Error: cannot add a debug scope without name or description.\n");
658 return NULL;
659 }
660
Marius Vlad3d7d9782019-04-17 12:35:38 +0300661 if (!log_ctx) {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200662 weston_log("Error: cannot add debug scope '%s', infra not initialized.\n",
663 name);
664 return NULL;
665 }
666
Marius Vlad3d7d9782019-04-17 12:35:38 +0300667 if (get_scope(log_ctx, name)){
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200668 weston_log("Error: debug scope named '%s' is already registered.\n",
669 name);
670 return NULL;
671 }
672
673 scope = zalloc(sizeof *scope);
674 if (!scope) {
675 weston_log("Error adding debug scope '%s': out of memory.\n",
676 name);
677 return NULL;
678 }
679
680 scope->name = strdup(name);
681 scope->desc = strdup(description);
682 scope->begin_cb = begin_cb;
683 scope->user_data = user_data;
Marius Vlad7814f302019-06-21 14:20:15 +0300684 wl_list_init(&scope->subscription_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200685
686 if (!scope->name || !scope->desc) {
687 weston_log("Error adding debug scope '%s': out of memory.\n",
688 name);
689 free(scope->name);
690 free(scope->desc);
691 free(scope);
692 return NULL;
693 }
694
Marius Vlad3d7d9782019-04-17 12:35:38 +0300695 wl_list_insert(log_ctx->scope_list.prev, &scope->compositor_link);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200696
697 return scope;
698}
699
Marius Vlad3d7d9782019-04-17 12:35:38 +0300700/** Destroy a log scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200701 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300702 * \param scope The log scope to destroy; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200703 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300704 * Destroys the log scope, closing all open streams subscribed to it and
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200705 * sending them each a \c weston_debug_stream_v1.failure event.
706 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300707 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200708 */
709WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300710weston_compositor_log_scope_destroy(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200711{
Marius Vlad7814f302019-06-21 14:20:15 +0300712 struct weston_log_subscription *sub, *sub_tmp;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200713
714 if (!scope)
715 return;
716
Marius Vlad7814f302019-06-21 14:20:15 +0300717 wl_list_for_each_safe(sub, sub_tmp, &scope->subscription_list, source_link) {
718 /* destroy each subscription */
719 if (sub->owner->destroy)
720 sub->owner->destroy(sub->owner);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200721
Marius Vlad7814f302019-06-21 14:20:15 +0300722 weston_log_subscription_remove(sub);
723 weston_log_subscription_destroy(sub);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200724 }
725
726 wl_list_remove(&scope->compositor_link);
727 free(scope->name);
728 free(scope->desc);
729 free(scope);
730}
731
732/** Are there any active subscriptions to the scope?
733 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300734 * \param scope The log scope to check; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200735 * \return True if any streams are open for this scope, false otherwise.
736 *
737 * As printing some debugging messages may be relatively expensive, one
738 * can use this function to determine if there is a need to gather the
739 * debugging information at all. If this function returns false, all
740 * printing for this scope is dropped, so gathering the information is
741 * pointless.
742 *
743 * The return value of this function should not be stored, as new clients
744 * may subscribe to the debug scope later.
745 *
746 * If the given scope is NULL, this function will always return false,
747 * making it safe to use in teardown or destroy code, provided the
748 * scope is initialized to NULL before creation and set to NULL after
749 * destruction.
750 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300751 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200752 */
753WL_EXPORT bool
Marius Vlad7e4db952019-04-17 13:47:06 +0300754weston_log_scope_is_enabled(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200755{
756 if (!scope)
757 return false;
758
Marius Vlad7814f302019-06-21 14:20:15 +0300759 return !wl_list_empty(&scope->subscription_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200760}
761
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200762WL_EXPORT void
Marius Vlad7814f302019-06-21 14:20:15 +0300763weston_log_scope_complete(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200764{
Marius Vlad7814f302019-06-21 14:20:15 +0300765 struct weston_log_subscription *sub;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200766
Marius Vlad7814f302019-06-21 14:20:15 +0300767 if (!scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200768 return;
769
Marius Vlad7814f302019-06-21 14:20:15 +0300770 wl_list_for_each(sub, &scope->subscription_list, source_link)
771 if (sub->owner && sub->owner->complete)
772 sub->owner->complete(sub->owner);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200773}
774
Marius Vlad7e4db952019-04-17 13:47:06 +0300775/** Write log data for a scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200776 *
777 * \param scope The debug scope to write for; may be NULL, in which case
778 * nothing will be written.
Marius Vlada2dace22019-06-12 16:05:44 +0300779 * \param[in] data Pointer to the data to write.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200780 * \param len Number of bytes to write.
781 *
782 * Writes the given data to all subscribed clients' streams.
783 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300784 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200785 */
786WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300787weston_log_scope_write(struct weston_log_scope *scope,
788 const char *data, size_t len)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200789{
Marius Vlad7814f302019-06-21 14:20:15 +0300790 struct weston_log_subscription *sub;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200791
792 if (!scope)
793 return;
794
Marius Vlad7814f302019-06-21 14:20:15 +0300795 wl_list_for_each(sub, &scope->subscription_list, source_link)
796 if (sub->owner && sub->owner->write)
797 sub->owner->write(sub->owner, data, len);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200798}
799
800/** Write a formatted string for a scope (varargs)
801 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300802 * \param scope The log scope to write for; may be NULL, in which case
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200803 * nothing will be written.
804 * \param fmt Printf-style format string.
805 * \param ap Formatting arguments.
806 *
807 * Writes to formatted string to all subscribed clients' streams.
808 *
809 * The behavioral details for each stream are the same as for
810 * weston_debug_stream_write().
811 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300812 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200813 */
814WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300815weston_log_scope_vprintf(struct weston_log_scope *scope,
816 const char *fmt, va_list ap)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200817{
818 static const char oom[] = "Out of memory";
819 char *str;
820 int len;
821
Marius Vlad7e4db952019-04-17 13:47:06 +0300822 if (!weston_log_scope_is_enabled(scope))
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200823 return;
824
825 len = vasprintf(&str, fmt, ap);
826 if (len >= 0) {
Marius Vlad7e4db952019-04-17 13:47:06 +0300827 weston_log_scope_write(scope, str, len);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200828 free(str);
829 } else {
Marius Vlad7e4db952019-04-17 13:47:06 +0300830 weston_log_scope_write(scope, oom, sizeof oom - 1);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200831 }
832}
833
834/** Write a formatted string for a scope
835 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300836 * \param scope The log scope to write for; may be NULL, in which case
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200837 * nothing will be written.
838 * \param fmt Printf-style format string and arguments.
839 *
840 * Writes to formatted string to all subscribed clients' streams.
841 *
842 * The behavioral details for each stream are the same as for
843 * weston_debug_stream_write().
844 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300845 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200846 */
847WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300848weston_log_scope_printf(struct weston_log_scope *scope,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200849 const char *fmt, ...)
850{
851 va_list ap;
852
853 va_start(ap, fmt);
Marius Vlad7e4db952019-04-17 13:47:06 +0300854 weston_log_scope_vprintf(scope, fmt, ap);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200855 va_end(ap);
856}
857
858/** Write debug scope name and current time into string
859 *
Marius Vlada2dace22019-06-12 16:05:44 +0300860 * \param[in] scope debug scope; may be NULL
861 * \param[out] buf Buffer to store the string.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200862 * \param len Available size in the buffer in bytes.
863 * \return \c buf
864 *
865 * Reads the current local wall-clock time and formats it into a string.
866 * and append the debug scope name to it, if a scope is available.
867 * The string is NUL-terminated, even if truncated.
868 */
869WL_EXPORT char *
Marius Vlad7e4db952019-04-17 13:47:06 +0300870weston_log_scope_timestamp(struct weston_log_scope *scope,
871 char *buf, size_t len)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200872{
873 struct timeval tv;
874 struct tm *bdt;
875 char string[128];
876 size_t ret = 0;
877
878 gettimeofday(&tv, NULL);
879
880 bdt = localtime(&tv.tv_sec);
881 if (bdt)
882 ret = strftime(string, sizeof string,
883 "%Y-%m-%d %H:%M:%S", bdt);
884
885 if (ret > 0) {
886 snprintf(buf, len, "[%s.%03ld][%s]", string,
887 tv.tv_usec / 1000,
888 (scope) ? scope->name : "no scope");
889 } else {
890 snprintf(buf, len, "[?][%s]",
891 (scope) ? scope->name : "no scope");
892 }
893
894 return buf;
895}