blob: 3534953e1b2213bb5778f5e233c151d18306c7b2 [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
29#include "weston-debug.h"
30#include "helpers.h"
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020031#include <libweston/libweston.h>
Pekka Paalanena5630ea2017-10-12 13:13:42 +020032
33#include "weston-debug-server-protocol.h"
34
35#include <assert.h>
36#include <unistd.h>
37#include <stdarg.h>
38#include <string.h>
39#include <errno.h>
40#include <sys/time.h>
41
Marius Vlad3d7d9782019-04-17 12:35:38 +030042/** Main weston-log context
Pekka Paalanena5630ea2017-10-12 13:13:42 +020043 *
44 * One per weston_compositor.
45 *
46 * \internal
47 */
Marius Vlad3d7d9782019-04-17 12:35:38 +030048struct weston_log_context {
Pekka Paalanena5630ea2017-10-12 13:13:42 +020049 struct weston_compositor *compositor;
50 struct wl_listener compositor_destroy_listener;
51 struct wl_global *global;
52 struct wl_list scope_list; /**< weston_debug_scope::compositor_link */
53};
54
55/** weston-debug message scope
56 *
57 * This is used for scoping debugging messages. Clients can subscribe to
58 * only the scopes they are interested in. A scope is identified by its name
59 * (also referred to as debug stream name).
60 */
61struct weston_debug_scope {
62 char *name;
63 char *desc;
64 weston_debug_scope_cb begin_cb;
65 void *user_data;
66 struct wl_list stream_list; /**< weston_debug_stream::scope_link */
67 struct wl_list compositor_link;
68};
69
70/** A debug stream created by a client
71 *
72 * A client provides a file descriptor for the server to write debug
73 * messages into. A weston_debug_stream is associated to one
74 * weston_debug_scope via the scope name, and the scope provides the messages.
75 * There can be several streams for the same scope, all streams getting the
76 * same messages.
77 */
78struct weston_debug_stream {
79 int fd; /**< client provided fd */
80 struct wl_resource *resource; /**< weston_debug_stream_v1 object */
81 struct wl_list scope_link;
82};
83
84static struct weston_debug_scope *
Marius Vlad3d7d9782019-04-17 12:35:38 +030085get_scope(struct weston_log_context *log_ctx, const char *name)
Pekka Paalanena5630ea2017-10-12 13:13:42 +020086{
87 struct weston_debug_scope *scope;
88
Marius Vlad3d7d9782019-04-17 12:35:38 +030089 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Pekka Paalanena5630ea2017-10-12 13:13:42 +020090 if (strcmp(name, scope->name) == 0)
91 return scope;
92
93 return NULL;
94}
95
96static void
97stream_close_unlink(struct weston_debug_stream *stream)
98{
99 if (stream->fd != -1)
100 close(stream->fd);
101 stream->fd = -1;
102
103 wl_list_remove(&stream->scope_link);
104 wl_list_init(&stream->scope_link);
105}
106
107static void WL_PRINTF(2, 3)
108stream_close_on_failure(struct weston_debug_stream *stream,
109 const char *fmt, ...)
110{
111 char *msg;
112 va_list ap;
113 int ret;
114
115 stream_close_unlink(stream);
116
117 va_start(ap, fmt);
118 ret = vasprintf(&msg, fmt, ap);
119 va_end(ap);
120
121 if (ret > 0) {
122 weston_debug_stream_v1_send_failure(stream->resource, msg);
123 free(msg);
124 } else {
125 weston_debug_stream_v1_send_failure(stream->resource,
126 "MEMFAIL");
127 }
128}
129
130static struct weston_debug_stream *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300131stream_create(struct weston_log_context *log_ctx, const char *name,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200132 int32_t streamfd, struct wl_resource *stream_resource)
133{
134 struct weston_debug_stream *stream;
135 struct weston_debug_scope *scope;
136
137 stream = zalloc(sizeof *stream);
138 if (!stream)
139 return NULL;
140
141 stream->fd = streamfd;
142 stream->resource = stream_resource;
143
Marius Vlad3d7d9782019-04-17 12:35:38 +0300144 scope = get_scope(log_ctx, name);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200145 if (scope) {
146 wl_list_insert(&scope->stream_list, &stream->scope_link);
147
148 if (scope->begin_cb)
149 scope->begin_cb(stream, scope->user_data);
150 } else {
151 wl_list_init(&stream->scope_link);
152 stream_close_on_failure(stream,
153 "Debug stream name '%s' is unknown.",
154 name);
155 }
156
157 return stream;
158}
159
160static void
161stream_destroy(struct wl_resource *stream_resource)
162{
163 struct weston_debug_stream *stream;
164
165 stream = wl_resource_get_user_data(stream_resource);
166
167 if (stream->fd != -1)
168 close(stream->fd);
169 wl_list_remove(&stream->scope_link);
170 free(stream);
171}
172
173static void
174weston_debug_stream_destroy(struct wl_client *client,
175 struct wl_resource *stream_resource)
176{
177 wl_resource_destroy(stream_resource);
178}
179
180static const struct weston_debug_stream_v1_interface
181 weston_debug_stream_impl = {
182 weston_debug_stream_destroy
183};
184
185static void
186weston_debug_destroy(struct wl_client *client,
187 struct wl_resource *global_resource)
188{
189 wl_resource_destroy(global_resource);
190}
191
192static void
193weston_debug_subscribe(struct wl_client *client,
194 struct wl_resource *global_resource,
195 const char *name,
196 int32_t streamfd,
197 uint32_t new_stream_id)
198{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300199 struct weston_log_context *log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200200 struct wl_resource *stream_resource;
201 uint32_t version;
202 struct weston_debug_stream *stream;
203
Marius Vlad3d7d9782019-04-17 12:35:38 +0300204 log_ctx = wl_resource_get_user_data(global_resource);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200205 version = wl_resource_get_version(global_resource);
206
207 stream_resource = wl_resource_create(client,
208 &weston_debug_stream_v1_interface,
209 version, new_stream_id);
210 if (!stream_resource)
211 goto fail;
212
Marius Vlad3d7d9782019-04-17 12:35:38 +0300213 stream = stream_create(log_ctx, name, streamfd, stream_resource);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200214 if (!stream)
215 goto fail;
216
217 wl_resource_set_implementation(stream_resource,
218 &weston_debug_stream_impl,
219 stream, stream_destroy);
220 return;
221
222fail:
223 close(streamfd);
224 wl_client_post_no_memory(client);
225}
226
227static const struct weston_debug_v1_interface weston_debug_impl = {
228 weston_debug_destroy,
229 weston_debug_subscribe
230};
231
232static void
233bind_weston_debug(struct wl_client *client,
234 void *data, uint32_t version, uint32_t id)
235{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300236 struct weston_log_context *log_ctx = data;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200237 struct weston_debug_scope *scope;
238 struct wl_resource *resource;
239
240 resource = wl_resource_create(client,
241 &weston_debug_v1_interface,
242 version, id);
243 if (!resource) {
244 wl_client_post_no_memory(client);
245 return;
246 }
247 wl_resource_set_implementation(resource, &weston_debug_impl,
Marius Vlad3d7d9782019-04-17 12:35:38 +0300248 log_ctx, NULL);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200249
Marius Vlad3d7d9782019-04-17 12:35:38 +0300250 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link) {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200251 weston_debug_v1_send_available(resource, scope->name,
252 scope->desc);
253 }
254}
255
Marius Vlad880b4852019-04-07 17:07:58 +0300256/**
Marius Vlad3d7d9782019-04-17 12:35:38 +0300257 * Connect weston_compositor structure to weston_log_context structure.
Marius Vlad880b4852019-04-07 17:07:58 +0300258 *
259 * \param compositor
Marius Vlad3d7d9782019-04-17 12:35:38 +0300260 * \param log_ctx
Marius Vlad880b4852019-04-07 17:07:58 +0300261 * \return 0 on success, -1 on failure
262 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300263 * Sets weston_compositor::weston_log_ctx.
Marius Vlad880b4852019-04-07 17:07:58 +0300264 */
265int
Marius Vlad3d7d9782019-04-17 12:35:38 +0300266weston_log_ctx_compositor_setup(struct weston_compositor *compositor,
267 struct weston_log_context *log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300268{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300269 if (compositor->weston_log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300270 return -1;
271
Marius Vlad3d7d9782019-04-17 12:35:38 +0300272 log_ctx->compositor = compositor;
273 compositor->weston_log_ctx = log_ctx;
Marius Vlad880b4852019-04-07 17:07:58 +0300274
275 return 0;
276}
277
Marius Vlad3d7d9782019-04-17 12:35:38 +0300278/** Initialize weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200279 *
280 * \param compositor The libweston compositor.
281 * \return 0 on success, -1 on failure.
282 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300283 * weston_log_context is a singleton for each weston_compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200284 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200285 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300286WL_EXPORT struct weston_log_context *
287weston_log_ctx_compositor_create(void)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200288{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300289 struct weston_log_context *log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200290
Marius Vlad3d7d9782019-04-17 12:35:38 +0300291 log_ctx = zalloc(sizeof *log_ctx);
292 if (!log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300293 return NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200294
Marius Vlad3d7d9782019-04-17 12:35:38 +0300295 wl_list_init(&log_ctx->scope_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200296
Marius Vlad3d7d9782019-04-17 12:35:38 +0300297 return log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200298}
299
Marius Vlad3d7d9782019-04-17 12:35:38 +0300300/** Destroy weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200301 *
302 * \param compositor The libweston compositor whose weston-debug to tear down.
303 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300304 * Clears weston_compositor::weston_log_ctx.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200305 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200306 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300307WL_EXPORT void
308weston_log_ctx_compositor_destroy(struct weston_compositor *compositor)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200309{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300310 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200311 struct weston_debug_scope *scope;
312
Marius Vlad3d7d9782019-04-17 12:35:38 +0300313 if (log_ctx->global)
314 wl_global_destroy(log_ctx->global);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200315
Marius Vlad3d7d9782019-04-17 12:35:38 +0300316 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200317 weston_log("Internal warning: debug scope '%s' has not been destroyed.\n",
318 scope->name);
319
320 /* Remove head to not crash if scope removed later. */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300321 wl_list_remove(&log_ctx->scope_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200322
Marius Vlad3d7d9782019-04-17 12:35:38 +0300323 free(log_ctx);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200324
Marius Vlad3d7d9782019-04-17 12:35:38 +0300325 compositor->weston_log_ctx = NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200326}
327
328/** Enable weston-debug protocol extension
329 *
330 * \param compositor The libweston compositor where to enable.
331 *
332 * This enables the weston_debug_v1 Wayland protocol extension which any client
Emmanuel Gil Peyrot426c2462019-02-20 16:33:32 +0100333 * can use to get debug messages from the compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200334 *
335 * WARNING: This feature should not be used in production. If a client
336 * provides a file descriptor that blocks writes, it will block the whole
337 * compositor indefinitely.
338 *
339 * There is no control on which client is allowed to subscribe to debug
340 * messages. Any and all clients are allowed.
341 *
342 * The debug extension is disabled by default, and once enabled, cannot be
343 * disabled again.
344 */
345WL_EXPORT void
346weston_compositor_enable_debug_protocol(struct weston_compositor *compositor)
347{
Marius Vlad1e2fda22019-04-07 19:07:16 +0300348 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
349 assert(log_ctx);
350 if (log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200351 return;
352
Marius Vlad1e2fda22019-04-07 19:07:16 +0300353 log_ctx->global = wl_global_create(compositor->wl_display,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200354 &weston_debug_v1_interface, 1,
Marius Vlad1e2fda22019-04-07 19:07:16 +0300355 log_ctx, bind_weston_debug);
356 if (!log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200357 return;
358
359 weston_log("WARNING: debug protocol has been enabled. "
360 "This is a potential denial-of-service attack vector and "
361 "information leak.\n");
362}
363
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200364/** Determine if the debug protocol has been enabled
365 *
366 * \param wc The libweston compositor to verify if debug protocol has been enabled
367 */
368WL_EXPORT bool
369weston_compositor_is_debug_protocol_enabled(struct weston_compositor *wc)
370{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300371 return wc->weston_log_ctx->global != NULL;
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200372}
373
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200374/** Register a new debug stream name, creating a debug scope
375 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300376 * \param log_ctx The weston_log_context where to add.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200377 * \param name The debug stream/scope name; must not be NULL.
378 * \param desc The debug scope description for humans; must not be NULL.
379 * \param begin_cb Optional callback when a client subscribes to this scope.
380 * \param user_data Optional user data pointer for the callback.
381 * \return A valid pointer on success, NULL on failure.
382 *
383 * This function is used to create a debug scope. All debug message printing
384 * happens for a scope, which allows clients to subscribe to the kind of
385 * debug messages they want by \c name.
386 *
387 * \c name must be unique in the \c weston_compositor instance. \c name and
388 * \c description must both be provided. The description is printed when a
389 * client asks for a list of supported debug scopes.
390 *
391 * \c begin_cb, if not NULL, is called when a client subscribes to the
392 * debug scope creating a debug stream. This is for debug scopes that need
393 * to print messages as a response to a client appearing, e.g. printing a
394 * list of windows on demand or a static preamble. The argument \c user_data
395 * is passed in to the callback and is otherwise unused.
396 *
397 * For one-shot debug streams, \c begin_cb should finally call
398 * weston_debug_stream_complete() to close the stream and tell the client
399 * the printing is complete. Otherwise the client expects more to be written
400 * to its file descriptor.
401 *
402 * The debug scope must be destroyed before destroying the
403 * \c weston_compositor.
404 *
405 * \memberof weston_debug_scope
406 * \sa weston_debug_stream, weston_debug_scope_cb
407 */
408WL_EXPORT struct weston_debug_scope *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300409weston_compositor_add_debug_scope(struct weston_log_context *log_ctx,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200410 const char *name,
411 const char *description,
412 weston_debug_scope_cb begin_cb,
413 void *user_data)
414{
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200415 struct weston_debug_scope *scope;
416
Marius Vlad1e2fda22019-04-07 19:07:16 +0300417 if (!name || !description) {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200418 weston_log("Error: cannot add a debug scope without name or description.\n");
419 return NULL;
420 }
421
Marius Vlad3d7d9782019-04-17 12:35:38 +0300422 if (!log_ctx) {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200423 weston_log("Error: cannot add debug scope '%s', infra not initialized.\n",
424 name);
425 return NULL;
426 }
427
Marius Vlad3d7d9782019-04-17 12:35:38 +0300428 if (get_scope(log_ctx, name)){
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200429 weston_log("Error: debug scope named '%s' is already registered.\n",
430 name);
431 return NULL;
432 }
433
434 scope = zalloc(sizeof *scope);
435 if (!scope) {
436 weston_log("Error adding debug scope '%s': out of memory.\n",
437 name);
438 return NULL;
439 }
440
441 scope->name = strdup(name);
442 scope->desc = strdup(description);
443 scope->begin_cb = begin_cb;
444 scope->user_data = user_data;
445 wl_list_init(&scope->stream_list);
446
447 if (!scope->name || !scope->desc) {
448 weston_log("Error adding debug scope '%s': out of memory.\n",
449 name);
450 free(scope->name);
451 free(scope->desc);
452 free(scope);
453 return NULL;
454 }
455
Marius Vlad3d7d9782019-04-17 12:35:38 +0300456 wl_list_insert(log_ctx->scope_list.prev, &scope->compositor_link);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200457
458 return scope;
459}
460
Marius Vlad3d7d9782019-04-17 12:35:38 +0300461/** Destroy a log scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200462 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300463 * \param scope The log scope to destroy; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200464 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300465 * Destroys the log scope, closing all open streams subscribed to it and
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200466 * sending them each a \c weston_debug_stream_v1.failure event.
467 *
468 * \memberof weston_debug_scope
469 */
470WL_EXPORT void
471weston_debug_scope_destroy(struct weston_debug_scope *scope)
472{
473 struct weston_debug_stream *stream;
474
475 if (!scope)
476 return;
477
478 while (!wl_list_empty(&scope->stream_list)) {
479 stream = wl_container_of(scope->stream_list.prev,
480 stream, scope_link);
481
482 stream_close_on_failure(stream, "debug name removed");
483 }
484
485 wl_list_remove(&scope->compositor_link);
486 free(scope->name);
487 free(scope->desc);
488 free(scope);
489}
490
491/** Are there any active subscriptions to the scope?
492 *
493 * \param scope The debug scope to check; may be NULL.
494 * \return True if any streams are open for this scope, false otherwise.
495 *
496 * As printing some debugging messages may be relatively expensive, one
497 * can use this function to determine if there is a need to gather the
498 * debugging information at all. If this function returns false, all
499 * printing for this scope is dropped, so gathering the information is
500 * pointless.
501 *
502 * The return value of this function should not be stored, as new clients
503 * may subscribe to the debug scope later.
504 *
505 * If the given scope is NULL, this function will always return false,
506 * making it safe to use in teardown or destroy code, provided the
507 * scope is initialized to NULL before creation and set to NULL after
508 * destruction.
509 *
510 * \memberof weston_debug_scope
511 */
512WL_EXPORT bool
513weston_debug_scope_is_enabled(struct weston_debug_scope *scope)
514{
515 if (!scope)
516 return false;
517
518 return !wl_list_empty(&scope->stream_list);
519}
520
521/** Write data into a specific debug stream
522 *
523 * \param stream The debug stream to write into; must not be NULL.
524 * \param data[in] Pointer to the data to write.
525 * \param len Number of bytes to write.
526 *
527 * Writes the given data (binary verbatim) into the debug stream.
528 * If \c len is zero or negative, the write is silently dropped.
529 *
530 * Writing is continued until all data has been written or
531 * a write fails. If the write fails due to a signal, it is re-tried.
532 * Otherwise on failure, the stream is closed and
533 * \c weston_debug_stream_v1.failure event is sent to the client.
534 *
535 * \memberof weston_debug_stream
536 */
537WL_EXPORT void
538weston_debug_stream_write(struct weston_debug_stream *stream,
539 const char *data, size_t len)
540{
541 ssize_t len_ = len;
542 ssize_t ret;
543 int e;
544
545 if (stream->fd == -1)
546 return;
547
548 while (len_ > 0) {
549 ret = write(stream->fd, data, len_);
550 e = errno;
551 if (ret < 0) {
552 if (e == EINTR)
553 continue;
554
555 stream_close_on_failure(stream,
556 "Error writing %zd bytes: %s (%d)",
557 len_, strerror(e), e);
558 break;
559 }
560
561 len_ -= ret;
562 data += ret;
563 }
564}
565
566/** Write a formatted string into a specific debug stream (varargs)
567 *
568 * \param stream The debug stream to write into.
569 * \param fmt Printf-style format string.
570 * \param ap Formatting arguments.
571 *
572 * The behavioral details are the same as for weston_debug_stream_write().
573 *
574 * \memberof weston_debug_stream
575 */
576WL_EXPORT void
577weston_debug_stream_vprintf(struct weston_debug_stream *stream,
578 const char *fmt, va_list ap)
579{
580 char *str;
581 int len;
582
583 len = vasprintf(&str, fmt, ap);
584 if (len >= 0) {
585 weston_debug_stream_write(stream, str, len);
586 free(str);
587 } else {
588 stream_close_on_failure(stream, "Out of memory");
589 }
590}
591
592/** Write a formatted string into a specific debug stream
593 *
594 * \param stream The debug stream to write into.
595 * \param fmt Printf-style format string and arguments.
596 *
597 * The behavioral details are the same as for weston_debug_stream_write().
598 *
599 * \memberof weston_debug_stream
600 */
601WL_EXPORT void
602weston_debug_stream_printf(struct weston_debug_stream *stream,
603 const char *fmt, ...)
604{
605 va_list ap;
606
607 va_start(ap, fmt);
608 weston_debug_stream_vprintf(stream, fmt, ap);
609 va_end(ap);
610}
611
612/** Close the debug stream and send success event
613 *
614 * \param stream The debug stream to close.
615 *
616 * Closes the debug stream and sends \c weston_debug_stream_v1.complete
617 * event to the client. This tells the client the debug information dump
618 * is complete.
619 *
620 * \memberof weston_debug_stream
621 */
622WL_EXPORT void
623weston_debug_stream_complete(struct weston_debug_stream *stream)
624{
625 stream_close_unlink(stream);
626 weston_debug_stream_v1_send_complete(stream->resource);
627}
628
629/** Write debug data for a scope
630 *
631 * \param scope The debug scope to write for; may be NULL, in which case
632 * nothing will be written.
633 * \param data[in] Pointer to the data to write.
634 * \param len Number of bytes to write.
635 *
636 * Writes the given data to all subscribed clients' streams.
637 *
638 * The behavioral details for each stream are the same as for
639 * weston_debug_stream_write().
640 *
641 * \memberof weston_debug_scope
642 */
643WL_EXPORT void
644weston_debug_scope_write(struct weston_debug_scope *scope,
645 const char *data, size_t len)
646{
647 struct weston_debug_stream *stream;
648
649 if (!scope)
650 return;
651
652 wl_list_for_each(stream, &scope->stream_list, scope_link)
653 weston_debug_stream_write(stream, data, len);
654}
655
656/** Write a formatted string for a scope (varargs)
657 *
658 * \param scope The debug scope to write for; may be NULL, in which case
659 * nothing will be written.
660 * \param fmt Printf-style format string.
661 * \param ap Formatting arguments.
662 *
663 * Writes to formatted string to all subscribed clients' streams.
664 *
665 * The behavioral details for each stream are the same as for
666 * weston_debug_stream_write().
667 *
668 * \memberof weston_debug_scope
669 */
670WL_EXPORT void
671weston_debug_scope_vprintf(struct weston_debug_scope *scope,
672 const char *fmt, va_list ap)
673{
674 static const char oom[] = "Out of memory";
675 char *str;
676 int len;
677
678 if (!weston_debug_scope_is_enabled(scope))
679 return;
680
681 len = vasprintf(&str, fmt, ap);
682 if (len >= 0) {
683 weston_debug_scope_write(scope, str, len);
684 free(str);
685 } else {
686 weston_debug_scope_write(scope, oom, sizeof oom - 1);
687 }
688}
689
690/** Write a formatted string for a scope
691 *
692 * \param scope The debug scope to write for; may be NULL, in which case
693 * nothing will be written.
694 * \param fmt Printf-style format string and arguments.
695 *
696 * Writes to formatted string to all subscribed clients' streams.
697 *
698 * The behavioral details for each stream are the same as for
699 * weston_debug_stream_write().
700 *
701 * \memberof weston_debug_scope
702 */
703WL_EXPORT void
704weston_debug_scope_printf(struct weston_debug_scope *scope,
705 const char *fmt, ...)
706{
707 va_list ap;
708
709 va_start(ap, fmt);
710 weston_debug_scope_vprintf(scope, fmt, ap);
711 va_end(ap);
712}
713
714/** Write debug scope name and current time into string
715 *
716 * \param scope[in] debug scope; may be NULL
717 * \param buf[out] Buffer to store the string.
718 * \param len Available size in the buffer in bytes.
719 * \return \c buf
720 *
721 * Reads the current local wall-clock time and formats it into a string.
722 * and append the debug scope name to it, if a scope is available.
723 * The string is NUL-terminated, even if truncated.
724 */
725WL_EXPORT char *
726weston_debug_scope_timestamp(struct weston_debug_scope *scope,
727 char *buf, size_t len)
728{
729 struct timeval tv;
730 struct tm *bdt;
731 char string[128];
732 size_t ret = 0;
733
734 gettimeofday(&tv, NULL);
735
736 bdt = localtime(&tv.tv_sec);
737 if (bdt)
738 ret = strftime(string, sizeof string,
739 "%Y-%m-%d %H:%M:%S", bdt);
740
741 if (ret > 0) {
742 snprintf(buf, len, "[%s.%03ld][%s]", string,
743 tv.tv_usec / 1000,
744 (scope) ? scope->name : "no scope");
745 } else {
746 snprintf(buf, len, "[?][%s]",
747 (scope) ? scope->name : "no scope");
748 }
749
750 return buf;
751}