blob: 5f5053460347c9edea8cb33fbef43df1c843940b [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
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 wl_listener compositor_destroy_listener;
50 struct wl_global *global;
Marius Vlad5d5e3352019-04-17 13:05:38 +030051 struct wl_list scope_list; /**< weston_log_scope::compositor_link */
Pekka Paalanena5630ea2017-10-12 13:13:42 +020052};
53
Marius Vlad5d5e3352019-04-17 13:05:38 +030054/** weston-log message scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +020055 *
Marius Vlad7e4db952019-04-17 13:47:06 +030056 * This is used for scoping logging/debugging messages. Clients can subscribe
57 * to only the scopes they are interested in. A scope is identified by its name
Pekka Paalanena5630ea2017-10-12 13:13:42 +020058 * (also referred to as debug stream name).
59 */
Marius Vlad5d5e3352019-04-17 13:05:38 +030060struct weston_log_scope {
Pekka Paalanena5630ea2017-10-12 13:13:42 +020061 char *name;
62 char *desc;
Marius Vlad5d5e3352019-04-17 13:05:38 +030063 weston_log_scope_cb begin_cb;
Pekka Paalanena5630ea2017-10-12 13:13:42 +020064 void *user_data;
65 struct wl_list stream_list; /**< weston_debug_stream::scope_link */
66 struct wl_list compositor_link;
67};
68
69/** A debug stream created by a client
70 *
71 * A client provides a file descriptor for the server to write debug
72 * messages into. A weston_debug_stream is associated to one
Marius Vlad5d5e3352019-04-17 13:05:38 +030073 * weston_log_scope via the scope name, and the scope provides the messages.
Pekka Paalanena5630ea2017-10-12 13:13:42 +020074 * There can be several streams for the same scope, all streams getting the
75 * same messages.
76 */
77struct weston_debug_stream {
78 int fd; /**< client provided fd */
79 struct wl_resource *resource; /**< weston_debug_stream_v1 object */
80 struct wl_list scope_link;
81};
82
Marius Vlad5d5e3352019-04-17 13:05:38 +030083static struct weston_log_scope *
Marius Vlad3d7d9782019-04-17 12:35:38 +030084get_scope(struct weston_log_context *log_ctx, const char *name)
Pekka Paalanena5630ea2017-10-12 13:13:42 +020085{
Marius Vlad5d5e3352019-04-17 13:05:38 +030086 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +020087
Marius Vlad3d7d9782019-04-17 12:35:38 +030088 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Pekka Paalanena5630ea2017-10-12 13:13:42 +020089 if (strcmp(name, scope->name) == 0)
90 return scope;
91
92 return NULL;
93}
94
95static void
96stream_close_unlink(struct weston_debug_stream *stream)
97{
98 if (stream->fd != -1)
99 close(stream->fd);
100 stream->fd = -1;
101
102 wl_list_remove(&stream->scope_link);
103 wl_list_init(&stream->scope_link);
104}
105
106static void WL_PRINTF(2, 3)
107stream_close_on_failure(struct weston_debug_stream *stream,
108 const char *fmt, ...)
109{
110 char *msg;
111 va_list ap;
112 int ret;
113
114 stream_close_unlink(stream);
115
116 va_start(ap, fmt);
117 ret = vasprintf(&msg, fmt, ap);
118 va_end(ap);
119
120 if (ret > 0) {
121 weston_debug_stream_v1_send_failure(stream->resource, msg);
122 free(msg);
123 } else {
124 weston_debug_stream_v1_send_failure(stream->resource,
125 "MEMFAIL");
126 }
127}
128
129static struct weston_debug_stream *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300130stream_create(struct weston_log_context *log_ctx, const char *name,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200131 int32_t streamfd, struct wl_resource *stream_resource)
132{
133 struct weston_debug_stream *stream;
Marius Vlad5d5e3352019-04-17 13:05:38 +0300134 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200135
136 stream = zalloc(sizeof *stream);
137 if (!stream)
138 return NULL;
139
140 stream->fd = streamfd;
141 stream->resource = stream_resource;
142
Marius Vlad3d7d9782019-04-17 12:35:38 +0300143 scope = get_scope(log_ctx, name);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200144 if (scope) {
145 wl_list_insert(&scope->stream_list, &stream->scope_link);
146
147 if (scope->begin_cb)
148 scope->begin_cb(stream, scope->user_data);
149 } else {
150 wl_list_init(&stream->scope_link);
151 stream_close_on_failure(stream,
152 "Debug stream name '%s' is unknown.",
153 name);
154 }
155
156 return stream;
157}
158
159static void
160stream_destroy(struct wl_resource *stream_resource)
161{
162 struct weston_debug_stream *stream;
163
164 stream = wl_resource_get_user_data(stream_resource);
165
166 if (stream->fd != -1)
167 close(stream->fd);
168 wl_list_remove(&stream->scope_link);
169 free(stream);
170}
171
172static void
173weston_debug_stream_destroy(struct wl_client *client,
174 struct wl_resource *stream_resource)
175{
176 wl_resource_destroy(stream_resource);
177}
178
179static const struct weston_debug_stream_v1_interface
180 weston_debug_stream_impl = {
181 weston_debug_stream_destroy
182};
183
184static void
185weston_debug_destroy(struct wl_client *client,
186 struct wl_resource *global_resource)
187{
188 wl_resource_destroy(global_resource);
189}
190
191static void
192weston_debug_subscribe(struct wl_client *client,
193 struct wl_resource *global_resource,
194 const char *name,
195 int32_t streamfd,
196 uint32_t new_stream_id)
197{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300198 struct weston_log_context *log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200199 struct wl_resource *stream_resource;
200 uint32_t version;
201 struct weston_debug_stream *stream;
202
Marius Vlad3d7d9782019-04-17 12:35:38 +0300203 log_ctx = wl_resource_get_user_data(global_resource);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200204 version = wl_resource_get_version(global_resource);
205
206 stream_resource = wl_resource_create(client,
207 &weston_debug_stream_v1_interface,
208 version, new_stream_id);
209 if (!stream_resource)
210 goto fail;
211
Marius Vlad3d7d9782019-04-17 12:35:38 +0300212 stream = stream_create(log_ctx, name, streamfd, stream_resource);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200213 if (!stream)
214 goto fail;
215
216 wl_resource_set_implementation(stream_resource,
217 &weston_debug_stream_impl,
218 stream, stream_destroy);
219 return;
220
221fail:
222 close(streamfd);
223 wl_client_post_no_memory(client);
224}
225
226static const struct weston_debug_v1_interface weston_debug_impl = {
227 weston_debug_destroy,
228 weston_debug_subscribe
229};
230
231static void
232bind_weston_debug(struct wl_client *client,
233 void *data, uint32_t version, uint32_t id)
234{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300235 struct weston_log_context *log_ctx = data;
Marius Vlad5d5e3352019-04-17 13:05:38 +0300236 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200237 struct wl_resource *resource;
238
239 resource = wl_resource_create(client,
240 &weston_debug_v1_interface,
241 version, id);
242 if (!resource) {
243 wl_client_post_no_memory(client);
244 return;
245 }
246 wl_resource_set_implementation(resource, &weston_debug_impl,
Marius Vlad3d7d9782019-04-17 12:35:38 +0300247 log_ctx, NULL);
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 weston_debug_v1_send_available(resource, scope->name,
251 scope->desc);
252 }
253}
254
Marius Vlad880b4852019-04-07 17:07:58 +0300255/**
Marius Vlad3d7d9782019-04-17 12:35:38 +0300256 * Connect weston_compositor structure to weston_log_context structure.
Marius Vlad880b4852019-04-07 17:07:58 +0300257 *
258 * \param compositor
Marius Vlad3d7d9782019-04-17 12:35:38 +0300259 * \param log_ctx
Marius Vlad880b4852019-04-07 17:07:58 +0300260 * \return 0 on success, -1 on failure
261 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300262 * Sets weston_compositor::weston_log_ctx.
Marius Vlad880b4852019-04-07 17:07:58 +0300263 */
264int
Marius Vlad3d7d9782019-04-17 12:35:38 +0300265weston_log_ctx_compositor_setup(struct weston_compositor *compositor,
266 struct weston_log_context *log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300267{
Marius Vlad6f098662019-04-17 13:50:28 +0300268 assert(!compositor->weston_log_ctx);
269 assert(log_ctx);
Marius Vlad880b4852019-04-07 17:07:58 +0300270
Marius Vlad3d7d9782019-04-17 12:35:38 +0300271 compositor->weston_log_ctx = log_ctx;
Marius Vlad880b4852019-04-07 17:07:58 +0300272 return 0;
273}
274
Marius Vlad3d7d9782019-04-17 12:35:38 +0300275/** Initialize weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200276 *
277 * \param compositor The libweston compositor.
278 * \return 0 on success, -1 on failure.
279 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300280 * weston_log_context is a singleton for each weston_compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200281 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200282 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300283WL_EXPORT struct weston_log_context *
284weston_log_ctx_compositor_create(void)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200285{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300286 struct weston_log_context *log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200287
Marius Vlad3d7d9782019-04-17 12:35:38 +0300288 log_ctx = zalloc(sizeof *log_ctx);
289 if (!log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300290 return NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200291
Marius Vlad3d7d9782019-04-17 12:35:38 +0300292 wl_list_init(&log_ctx->scope_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200293
Marius Vlad3d7d9782019-04-17 12:35:38 +0300294 return log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200295}
296
Marius Vlad3d7d9782019-04-17 12:35:38 +0300297/** Destroy weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200298 *
299 * \param compositor The libweston compositor whose weston-debug to tear down.
300 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300301 * Clears weston_compositor::weston_log_ctx.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200302 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200303 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300304WL_EXPORT void
305weston_log_ctx_compositor_destroy(struct weston_compositor *compositor)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200306{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300307 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
Marius Vlad5d5e3352019-04-17 13:05:38 +0300308 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200309
Marius Vlad3d7d9782019-04-17 12:35:38 +0300310 if (log_ctx->global)
311 wl_global_destroy(log_ctx->global);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200312
Marius Vlad3d7d9782019-04-17 12:35:38 +0300313 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200314 weston_log("Internal warning: debug scope '%s' has not been destroyed.\n",
315 scope->name);
316
317 /* Remove head to not crash if scope removed later. */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300318 wl_list_remove(&log_ctx->scope_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200319
Marius Vlad3d7d9782019-04-17 12:35:38 +0300320 free(log_ctx);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200321
Marius Vlad3d7d9782019-04-17 12:35:38 +0300322 compositor->weston_log_ctx = NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200323}
324
325/** Enable weston-debug protocol extension
326 *
327 * \param compositor The libweston compositor where to enable.
328 *
329 * This enables the weston_debug_v1 Wayland protocol extension which any client
Emmanuel Gil Peyrot426c2462019-02-20 16:33:32 +0100330 * can use to get debug messages from the compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200331 *
332 * WARNING: This feature should not be used in production. If a client
333 * provides a file descriptor that blocks writes, it will block the whole
334 * compositor indefinitely.
335 *
336 * There is no control on which client is allowed to subscribe to debug
337 * messages. Any and all clients are allowed.
338 *
339 * The debug extension is disabled by default, and once enabled, cannot be
340 * disabled again.
341 */
342WL_EXPORT void
343weston_compositor_enable_debug_protocol(struct weston_compositor *compositor)
344{
Marius Vlad1e2fda22019-04-07 19:07:16 +0300345 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
346 assert(log_ctx);
347 if (log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200348 return;
349
Marius Vlad1e2fda22019-04-07 19:07:16 +0300350 log_ctx->global = wl_global_create(compositor->wl_display,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200351 &weston_debug_v1_interface, 1,
Marius Vlad1e2fda22019-04-07 19:07:16 +0300352 log_ctx, bind_weston_debug);
353 if (!log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200354 return;
355
356 weston_log("WARNING: debug protocol has been enabled. "
357 "This is a potential denial-of-service attack vector and "
358 "information leak.\n");
359}
360
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200361/** Determine if the debug protocol has been enabled
362 *
363 * \param wc The libweston compositor to verify if debug protocol has been enabled
364 */
365WL_EXPORT bool
366weston_compositor_is_debug_protocol_enabled(struct weston_compositor *wc)
367{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300368 return wc->weston_log_ctx->global != NULL;
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200369}
370
Marius Vlad7e4db952019-04-17 13:47:06 +0300371/** Register a new debug stream name, creating a log scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200372 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300373 * \param log_ctx The weston_log_context where to add.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200374 * \param name The debug stream/scope name; must not be NULL.
375 * \param desc The debug scope description for humans; must not be NULL.
376 * \param begin_cb Optional callback when a client subscribes to this scope.
377 * \param user_data Optional user data pointer for the callback.
378 * \return A valid pointer on success, NULL on failure.
379 *
380 * This function is used to create a debug scope. All debug message printing
381 * happens for a scope, which allows clients to subscribe to the kind of
382 * debug messages they want by \c name.
383 *
384 * \c name must be unique in the \c weston_compositor instance. \c name and
385 * \c description must both be provided. The description is printed when a
386 * client asks for a list of supported debug scopes.
387 *
388 * \c begin_cb, if not NULL, is called when a client subscribes to the
389 * debug scope creating a debug stream. This is for debug scopes that need
390 * to print messages as a response to a client appearing, e.g. printing a
391 * list of windows on demand or a static preamble. The argument \c user_data
392 * is passed in to the callback and is otherwise unused.
393 *
394 * For one-shot debug streams, \c begin_cb should finally call
395 * weston_debug_stream_complete() to close the stream and tell the client
396 * the printing is complete. Otherwise the client expects more to be written
397 * to its file descriptor.
398 *
399 * The debug scope must be destroyed before destroying the
400 * \c weston_compositor.
401 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300402 * \memberof weston_log_scope
403 * \sa weston_debug_stream, weston_log_scope_cb
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200404 */
Marius Vlad5d5e3352019-04-17 13:05:38 +0300405WL_EXPORT struct weston_log_scope *
Marius Vlad7e4db952019-04-17 13:47:06 +0300406weston_compositor_add_log_scope(struct weston_log_context *log_ctx,
407 const char *name,
408 const char *description,
409 weston_log_scope_cb begin_cb,
410 void *user_data)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200411{
Marius Vlad5d5e3352019-04-17 13:05:38 +0300412 struct weston_log_scope *scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200413
Marius Vlad1e2fda22019-04-07 19:07:16 +0300414 if (!name || !description) {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200415 weston_log("Error: cannot add a debug scope without name or description.\n");
416 return NULL;
417 }
418
Marius Vlad3d7d9782019-04-17 12:35:38 +0300419 if (!log_ctx) {
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200420 weston_log("Error: cannot add debug scope '%s', infra not initialized.\n",
421 name);
422 return NULL;
423 }
424
Marius Vlad3d7d9782019-04-17 12:35:38 +0300425 if (get_scope(log_ctx, name)){
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200426 weston_log("Error: debug scope named '%s' is already registered.\n",
427 name);
428 return NULL;
429 }
430
431 scope = zalloc(sizeof *scope);
432 if (!scope) {
433 weston_log("Error adding debug scope '%s': out of memory.\n",
434 name);
435 return NULL;
436 }
437
438 scope->name = strdup(name);
439 scope->desc = strdup(description);
440 scope->begin_cb = begin_cb;
441 scope->user_data = user_data;
442 wl_list_init(&scope->stream_list);
443
444 if (!scope->name || !scope->desc) {
445 weston_log("Error adding debug scope '%s': out of memory.\n",
446 name);
447 free(scope->name);
448 free(scope->desc);
449 free(scope);
450 return NULL;
451 }
452
Marius Vlad3d7d9782019-04-17 12:35:38 +0300453 wl_list_insert(log_ctx->scope_list.prev, &scope->compositor_link);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200454
455 return scope;
456}
457
Marius Vlad3d7d9782019-04-17 12:35:38 +0300458/** Destroy a log scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200459 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300460 * \param scope The log scope to destroy; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200461 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300462 * Destroys the log scope, closing all open streams subscribed to it and
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200463 * sending them each a \c weston_debug_stream_v1.failure event.
464 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300465 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200466 */
467WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300468weston_compositor_log_scope_destroy(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200469{
470 struct weston_debug_stream *stream;
471
472 if (!scope)
473 return;
474
475 while (!wl_list_empty(&scope->stream_list)) {
476 stream = wl_container_of(scope->stream_list.prev,
477 stream, scope_link);
478
479 stream_close_on_failure(stream, "debug name removed");
480 }
481
482 wl_list_remove(&scope->compositor_link);
483 free(scope->name);
484 free(scope->desc);
485 free(scope);
486}
487
488/** Are there any active subscriptions to the scope?
489 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300490 * \param scope The log scope to check; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200491 * \return True if any streams are open for this scope, false otherwise.
492 *
493 * As printing some debugging messages may be relatively expensive, one
494 * can use this function to determine if there is a need to gather the
495 * debugging information at all. If this function returns false, all
496 * printing for this scope is dropped, so gathering the information is
497 * pointless.
498 *
499 * The return value of this function should not be stored, as new clients
500 * may subscribe to the debug scope later.
501 *
502 * If the given scope is NULL, this function will always return false,
503 * making it safe to use in teardown or destroy code, provided the
504 * scope is initialized to NULL before creation and set to NULL after
505 * destruction.
506 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300507 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200508 */
509WL_EXPORT bool
Marius Vlad7e4db952019-04-17 13:47:06 +0300510weston_log_scope_is_enabled(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200511{
512 if (!scope)
513 return false;
514
515 return !wl_list_empty(&scope->stream_list);
516}
517
518/** Write data into a specific debug stream
519 *
520 * \param stream The debug stream to write into; must not be NULL.
521 * \param data[in] Pointer to the data to write.
522 * \param len Number of bytes to write.
523 *
524 * Writes the given data (binary verbatim) into the debug stream.
525 * If \c len is zero or negative, the write is silently dropped.
526 *
527 * Writing is continued until all data has been written or
528 * a write fails. If the write fails due to a signal, it is re-tried.
529 * Otherwise on failure, the stream is closed and
530 * \c weston_debug_stream_v1.failure event is sent to the client.
531 *
532 * \memberof weston_debug_stream
533 */
534WL_EXPORT void
535weston_debug_stream_write(struct weston_debug_stream *stream,
536 const char *data, size_t len)
537{
538 ssize_t len_ = len;
539 ssize_t ret;
540 int e;
541
542 if (stream->fd == -1)
543 return;
544
545 while (len_ > 0) {
546 ret = write(stream->fd, data, len_);
547 e = errno;
548 if (ret < 0) {
549 if (e == EINTR)
550 continue;
551
552 stream_close_on_failure(stream,
553 "Error writing %zd bytes: %s (%d)",
554 len_, strerror(e), e);
555 break;
556 }
557
558 len_ -= ret;
559 data += ret;
560 }
561}
562
563/** Write a formatted string into a specific debug stream (varargs)
564 *
565 * \param stream The debug stream to write into.
566 * \param fmt Printf-style format string.
567 * \param ap Formatting arguments.
568 *
569 * The behavioral details are the same as for weston_debug_stream_write().
570 *
571 * \memberof weston_debug_stream
572 */
573WL_EXPORT void
574weston_debug_stream_vprintf(struct weston_debug_stream *stream,
575 const char *fmt, va_list ap)
576{
577 char *str;
578 int len;
579
580 len = vasprintf(&str, fmt, ap);
581 if (len >= 0) {
582 weston_debug_stream_write(stream, str, len);
583 free(str);
584 } else {
585 stream_close_on_failure(stream, "Out of memory");
586 }
587}
588
589/** Write a formatted string into a specific debug stream
590 *
591 * \param stream The debug stream to write into.
592 * \param fmt Printf-style format string and arguments.
593 *
594 * The behavioral details are the same as for weston_debug_stream_write().
595 *
596 * \memberof weston_debug_stream
597 */
598WL_EXPORT void
599weston_debug_stream_printf(struct weston_debug_stream *stream,
600 const char *fmt, ...)
601{
602 va_list ap;
603
604 va_start(ap, fmt);
605 weston_debug_stream_vprintf(stream, fmt, ap);
606 va_end(ap);
607}
608
609/** Close the debug stream and send success event
610 *
611 * \param stream The debug stream to close.
612 *
613 * Closes the debug stream and sends \c weston_debug_stream_v1.complete
614 * event to the client. This tells the client the debug information dump
615 * is complete.
616 *
617 * \memberof weston_debug_stream
618 */
619WL_EXPORT void
620weston_debug_stream_complete(struct weston_debug_stream *stream)
621{
622 stream_close_unlink(stream);
623 weston_debug_stream_v1_send_complete(stream->resource);
624}
625
Marius Vlad7e4db952019-04-17 13:47:06 +0300626/** Write log data for a scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200627 *
628 * \param scope The debug scope to write for; may be NULL, in which case
629 * nothing will be written.
630 * \param data[in] Pointer to the data to write.
631 * \param len Number of bytes to write.
632 *
633 * Writes the given data to all subscribed clients' streams.
634 *
635 * The behavioral details for each stream are the same as for
636 * weston_debug_stream_write().
637 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300638 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200639 */
640WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300641weston_log_scope_write(struct weston_log_scope *scope,
642 const char *data, size_t len)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200643{
644 struct weston_debug_stream *stream;
645
646 if (!scope)
647 return;
648
649 wl_list_for_each(stream, &scope->stream_list, scope_link)
650 weston_debug_stream_write(stream, data, len);
651}
652
653/** Write a formatted string for a scope (varargs)
654 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300655 * \param scope The log scope to write for; may be NULL, in which case
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200656 * nothing will be written.
657 * \param fmt Printf-style format string.
658 * \param ap Formatting arguments.
659 *
660 * Writes to formatted string to all subscribed clients' streams.
661 *
662 * The behavioral details for each stream are the same as for
663 * weston_debug_stream_write().
664 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300665 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200666 */
667WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300668weston_log_scope_vprintf(struct weston_log_scope *scope,
669 const char *fmt, va_list ap)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200670{
671 static const char oom[] = "Out of memory";
672 char *str;
673 int len;
674
Marius Vlad7e4db952019-04-17 13:47:06 +0300675 if (!weston_log_scope_is_enabled(scope))
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200676 return;
677
678 len = vasprintf(&str, fmt, ap);
679 if (len >= 0) {
Marius Vlad7e4db952019-04-17 13:47:06 +0300680 weston_log_scope_write(scope, str, len);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200681 free(str);
682 } else {
Marius Vlad7e4db952019-04-17 13:47:06 +0300683 weston_log_scope_write(scope, oom, sizeof oom - 1);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200684 }
685}
686
687/** Write a formatted string for a scope
688 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300689 * \param scope The log scope to write for; may be NULL, in which case
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200690 * nothing will be written.
691 * \param fmt Printf-style format string and arguments.
692 *
693 * Writes to formatted string to all subscribed clients' streams.
694 *
695 * The behavioral details for each stream are the same as for
696 * weston_debug_stream_write().
697 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300698 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200699 */
700WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300701weston_log_scope_printf(struct weston_log_scope *scope,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200702 const char *fmt, ...)
703{
704 va_list ap;
705
706 va_start(ap, fmt);
Marius Vlad7e4db952019-04-17 13:47:06 +0300707 weston_log_scope_vprintf(scope, fmt, ap);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200708 va_end(ap);
709}
710
711/** Write debug scope name and current time into string
712 *
713 * \param scope[in] debug scope; may be NULL
714 * \param buf[out] Buffer to store the string.
715 * \param len Available size in the buffer in bytes.
716 * \return \c buf
717 *
718 * Reads the current local wall-clock time and formats it into a string.
719 * and append the debug scope name to it, if a scope is available.
720 * The string is NUL-terminated, even if truncated.
721 */
722WL_EXPORT char *
Marius Vlad7e4db952019-04-17 13:47:06 +0300723weston_log_scope_timestamp(struct weston_log_scope *scope,
724 char *buf, size_t len)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200725{
726 struct timeval tv;
727 struct tm *bdt;
728 char string[128];
729 size_t ret = 0;
730
731 gettimeofday(&tv, NULL);
732
733 bdt = localtime(&tv.tv_sec);
734 if (bdt)
735 ret = strftime(string, sizeof string,
736 "%Y-%m-%d %H:%M:%S", bdt);
737
738 if (ret > 0) {
739 snprintf(buf, len, "[%s.%03ld][%s]", string,
740 tv.tv_usec / 1000,
741 (scope) ? scope->name : "no scope");
742 } else {
743 snprintf(buf, len, "[?][%s]",
744 (scope) ? scope->name : "no scope");
745 }
746
747 return buf;
748}