blob: ed41850e8f17db69b9211df0b91707b57f57a5cf [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
Marius Vlad8f329e22019-06-21 14:57:02 +0300243/** Look-up the scope from the scope list stored in the log context, by
244 * matching against the \c name.
245 *
246 * @param log_ctx
247 * @param name the scope name, see weston_compositor_add_log_scope()
248 * @returns NULL if none found, or a pointer to a weston_log_scope
249 *
250 * @internal
251 */
252struct weston_log_scope *
253weston_log_get_scope(struct weston_log_context *log_ctx, const char *name)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200254{
Marius Vlad5d5e3352019-04-17 13:05:38 +0300255 struct weston_log_scope *scope;
Marius Vlad3d7d9782019-04-17 12:35:38 +0300256 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200257 if (strcmp(name, scope->name) == 0)
258 return scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200259 return NULL;
260}
261
Marius Vlad8f329e22019-06-21 14:57:02 +0300262/** Wrapper to invoke the weston_log_scope_cb. Allows to call the begin_cb of
263 * a log scope.
264 *
265 * @internal
266 */
267void
268weston_log_run_begin_cb(struct weston_log_scope *scope)
269{
270 if (scope->begin_cb)
271 scope->begin_cb(scope, scope->user_data);
272}
273
274/** Advertise the log scope name and the log scope description
275 *
276 * This is only used by the weston-debug protocol!
277 *
278 * @internal
279 */
280void
281weston_debug_protocol_advertise_scopes(struct weston_log_context *log_ctx,
282 struct wl_resource *res)
283{
284 struct weston_log_scope *scope;
285 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
286 weston_debug_v1_send_available(res, scope->name, scope->desc);
287}
288
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200289static void
290stream_close_unlink(struct weston_debug_stream *stream)
291{
292 if (stream->fd != -1)
293 close(stream->fd);
294 stream->fd = -1;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200295}
296
297static void WL_PRINTF(2, 3)
298stream_close_on_failure(struct weston_debug_stream *stream,
299 const char *fmt, ...)
300{
301 char *msg;
302 va_list ap;
303 int ret;
304
305 stream_close_unlink(stream);
306
307 va_start(ap, fmt);
308 ret = vasprintf(&msg, fmt, ap);
309 va_end(ap);
310
311 if (ret > 0) {
312 weston_debug_stream_v1_send_failure(stream->resource, msg);
313 free(msg);
314 } else {
315 weston_debug_stream_v1_send_failure(stream->resource,
316 "MEMFAIL");
317 }
318}
319
Marius Vlad7814f302019-06-21 14:20:15 +0300320/** Write data into a specific debug stream
321 *
322 * \param sub The subscriber's stream to write into; must not be NULL.
323 * \param[in] data Pointer to the data to write.
324 * \param len Number of bytes to write.
325 *
326 * Writes the given data (binary verbatim) into the debug stream.
327 * If \c len is zero or negative, the write is silently dropped.
328 *
329 * Writing is continued until all data has been written or
330 * a write fails. If the write fails due to a signal, it is re-tried.
331 * Otherwise on failure, the stream is closed and
332 * \c weston_debug_stream_v1.failure event is sent to the client.
333 *
334 * \memberof weston_debug_stream
335 */
336static void
337weston_debug_stream_write(struct weston_log_subscriber *sub,
338 const char *data, size_t len)
339{
340 ssize_t len_ = len;
341 ssize_t ret;
342 int e;
343 struct weston_debug_stream *stream = to_weston_debug_stream(sub);
344
345 if (stream->fd == -1)
346 return;
347
348 while (len_ > 0) {
349 ret = write(stream->fd, data, len_);
350 e = errno;
351 if (ret < 0) {
352 if (e == EINTR)
353 continue;
354
355 stream_close_on_failure(stream,
356 "Error writing %zd bytes: %s (%d)",
357 len_, strerror(e), e);
358 break;
359 }
360
361 len_ -= ret;
362 data += ret;
363 }
364}
365
366/** Close the debug stream and send success event
367 *
368 * \param sub Subscriber's stream to close.
369 *
370 * Closes the debug stream and sends \c weston_debug_stream_v1.complete
371 * event to the client. This tells the client the debug information dump
372 * is complete.
373 *
374 * \memberof weston_debug_stream
375 */
376static void
377weston_debug_stream_complete(struct weston_log_subscriber *sub)
378{
379 struct weston_debug_stream *stream = to_weston_debug_stream(sub);
380
381 stream_close_unlink(stream);
382 weston_debug_stream_v1_send_complete(stream->resource);
383}
384
385static void
386weston_debug_stream_to_destroy(struct weston_log_subscriber *sub)
387{
388 struct weston_debug_stream *stream = to_weston_debug_stream(sub);
389 stream_close_on_failure(stream, "debug name removed");
390}
391
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200392static struct weston_debug_stream *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300393stream_create(struct weston_log_context *log_ctx, const char *name,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200394 int32_t streamfd, struct wl_resource *stream_resource)
395{
396 struct weston_debug_stream *stream;
Marius Vlad5d5e3352019-04-17 13:05:38 +0300397 struct weston_log_scope *scope;
Marius Vlad7814f302019-06-21 14:20:15 +0300398 struct weston_log_subscription *sub;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200399
400 stream = zalloc(sizeof *stream);
401 if (!stream)
402 return NULL;
403
Marius Vlad7814f302019-06-21 14:20:15 +0300404
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200405 stream->fd = streamfd;
406 stream->resource = stream_resource;
407
Marius Vlad7814f302019-06-21 14:20:15 +0300408 stream->base.write = weston_debug_stream_write;
409 stream->base.destroy = weston_debug_stream_to_destroy;
410 stream->base.complete = weston_debug_stream_complete;
411 wl_list_init(&stream->base.subscription_list);
412
413 sub = weston_log_subscription_create(&stream->base, name);
414
Marius Vlad8f329e22019-06-21 14:57:02 +0300415 scope = weston_log_get_scope(log_ctx, name);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200416 if (scope) {
Marius Vlad7814f302019-06-21 14:20:15 +0300417 weston_log_subscription_add(scope, sub);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200418 if (scope->begin_cb)
Marius Vlad7814f302019-06-21 14:20:15 +0300419 scope->begin_cb(scope, scope->user_data);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200420 } else {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200421 stream_close_on_failure(stream,
422 "Debug stream name '%s' is unknown.",
423 name);
424 }
425
426 return stream;
427}
428
429static void
430stream_destroy(struct wl_resource *stream_resource)
431{
432 struct weston_debug_stream *stream;
Marius Vlad7814f302019-06-21 14:20:15 +0300433 struct weston_log_subscription *sub = NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200434
435 stream = wl_resource_get_user_data(stream_resource);
436
437 if (stream->fd != -1)
438 close(stream->fd);
Marius Vlad7814f302019-06-21 14:20:15 +0300439
440 sub = weston_log_subscriber_get_only_subscription(&stream->base);
441 weston_log_subscription_remove(sub);
442 weston_log_subscription_destroy(sub);
443
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200444 free(stream);
445}
446
447static void
448weston_debug_stream_destroy(struct wl_client *client,
449 struct wl_resource *stream_resource)
450{
451 wl_resource_destroy(stream_resource);
452}
453
454static const struct weston_debug_stream_v1_interface
455 weston_debug_stream_impl = {
456 weston_debug_stream_destroy
457};
458
459static void
460weston_debug_destroy(struct wl_client *client,
461 struct wl_resource *global_resource)
462{
463 wl_resource_destroy(global_resource);
464}
465
466static void
467weston_debug_subscribe(struct wl_client *client,
468 struct wl_resource *global_resource,
469 const char *name,
470 int32_t streamfd,
471 uint32_t new_stream_id)
472{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300473 struct weston_log_context *log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200474 struct wl_resource *stream_resource;
475 uint32_t version;
476 struct weston_debug_stream *stream;
477
Marius Vlad3d7d9782019-04-17 12:35:38 +0300478 log_ctx = wl_resource_get_user_data(global_resource);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200479 version = wl_resource_get_version(global_resource);
480
481 stream_resource = wl_resource_create(client,
482 &weston_debug_stream_v1_interface,
483 version, new_stream_id);
484 if (!stream_resource)
485 goto fail;
486
Marius Vlad3d7d9782019-04-17 12:35:38 +0300487 stream = stream_create(log_ctx, name, streamfd, stream_resource);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200488 if (!stream)
489 goto fail;
490
491 wl_resource_set_implementation(stream_resource,
492 &weston_debug_stream_impl,
493 stream, stream_destroy);
494 return;
495
496fail:
497 close(streamfd);
498 wl_client_post_no_memory(client);
499}
500
501static const struct weston_debug_v1_interface weston_debug_impl = {
502 weston_debug_destroy,
503 weston_debug_subscribe
504};
505
506static void
507bind_weston_debug(struct wl_client *client,
508 void *data, uint32_t version, uint32_t id)
509{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300510 struct weston_log_context *log_ctx = data;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200511 struct wl_resource *resource;
512
513 resource = wl_resource_create(client,
514 &weston_debug_v1_interface,
515 version, id);
516 if (!resource) {
517 wl_client_post_no_memory(client);
518 return;
519 }
520 wl_resource_set_implementation(resource, &weston_debug_impl,
Marius Vlad3d7d9782019-04-17 12:35:38 +0300521 log_ctx, NULL);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200522
Marius Vlad8f329e22019-06-21 14:57:02 +0300523 weston_debug_protocol_advertise_scopes(log_ctx, resource);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200524}
525
Marius Vlad880b4852019-04-07 17:07:58 +0300526/**
Marius Vlad3d7d9782019-04-17 12:35:38 +0300527 * Connect weston_compositor structure to weston_log_context structure.
Marius Vlad880b4852019-04-07 17:07:58 +0300528 *
529 * \param compositor
Marius Vlad3d7d9782019-04-17 12:35:38 +0300530 * \param log_ctx
Marius Vlad880b4852019-04-07 17:07:58 +0300531 * \return 0 on success, -1 on failure
532 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300533 * Sets weston_compositor::weston_log_ctx.
Marius Vlad880b4852019-04-07 17:07:58 +0300534 */
535int
Marius Vlad3d7d9782019-04-17 12:35:38 +0300536weston_log_ctx_compositor_setup(struct weston_compositor *compositor,
537 struct weston_log_context *log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300538{
Marius Vlad6f098662019-04-17 13:50:28 +0300539 assert(!compositor->weston_log_ctx);
540 assert(log_ctx);
Marius Vlad880b4852019-04-07 17:07:58 +0300541
Marius Vlad3d7d9782019-04-17 12:35:38 +0300542 compositor->weston_log_ctx = log_ctx;
Marius Vlad880b4852019-04-07 17:07:58 +0300543 return 0;
544}
545
Marius Vlada2dace22019-06-12 16:05:44 +0300546/** Creates weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200547 *
Marius Vlada2dace22019-06-12 16:05:44 +0300548 * \return NULL in case of failure, or a weston_log_context object in case of
549 * success
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200550 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300551 * weston_log_context is a singleton for each weston_compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200552 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200553 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300554WL_EXPORT struct weston_log_context *
555weston_log_ctx_compositor_create(void)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200556{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300557 struct weston_log_context *log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200558
Marius Vlad3d7d9782019-04-17 12:35:38 +0300559 log_ctx = zalloc(sizeof *log_ctx);
560 if (!log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300561 return NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200562
Marius Vlad3d7d9782019-04-17 12:35:38 +0300563 wl_list_init(&log_ctx->scope_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200564
Marius Vlad3d7d9782019-04-17 12:35:38 +0300565 return log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200566}
567
Marius Vlad3d7d9782019-04-17 12:35:38 +0300568/** Destroy weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200569 *
570 * \param compositor The libweston compositor whose weston-debug to tear down.
571 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300572 * Clears weston_compositor::weston_log_ctx.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200573 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200574 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300575WL_EXPORT void
576weston_log_ctx_compositor_destroy(struct weston_compositor *compositor)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200577{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300578 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
Marius Vlad5d5e3352019-04-17 13:05:38 +0300579 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200580
Marius Vlad3d7d9782019-04-17 12:35:38 +0300581 if (log_ctx->global)
582 wl_global_destroy(log_ctx->global);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200583
Marius Vlad3d7d9782019-04-17 12:35:38 +0300584 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200585 weston_log("Internal warning: debug scope '%s' has not been destroyed.\n",
586 scope->name);
587
588 /* Remove head to not crash if scope removed later. */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300589 wl_list_remove(&log_ctx->scope_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200590
Marius Vlad3d7d9782019-04-17 12:35:38 +0300591 free(log_ctx);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200592
Marius Vlad3d7d9782019-04-17 12:35:38 +0300593 compositor->weston_log_ctx = NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200594}
595
596/** Enable weston-debug protocol extension
597 *
598 * \param compositor The libweston compositor where to enable.
599 *
600 * This enables the weston_debug_v1 Wayland protocol extension which any client
Emmanuel Gil Peyrot426c2462019-02-20 16:33:32 +0100601 * can use to get debug messages from the compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200602 *
603 * WARNING: This feature should not be used in production. If a client
604 * provides a file descriptor that blocks writes, it will block the whole
605 * compositor indefinitely.
606 *
607 * There is no control on which client is allowed to subscribe to debug
608 * messages. Any and all clients are allowed.
609 *
610 * The debug extension is disabled by default, and once enabled, cannot be
611 * disabled again.
612 */
613WL_EXPORT void
614weston_compositor_enable_debug_protocol(struct weston_compositor *compositor)
615{
Marius Vlad1e2fda22019-04-07 19:07:16 +0300616 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
617 assert(log_ctx);
618 if (log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200619 return;
620
Marius Vlad1e2fda22019-04-07 19:07:16 +0300621 log_ctx->global = wl_global_create(compositor->wl_display,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200622 &weston_debug_v1_interface, 1,
Marius Vlad1e2fda22019-04-07 19:07:16 +0300623 log_ctx, bind_weston_debug);
624 if (!log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200625 return;
626
627 weston_log("WARNING: debug protocol has been enabled. "
628 "This is a potential denial-of-service attack vector and "
629 "information leak.\n");
630}
631
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200632/** Determine if the debug protocol has been enabled
633 *
634 * \param wc The libweston compositor to verify if debug protocol has been enabled
635 */
636WL_EXPORT bool
637weston_compositor_is_debug_protocol_enabled(struct weston_compositor *wc)
638{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300639 return wc->weston_log_ctx->global != NULL;
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200640}
641
Marius Vlad7e4db952019-04-17 13:47:06 +0300642/** Register a new debug stream name, creating a log scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200643 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300644 * \param log_ctx The weston_log_context where to add.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200645 * \param name The debug stream/scope name; must not be NULL.
Marius Vlada2dace22019-06-12 16:05:44 +0300646 * \param description The debug scope description for humans; must not be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200647 * \param begin_cb Optional callback when a client subscribes to this scope.
648 * \param user_data Optional user data pointer for the callback.
649 * \return A valid pointer on success, NULL on failure.
650 *
651 * This function is used to create a debug scope. All debug message printing
652 * happens for a scope, which allows clients to subscribe to the kind of
653 * debug messages they want by \c name.
654 *
655 * \c name must be unique in the \c weston_compositor instance. \c name and
656 * \c description must both be provided. The description is printed when a
657 * client asks for a list of supported debug scopes.
658 *
659 * \c begin_cb, if not NULL, is called when a client subscribes to the
660 * debug scope creating a debug stream. This is for debug scopes that need
661 * to print messages as a response to a client appearing, e.g. printing a
662 * list of windows on demand or a static preamble. The argument \c user_data
663 * is passed in to the callback and is otherwise unused.
664 *
665 * For one-shot debug streams, \c begin_cb should finally call
666 * weston_debug_stream_complete() to close the stream and tell the client
667 * the printing is complete. Otherwise the client expects more to be written
668 * to its file descriptor.
669 *
670 * The debug scope must be destroyed before destroying the
671 * \c weston_compositor.
672 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300673 * \memberof weston_log_scope
674 * \sa weston_debug_stream, weston_log_scope_cb
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200675 */
Marius Vlad5d5e3352019-04-17 13:05:38 +0300676WL_EXPORT struct weston_log_scope *
Marius Vlad7e4db952019-04-17 13:47:06 +0300677weston_compositor_add_log_scope(struct weston_log_context *log_ctx,
678 const char *name,
679 const char *description,
680 weston_log_scope_cb begin_cb,
681 void *user_data)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200682{
Marius Vlad5d5e3352019-04-17 13:05:38 +0300683 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200684
Marius Vlad1e2fda22019-04-07 19:07:16 +0300685 if (!name || !description) {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200686 weston_log("Error: cannot add a debug scope without name or description.\n");
687 return NULL;
688 }
689
Marius Vlad3d7d9782019-04-17 12:35:38 +0300690 if (!log_ctx) {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200691 weston_log("Error: cannot add debug scope '%s', infra not initialized.\n",
692 name);
693 return NULL;
694 }
695
Marius Vlad8f329e22019-06-21 14:57:02 +0300696 if (weston_log_get_scope(log_ctx, name)){
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200697 weston_log("Error: debug scope named '%s' is already registered.\n",
698 name);
699 return NULL;
700 }
701
702 scope = zalloc(sizeof *scope);
703 if (!scope) {
704 weston_log("Error adding debug scope '%s': out of memory.\n",
705 name);
706 return NULL;
707 }
708
709 scope->name = strdup(name);
710 scope->desc = strdup(description);
711 scope->begin_cb = begin_cb;
712 scope->user_data = user_data;
Marius Vlad7814f302019-06-21 14:20:15 +0300713 wl_list_init(&scope->subscription_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200714
715 if (!scope->name || !scope->desc) {
716 weston_log("Error adding debug scope '%s': out of memory.\n",
717 name);
718 free(scope->name);
719 free(scope->desc);
720 free(scope);
721 return NULL;
722 }
723
Marius Vlad3d7d9782019-04-17 12:35:38 +0300724 wl_list_insert(log_ctx->scope_list.prev, &scope->compositor_link);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200725
726 return scope;
727}
728
Marius Vlad3d7d9782019-04-17 12:35:38 +0300729/** Destroy a log scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200730 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300731 * \param scope The log scope to destroy; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200732 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300733 * Destroys the log scope, closing all open streams subscribed to it and
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200734 * sending them each a \c weston_debug_stream_v1.failure event.
735 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300736 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200737 */
738WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300739weston_compositor_log_scope_destroy(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200740{
Marius Vlad7814f302019-06-21 14:20:15 +0300741 struct weston_log_subscription *sub, *sub_tmp;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200742
743 if (!scope)
744 return;
745
Marius Vlad7814f302019-06-21 14:20:15 +0300746 wl_list_for_each_safe(sub, sub_tmp, &scope->subscription_list, source_link) {
747 /* destroy each subscription */
748 if (sub->owner->destroy)
749 sub->owner->destroy(sub->owner);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200750
Marius Vlad7814f302019-06-21 14:20:15 +0300751 weston_log_subscription_remove(sub);
752 weston_log_subscription_destroy(sub);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200753 }
754
755 wl_list_remove(&scope->compositor_link);
756 free(scope->name);
757 free(scope->desc);
758 free(scope);
759}
760
761/** Are there any active subscriptions to the scope?
762 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300763 * \param scope The log scope to check; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200764 * \return True if any streams are open for this scope, false otherwise.
765 *
766 * As printing some debugging messages may be relatively expensive, one
767 * can use this function to determine if there is a need to gather the
768 * debugging information at all. If this function returns false, all
769 * printing for this scope is dropped, so gathering the information is
770 * pointless.
771 *
772 * The return value of this function should not be stored, as new clients
773 * may subscribe to the debug scope later.
774 *
775 * If the given scope is NULL, this function will always return false,
776 * making it safe to use in teardown or destroy code, provided the
777 * scope is initialized to NULL before creation and set to NULL after
778 * destruction.
779 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300780 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200781 */
782WL_EXPORT bool
Marius Vlad7e4db952019-04-17 13:47:06 +0300783weston_log_scope_is_enabled(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200784{
785 if (!scope)
786 return false;
787
Marius Vlad7814f302019-06-21 14:20:15 +0300788 return !wl_list_empty(&scope->subscription_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200789}
790
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200791WL_EXPORT void
Marius Vlad7814f302019-06-21 14:20:15 +0300792weston_log_scope_complete(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200793{
Marius Vlad7814f302019-06-21 14:20:15 +0300794 struct weston_log_subscription *sub;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200795
Marius Vlad7814f302019-06-21 14:20:15 +0300796 if (!scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200797 return;
798
Marius Vlad7814f302019-06-21 14:20:15 +0300799 wl_list_for_each(sub, &scope->subscription_list, source_link)
800 if (sub->owner && sub->owner->complete)
801 sub->owner->complete(sub->owner);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200802}
803
Marius Vlad7e4db952019-04-17 13:47:06 +0300804/** Write log data for a scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200805 *
806 * \param scope The debug scope to write for; may be NULL, in which case
807 * nothing will be written.
Marius Vlada2dace22019-06-12 16:05:44 +0300808 * \param[in] data Pointer to the data to write.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200809 * \param len Number of bytes to write.
810 *
811 * Writes the given data to all subscribed clients' streams.
812 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300813 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200814 */
815WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300816weston_log_scope_write(struct weston_log_scope *scope,
817 const char *data, size_t len)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200818{
Marius Vlad7814f302019-06-21 14:20:15 +0300819 struct weston_log_subscription *sub;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200820
821 if (!scope)
822 return;
823
Marius Vlad7814f302019-06-21 14:20:15 +0300824 wl_list_for_each(sub, &scope->subscription_list, source_link)
825 if (sub->owner && sub->owner->write)
826 sub->owner->write(sub->owner, data, len);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200827}
828
829/** Write a formatted string for a scope (varargs)
830 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300831 * \param scope The log scope to write for; may be NULL, in which case
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200832 * nothing will be written.
833 * \param fmt Printf-style format string.
834 * \param ap Formatting arguments.
835 *
836 * Writes to formatted string to all subscribed clients' streams.
837 *
838 * The behavioral details for each stream are the same as for
839 * weston_debug_stream_write().
840 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300841 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200842 */
843WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300844weston_log_scope_vprintf(struct weston_log_scope *scope,
845 const char *fmt, va_list ap)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200846{
847 static const char oom[] = "Out of memory";
848 char *str;
849 int len;
850
Marius Vlad7e4db952019-04-17 13:47:06 +0300851 if (!weston_log_scope_is_enabled(scope))
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200852 return;
853
854 len = vasprintf(&str, fmt, ap);
855 if (len >= 0) {
Marius Vlad7e4db952019-04-17 13:47:06 +0300856 weston_log_scope_write(scope, str, len);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200857 free(str);
858 } else {
Marius Vlad7e4db952019-04-17 13:47:06 +0300859 weston_log_scope_write(scope, oom, sizeof oom - 1);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200860 }
861}
862
863/** Write a formatted string for a scope
864 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300865 * \param scope The log scope to write for; may be NULL, in which case
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200866 * nothing will be written.
867 * \param fmt Printf-style format string and arguments.
868 *
869 * Writes to formatted string to all subscribed clients' streams.
870 *
871 * The behavioral details for each stream are the same as for
872 * weston_debug_stream_write().
873 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300874 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200875 */
876WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300877weston_log_scope_printf(struct weston_log_scope *scope,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200878 const char *fmt, ...)
879{
880 va_list ap;
881
882 va_start(ap, fmt);
Marius Vlad7e4db952019-04-17 13:47:06 +0300883 weston_log_scope_vprintf(scope, fmt, ap);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200884 va_end(ap);
885}
886
887/** Write debug scope name and current time into string
888 *
Marius Vlada2dace22019-06-12 16:05:44 +0300889 * \param[in] scope debug scope; may be NULL
890 * \param[out] buf Buffer to store the string.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200891 * \param len Available size in the buffer in bytes.
892 * \return \c buf
893 *
894 * Reads the current local wall-clock time and formats it into a string.
895 * and append the debug scope name to it, if a scope is available.
896 * The string is NUL-terminated, even if truncated.
897 */
898WL_EXPORT char *
Marius Vlad7e4db952019-04-17 13:47:06 +0300899weston_log_scope_timestamp(struct weston_log_scope *scope,
900 char *buf, size_t len)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200901{
902 struct timeval tv;
903 struct tm *bdt;
904 char string[128];
905 size_t ret = 0;
906
907 gettimeofday(&tv, NULL);
908
909 bdt = localtime(&tv.tv_sec);
910 if (bdt)
911 ret = strftime(string, sizeof string,
912 "%Y-%m-%d %H:%M:%S", bdt);
913
914 if (ret > 0) {
915 snprintf(buf, len, "[%s.%03ld][%s]", string,
916 tv.tv_usec / 1000,
917 (scope) ? scope->name : "no scope");
918 } else {
919 snprintf(buf, len, "[?][%s]",
920 (scope) ? scope->name : "no scope");
921 }
922
923 return buf;
924}