1 /*
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 <libweston/weston-log.h>
30 #include "shared/helpers.h"
31 #include <libweston/libweston.h>
32
33 #include "weston-log-internal.h"
34 #include "weston-debug-server-protocol.h"
35
36 #include <assert.h>
37 #include <unistd.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <sys/time.h>
42
43 /**
44 * @defgroup log Public Logging/Debugging API
45 * @defgroup internal-log Private/Internal Logging/Debugging API
46 * @defgroup debug-protocol weston-debug protocol specific
47 */
48
49 /** Main weston-log context
50 *
51 * One per weston_compositor. Stores list of scopes created and a list pending
52 * subscriptions.
53 *
54 * A pending subscription is a subscription to a scope which hasn't been
55 * created. When the scope is finally created the pending subscription will be
56 * removed from the pending subscription list, but not before was added in the
57 * scope's subscription list and that of the subscriber list.
58 *
59 * Pending subscriptions only make sense for other types of streams, other than
60 * those created by weston-debug protocol. In the case of the weston-debug
61 * protocol, the subscription processes is done automatically whenever a client
62 * connects and subscribes to a scope which was previously advertised by the
63 * compositor.
64 *
65 * @ingroup internal-log
66 */
67 struct weston_log_context {
68 struct wl_global *global;
69 struct wl_listener compositor_destroy_listener;
70 struct wl_list scope_list; /**< weston_log_scope::compositor_link */
71 struct wl_list pending_subscription_list; /**< weston_log_subscription::source_link */
72 };
73
74 /** weston-log message scope
75 *
76 * This is used for scoping logging/debugging messages. Clients can subscribe
77 * to only the scopes they are interested in. A scope is identified by its name
78 * (also referred to as debug stream name).
79 *
80 * @ingroup log
81 */
82 struct weston_log_scope {
83 char *name;
84 char *desc;
85 weston_log_scope_cb new_subscription;
86 weston_log_scope_cb destroy_subscription;
87 void *user_data;
88 struct wl_list compositor_link;
89 struct wl_list subscription_list; /**< weston_log_subscription::source_link */
90 };
91
92 /** Ties a subscriber to a scope
93 *
94 * A subscription is created each time we'd want to subscribe to a scope. From
95 * the stream type we can retrieve the subscriber and from the subscriber we
96 * reach each of the streams callbacks. See also weston_log_subscriber object.
97 *
98 * When a subscription has been created we store it in the scope's subscription
99 * list and in the subscriber's subscription list. The subscription might be a
100 * pending subscription until the scope for which there's was a subscribe has
101 * been created. The scope creation will take of looking through the pending
102 * subscription list.
103 *
104 * A subscription can reached from a subscriber subscription list by using the
105 * streams base class.
106 *
107 * @ingroup internal-log
108 */
109 struct weston_log_subscription {
110 struct weston_log_subscriber *owner;
111 struct wl_list owner_link; /**< weston_log_subscriber::subscription_list */
112
113 char *scope_name;
114 struct weston_log_scope *source;
115 struct wl_list source_link; /**< weston_log_scope::subscription_list or
116 weston_log_context::pending_subscription_list */
117
118 void *data;
119 };
120
121 static struct weston_log_subscription *
find_pending_subscription(struct weston_log_context * log_ctx,const char * scope_name)122 find_pending_subscription(struct weston_log_context *log_ctx,
123 const char *scope_name)
124 {
125 struct weston_log_subscription *sub;
126
127 wl_list_for_each(sub, &log_ctx->pending_subscription_list, source_link)
128 if (!strcmp(sub->scope_name, scope_name))
129 return sub;
130
131 return NULL;
132 }
133
134 /** Create a pending subscription and add it the list of pending subscriptions
135 *
136 * @param owner a subscriber represented by weston_log_subscriber object
137 * @param scope_name the name of the scope (which we don't have in the list of scopes)
138 * @param log_ctx the logging context used to add the pending subscription
139 *
140 * @memberof weston_log_subscription
141 */
142 static void
weston_log_subscription_create_pending(struct weston_log_subscriber * owner,const char * scope_name,struct weston_log_context * log_ctx)143 weston_log_subscription_create_pending(struct weston_log_subscriber *owner,
144 const char *scope_name,
145 struct weston_log_context *log_ctx)
146 {
147 assert(owner);
148 assert(scope_name);
149 struct weston_log_subscription *sub = zalloc(sizeof(*sub));
150
151 if (!sub)
152 return;
153
154 sub->scope_name = strdup(scope_name);
155 sub->owner = owner;
156
157 wl_list_insert(&log_ctx->pending_subscription_list, &sub->source_link);
158 }
159
160 /** Destroys the pending subscription created previously with
161 * weston_log_subscription_create_pending()
162 *
163 * @param sub the weston_log_subscription object to remove from the list
164 * of subscriptions and to destroy the subscription
165 *
166 * @memberof weston_log_subscription
167 */
168 static void
weston_log_subscription_destroy_pending(struct weston_log_subscription * sub)169 weston_log_subscription_destroy_pending(struct weston_log_subscription *sub)
170 {
171 assert(sub);
172 /* pending subsriptions do not have a source */
173 wl_list_remove(&sub->source_link);
174 free(sub->scope_name);
175 free(sub);
176 }
177
178 /** Write to the stream's subscription
179 *
180 * @memberof weston_log_subscription
181 */
182 static void
weston_log_subscription_write(struct weston_log_subscription * sub,const char * data,size_t len)183 weston_log_subscription_write(struct weston_log_subscription *sub,
184 const char *data, size_t len)
185 {
186 if (sub->owner && sub->owner->write)
187 sub->owner->write(sub->owner, data, len);
188 }
189
190 /** Write a formatted string to the stream's subscription
191 *
192 * @memberof weston_log_subscription
193 */
194 static void
weston_log_subscription_vprintf(struct weston_log_subscription * sub,const char * fmt,va_list ap)195 weston_log_subscription_vprintf(struct weston_log_subscription *sub,
196 const char *fmt, va_list ap)
197 {
198 static const char oom[] = "Out of memory";
199 char *str;
200 int len;
201
202 if (!weston_log_scope_is_enabled(sub->source))
203 return;
204
205 len = vasprintf(&str, fmt, ap);
206 if (len >= 0) {
207 weston_log_subscription_write(sub, str, len);
208 free(str);
209 } else {
210 weston_log_subscription_write(sub, oom, sizeof oom - 1);
211 }
212 }
213
214 void
weston_log_subscription_set_data(struct weston_log_subscription * sub,void * data)215 weston_log_subscription_set_data(struct weston_log_subscription *sub, void *data)
216 {
217 /* don't allow data to already be set */
218 assert(!sub->data);
219 sub->data = data;
220 }
221
222 void *
weston_log_subscription_get_data(struct weston_log_subscription * sub)223 weston_log_subscription_get_data(struct weston_log_subscription *sub)
224 {
225 return sub->data;
226 }
227
228 /** Creates a new subscription using the subscriber by \c owner.
229 *
230 * The subscription created is added to the \c owner subscription list.
231 * Destroying the subscription using weston_log_subscription_destroy() will
232 * remove the link from the subscription list and free storage alloc'ed.
233 *
234 * Note that this adds the subscription to the scope's subscription list
235 * hence the \c scope required argument.
236 *
237 * @param owner the subscriber owner, must be created before creating a
238 * subscription
239 * @param scope the scope in order to add the subscription to the scope's
240 * subscription list
241 * @returns a weston_log_subscription object in case of success, or NULL
242 * otherwise
243 *
244 * @sa weston_log_subscription_destroy, weston_log_subscription_remove,
245 * weston_log_subscription_add
246 * @memberof weston_log_subscription
247 */
248 void
weston_log_subscription_create(struct weston_log_subscriber * owner,struct weston_log_scope * scope)249 weston_log_subscription_create(struct weston_log_subscriber *owner,
250 struct weston_log_scope *scope)
251 {
252 struct weston_log_subscription *sub;
253 assert(owner);
254 assert(scope);
255 assert(scope->name);
256
257 sub = zalloc(sizeof(*sub));
258 if (!sub)
259 return;
260
261 sub->owner = owner;
262 sub->scope_name = strdup(scope->name);
263
264 wl_list_insert(&sub->owner->subscription_list, &sub->owner_link);
265
266 weston_log_subscription_add(scope, sub);
267 weston_log_run_cb_new_subscription(sub);
268 }
269
270 /** Destroys the subscription
271 *
272 * Removes the subscription from the scopes subscription list and from
273 * subscriber's subscription list. It destroys the subscription afterwads.
274 *
275 * @memberof weston_log_subscription
276 */
277 void
weston_log_subscription_destroy(struct weston_log_subscription * sub)278 weston_log_subscription_destroy(struct weston_log_subscription *sub)
279 {
280 assert(sub);
281
282 if (sub->owner->destroy_subscription)
283 sub->owner->destroy_subscription(sub->owner);
284
285 if (sub->source->destroy_subscription)
286 sub->source->destroy_subscription(sub, sub->source->user_data);
287
288 if (sub->owner)
289 wl_list_remove(&sub->owner_link);
290
291 weston_log_subscription_remove(sub);
292 free(sub->scope_name);
293 free(sub);
294 }
295
296 /** Adds the subscription \c sub to the subscription list of the
297 * scope.
298 *
299 * This should used when the scope has been created, and the subscription \c
300 * sub has be created before calling this function.
301 *
302 * @param scope the scope
303 * @param sub the subscription, it must be created before, see
304 * weston_log_subscription_create()
305 *
306 * @memberof weston_log_subscription
307 */
308 void
weston_log_subscription_add(struct weston_log_scope * scope,struct weston_log_subscription * sub)309 weston_log_subscription_add(struct weston_log_scope *scope,
310 struct weston_log_subscription *sub)
311 {
312 assert(scope);
313 assert(sub);
314 /* don't allow subscriptions to have a source already! */
315 assert(!sub->source);
316
317 sub->source = scope;
318 wl_list_insert(&scope->subscription_list, &sub->source_link);
319 }
320
321 /** Removes the subscription from the scope's subscription list
322 *
323 * @memberof weston_log_subscription
324 */
325 void
weston_log_subscription_remove(struct weston_log_subscription * sub)326 weston_log_subscription_remove(struct weston_log_subscription *sub)
327 {
328 assert(sub);
329 if (sub->source)
330 wl_list_remove(&sub->source_link);
331 sub->source = NULL;
332 }
333
334 /** Look-up the scope from the scope list stored in the log context, by
335 * matching against the \c name.
336 *
337 * @param log_ctx
338 * @param name the scope name, see weston_log_ctx_add_log_scope() and
339 * weston_compositor_add_log_scope()
340 * @returns NULL if none found, or a pointer to a weston_log_scope
341 *
342 * @ingroup internal-log
343 */
344 struct weston_log_scope *
weston_log_get_scope(struct weston_log_context * log_ctx,const char * name)345 weston_log_get_scope(struct weston_log_context *log_ctx, const char *name)
346 {
347 struct weston_log_scope *scope;
348 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
349 if (strcmp(name, scope->name) == 0)
350 return scope;
351 return NULL;
352 }
353
354 /** Wrapper to invoke the weston_log_scope_cb. Allows to call the cb
355 * new_subscription of a log scope.
356 *
357 * @ingroup internal-log
358 */
359 void
weston_log_run_cb_new_subscription(struct weston_log_subscription * sub)360 weston_log_run_cb_new_subscription(struct weston_log_subscription *sub)
361 {
362 if (sub->source->new_subscription)
363 sub->source->new_subscription(sub, sub->source->user_data);
364 }
365
366 /** Advertise the log scope name and the log scope description
367 *
368 * This is only used by the weston-debug protocol!
369 *
370 * @ingroup internal-log
371 */
372 void
weston_debug_protocol_advertise_scopes(struct weston_log_context * log_ctx,struct wl_resource * res)373 weston_debug_protocol_advertise_scopes(struct weston_log_context *log_ctx,
374 struct wl_resource *res)
375 {
376 struct weston_log_scope *scope;
377 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
378 weston_debug_v1_send_available(res, scope->name, scope->desc);
379 }
380
381 /** Disable debug-protocol
382 *
383 * @param log_ctx The log context where the debug-protocol is linked
384 *
385 * @ingroup internal-log
386 */
387 static void
weston_log_ctx_disable_debug_protocol(struct weston_log_context * log_ctx)388 weston_log_ctx_disable_debug_protocol(struct weston_log_context *log_ctx)
389 {
390 if (!log_ctx->global)
391 return;
392
393 wl_global_destroy(log_ctx->global);
394 log_ctx->global = NULL;
395 }
396
397 /** Creates weston_log_context structure
398 *
399 * \return NULL in case of failure, or a weston_log_context object in case of
400 * success
401 *
402 * weston_log_context is a singleton for each weston_compositor.
403 * @ingroup log
404 *
405 */
406 WL_EXPORT struct weston_log_context *
weston_log_ctx_create(void)407 weston_log_ctx_create(void)
408 {
409 struct weston_log_context *log_ctx;
410
411 log_ctx = zalloc(sizeof *log_ctx);
412 if (!log_ctx)
413 return NULL;
414
415 wl_list_init(&log_ctx->scope_list);
416 wl_list_init(&log_ctx->pending_subscription_list);
417 wl_list_init(&log_ctx->compositor_destroy_listener.link);
418
419 return log_ctx;
420 }
421
422 /** Destroy weston_log_context structure
423 *
424 * \param log_ctx The log context to destroy.
425 *
426 * @ingroup log
427 *
428 */
429 WL_EXPORT void
weston_log_ctx_destroy(struct weston_log_context * log_ctx)430 weston_log_ctx_destroy(struct weston_log_context *log_ctx)
431 {
432 struct weston_log_scope *scope;
433 struct weston_log_subscription *pending_sub, *pending_sub_tmp;
434
435 /* We can't destroy the log context if there's still a compositor
436 * that depends on it. This is an user error */
437 assert(wl_list_empty(&log_ctx->compositor_destroy_listener.link));
438
439 weston_log_ctx_disable_debug_protocol(log_ctx);
440
441 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
442 fprintf(stderr, "Internal warning: debug scope '%s' has not been destroyed.\n",
443 scope->name);
444
445 /* Remove head to not crash if scope removed later. */
446 wl_list_remove(&log_ctx->scope_list);
447
448 /* Remove any pending subscription(s) which nobody subscribed to */
449 wl_list_for_each_safe(pending_sub, pending_sub_tmp,
450 &log_ctx->pending_subscription_list, source_link) {
451 weston_log_subscription_destroy_pending(pending_sub);
452 }
453
454 /* pending_subscription_list should be empty at this point */
455
456 free(log_ctx);
457 }
458
459 static void
compositor_destroy_listener(struct wl_listener * listener,void * data)460 compositor_destroy_listener(struct wl_listener *listener, void *data)
461 {
462 struct weston_log_context *log_ctx =
463 wl_container_of(listener, log_ctx, compositor_destroy_listener);
464
465 /* We have to keep this list initalized as weston_log_ctx_destroy() has
466 * to check if there's any compositor destroy listener registered */
467 wl_list_remove(&log_ctx->compositor_destroy_listener.link);
468 wl_list_init(&log_ctx->compositor_destroy_listener.link);
469
470 weston_log_ctx_disable_debug_protocol(log_ctx);
471 }
472
473 /** Enable weston-debug protocol extension
474 *
475 * \param compositor The libweston compositor where to enable.
476 *
477 * This enables the weston_debug_v1 Wayland protocol extension which any client
478 * can use to get debug messages from the compositor.
479 *
480 * WARNING: This feature should not be used in production. If a client
481 * provides a file descriptor that blocks writes, it will block the whole
482 * compositor indefinitely.
483 *
484 * There is no control on which client is allowed to subscribe to debug
485 * messages. Any and all clients are allowed.
486 *
487 * The debug extension is disabled by default, and once enabled, cannot be
488 * disabled again.
489 *
490 * @ingroup debug-protocol
491 */
492 WL_EXPORT void
weston_compositor_enable_debug_protocol(struct weston_compositor * compositor)493 weston_compositor_enable_debug_protocol(struct weston_compositor *compositor)
494 {
495 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
496 assert(log_ctx);
497 if (log_ctx->global)
498 return;
499
500 log_ctx->global = wl_global_create(compositor->wl_display,
501 &weston_debug_v1_interface, 1,
502 log_ctx, weston_log_bind_weston_debug);
503 if (!log_ctx->global)
504 return;
505
506 log_ctx->compositor_destroy_listener.notify = compositor_destroy_listener;
507 wl_signal_add(&compositor->destroy_signal, &log_ctx->compositor_destroy_listener);
508
509 fprintf(stderr, "WARNING: debug protocol has been enabled. "
510 "This is a potential denial-of-service attack vector and "
511 "information leak.\n");
512 }
513
514 /** Determine if the debug protocol has been enabled
515 *
516 * \param wc The libweston compositor to verify if debug protocol has been
517 * enabled
518 *
519 * @ingroup debug-protocol
520 */
521 WL_EXPORT bool
weston_compositor_is_debug_protocol_enabled(struct weston_compositor * wc)522 weston_compositor_is_debug_protocol_enabled(struct weston_compositor *wc)
523 {
524 return wc->weston_log_ctx->global != NULL;
525 }
526
527 /** Register a new stream name, creating a log scope.
528 *
529 * @param log_ctx The weston_log_context where to add.
530 * @param name The debug stream/scope name; must not be NULL.
531 * @param description The log scope description for humans; must not be NULL.
532 * @param new_subscription Optional callback when a client subscribes to this
533 * scope.
534 * @param destroy_subscription Optional callback when a client destroys the
535 * subscription.
536 * @param user_data Optional user data pointer for the callback.
537 * @returns A valid pointer on success, NULL on failure.
538 *
539 * This function is used to create a log scope. All debug message printing
540 * happens for a scope, which allows clients to subscribe to the kind of debug
541 * messages they want by \c name. For the weston-debug protocol,
542 * subscription for the scope will happen automatically but for other types of
543 * streams, weston_log_subscribe() should be called as to create a subscription
544 * and tie it to the scope created by this function.
545 *
546 * \p name must be unique in the weston_compositor instance. \p name
547 * and \p description must both be provided. In case of the weston-debug
548 * protocol, the description is printed when a client asks for a list of
549 * supported log scopes.
550 *
551 * \p new_subscription, if not NULL, is called when a client subscribes to the log
552 * scope creating a debug stream. This is for log scopes that need to print
553 * messages as a response to a client appearing, e.g. printing a list of
554 * windows on demand or a static preamble. The argument \p user_data is
555 * passed in to the callback and is otherwise unused.
556 *
557 * For one-shot debug streams, \c new_subscription should finally call
558 * weston_log_subscription_complete() to close the stream and tell the client
559 * the printing is complete. Otherwise the client expects more data to be
560 * written. The complete callback in weston_log_subscriber should be installed
561 * to trigger it and it is set-up automatically for the weston-debug protocol.
562 *
563 * As subscription can take place before creating the scope, any pending
564 * subscriptions to scope added by weston_log_subscribe(), will be checked
565 * against the scope being created and if found will be added to the scope's
566 * subscription list.
567 *
568 * The log scope must be destroyed using weston_log_scope_destroy()
569 * before destroying the weston_compositor.
570 *
571 * @memberof weston_log_scope
572 * @sa weston_log_scope_cb, weston_log_subscribe
573 */
574 WL_EXPORT struct weston_log_scope *
weston_log_ctx_add_log_scope(struct weston_log_context * log_ctx,const char * name,const char * description,weston_log_scope_cb new_subscription,weston_log_scope_cb destroy_subscription,void * user_data)575 weston_log_ctx_add_log_scope(struct weston_log_context *log_ctx,
576 const char *name,
577 const char *description,
578 weston_log_scope_cb new_subscription,
579 weston_log_scope_cb destroy_subscription,
580 void *user_data)
581 {
582 struct weston_log_scope *scope;
583 struct weston_log_subscription *pending_sub = NULL;
584
585 if (!name || !description) {
586 fprintf(stderr, "Error: cannot add a debug scope without name or description.\n");
587 return NULL;
588 }
589
590 if (!log_ctx) {
591 fprintf(stderr, "Error: cannot add debug scope '%s', infra not initialized.\n",
592 name);
593 return NULL;
594 }
595
596 if (weston_log_get_scope(log_ctx, name)){
597 fprintf(stderr, "Error: debug scope named '%s' is already registered.\n",
598 name);
599 return NULL;
600 }
601
602 scope = zalloc(sizeof *scope);
603 if (!scope) {
604 fprintf(stderr, "Error adding debug scope '%s': out of memory.\n",
605 name);
606 return NULL;
607 }
608
609 scope->name = strdup(name);
610 scope->desc = strdup(description);
611 scope->new_subscription = new_subscription;
612 scope->destroy_subscription = destroy_subscription;
613 scope->user_data = user_data;
614 wl_list_init(&scope->subscription_list);
615
616 if (!scope->name || !scope->desc) {
617 fprintf(stderr, "Error adding debug scope '%s': out of memory.\n",
618 name);
619 free(scope->name);
620 free(scope->desc);
621 free(scope);
622 return NULL;
623 }
624
625 wl_list_insert(log_ctx->scope_list.prev, &scope->compositor_link);
626
627 /* check if there are any pending subscriptions to this scope */
628 while ((pending_sub = find_pending_subscription(log_ctx, scope->name)) != NULL) {
629 weston_log_subscription_create(pending_sub->owner, scope);
630
631 /* remove it from pending */
632 weston_log_subscription_destroy_pending(pending_sub);
633 }
634
635
636 return scope;
637 }
638
639 /** Register a new stream name, creating a log scope.
640 *
641 * @param compositor The compositor that contains the log context where the log
642 * scope will be linked.
643 * @param name The debug stream/scope name; must not be NULL.
644 * @param description The log scope description for humans; must not be NULL.
645 * @param new_subscription Optional callback when a client subscribes to this
646 * scope.
647 * @param destroy_subscription Optional callback when a client destroys the
648 * subscription.
649 * @param user_data Optional user data pointer for the callback.
650 * @returns A valid pointer on success, NULL on failure.
651 *
652 * This function works like weston_log_ctx_add_log_scope(), but the log scope
653 * created is linked to the log context of \c compositor.
654 *
655 * @memberof weston_compositor
656 * @sa weston_log_ctx_add_log_scope
657 */
658 WL_EXPORT struct weston_log_scope *
weston_compositor_add_log_scope(struct weston_compositor * compositor,const char * name,const char * description,weston_log_scope_cb new_subscription,weston_log_scope_cb destroy_subscription,void * user_data)659 weston_compositor_add_log_scope(struct weston_compositor *compositor,
660 const char *name,
661 const char *description,
662 weston_log_scope_cb new_subscription,
663 weston_log_scope_cb destroy_subscription,
664 void *user_data)
665 {
666 struct weston_log_scope *scope;
667 scope = weston_log_ctx_add_log_scope(compositor->weston_log_ctx,
668 name, description,
669 new_subscription,
670 destroy_subscription,
671 user_data);
672 return scope;
673 }
674
675 /** Destroy a log scope
676 *
677 * @param scope The log scope to destroy; may be NULL.
678 *
679 * Destroys the log scope, calling each stream's destroy callback if one was
680 * installed/created.
681 *
682 * @memberof weston_log_scope
683 */
684 WL_EXPORT void
weston_log_scope_destroy(struct weston_log_scope * scope)685 weston_log_scope_destroy(struct weston_log_scope *scope)
686 {
687 struct weston_log_subscription *sub, *sub_tmp;
688
689 if (!scope)
690 return;
691
692 wl_list_for_each_safe(sub, sub_tmp, &scope->subscription_list, source_link)
693 weston_log_subscription_destroy(sub);
694
695 wl_list_remove(&scope->compositor_link);
696 free(scope->name);
697 free(scope->desc);
698 free(scope);
699 }
700
701 /** Are there any active subscriptions to the scope?
702 *
703 * \param scope The log scope to check; may be NULL.
704 * \return True if any streams are open for this scope, false otherwise.
705 *
706 * As printing some debugging messages may be relatively expensive, one
707 * can use this function to determine if there is a need to gather the
708 * debugging information at all. If this function returns false, all
709 * printing for this scope is dropped, so gathering the information is
710 * pointless.
711 *
712 * The return value of this function should not be stored, as new clients
713 * may subscribe to the debug scope later.
714 *
715 * If the given scope is NULL, this function will always return false,
716 * making it safe to use in teardown or destroy code, provided the
717 * scope is initialized to NULL before creation and set to NULL after
718 * destruction.
719 *
720 * \memberof weston_log_scope
721 */
722 WL_EXPORT bool
weston_log_scope_is_enabled(struct weston_log_scope * scope)723 weston_log_scope_is_enabled(struct weston_log_scope *scope)
724 {
725 if (!scope)
726 return false;
727
728 return !wl_list_empty(&scope->subscription_list);
729 }
730
731 /** Close the stream's complete callback if one was installed/created.
732 *
733 * @ingroup log
734 */
735 WL_EXPORT void
weston_log_subscription_complete(struct weston_log_subscription * sub)736 weston_log_subscription_complete(struct weston_log_subscription *sub)
737 {
738 if (sub->owner && sub->owner->complete)
739 sub->owner->complete(sub->owner);
740 }
741
742 /** Close the log scope.
743 *
744 * @param scope The log scope to complete; may be NULL.
745 *
746 * Complete the log scope, calling each stream's complete callback if one was
747 * installed/created. This can be useful to signal the reading end that the
748 * data has been transmited and should no longer expect that written over the
749 * stream. Particularly useful for the weston-debug protocol.
750 *
751 * @memberof weston_log_scope
752 * @sa weston_log_ctx_add_log_scope, weston_compositor_add_log_scope,
753 * weston_log_scope_destroy
754 */
755 WL_EXPORT void
weston_log_scope_complete(struct weston_log_scope * scope)756 weston_log_scope_complete(struct weston_log_scope *scope)
757 {
758 struct weston_log_subscription *sub;
759
760 if (!scope)
761 return;
762
763 wl_list_for_each(sub, &scope->subscription_list, source_link)
764 weston_log_subscription_complete(sub);
765 }
766
767 /** Write log data for a scope
768 *
769 * \param scope The debug scope to write for; may be NULL, in which case
770 * nothing will be written.
771 * \param[in] data Pointer to the data to write.
772 * \param len Number of bytes to write.
773 *
774 * Writes the given data to all subscribed clients' streams.
775 *
776 * \memberof weston_log_scope
777 */
778 WL_EXPORT void
weston_log_scope_write(struct weston_log_scope * scope,const char * data,size_t len)779 weston_log_scope_write(struct weston_log_scope *scope,
780 const char *data, size_t len)
781 {
782 struct weston_log_subscription *sub;
783
784 if (!scope)
785 return;
786
787 wl_list_for_each(sub, &scope->subscription_list, source_link)
788 weston_log_subscription_write(sub, data, len);
789 }
790
791 /** Write a formatted string for a scope (varargs)
792 *
793 * \param scope The log scope to write for; may be NULL, in which case
794 * nothing will be written.
795 * \param fmt Printf-style format string.
796 * \param ap Formatting arguments.
797 *
798 * Writes to formatted string to all subscribed clients' streams.
799 *
800 * The behavioral details for each stream are the same as for
801 * weston_debug_stream_write().
802 *
803 * \memberof weston_log_scope
804 */
805 WL_EXPORT int
weston_log_scope_vprintf(struct weston_log_scope * scope,const char * fmt,va_list ap)806 weston_log_scope_vprintf(struct weston_log_scope *scope,
807 const char *fmt, va_list ap)
808 {
809 static const char oom[] = "Out of memory";
810 char *str;
811 int len = 0;
812
813 if (!weston_log_scope_is_enabled(scope))
814 return len;
815
816 len = vasprintf(&str, fmt, ap);
817 if (len >= 0) {
818 weston_log_scope_write(scope, str, len);
819 free(str);
820 } else {
821 weston_log_scope_write(scope, oom, sizeof oom - 1);
822 }
823
824 return len;
825 }
826
827 /** Write a formatted string for a scope
828 *
829 * \param scope The log scope to write for; may be NULL, in which case
830 * nothing will be written.
831 * \param fmt Printf-style format string and arguments.
832 *
833 * Writes to formatted string to all subscribed clients' streams.
834 *
835 * The behavioral details for each stream are the same as for
836 * weston_debug_stream_write().
837 *
838 * \memberof weston_log_scope
839 */
840 WL_EXPORT int
weston_log_scope_printf(struct weston_log_scope * scope,const char * fmt,...)841 weston_log_scope_printf(struct weston_log_scope *scope,
842 const char *fmt, ...)
843 {
844 va_list ap;
845 int len;
846
847 va_start(ap, fmt);
848 len = weston_log_scope_vprintf(scope, fmt, ap);
849 va_end(ap);
850
851 return len;
852 }
853
854 /** Write a formatted string for a subscription
855 *
856 * \param sub The subscription to write for; may be NULL, in which case
857 * nothing will be written.
858 * \param fmt Printf-style format string and arguments.
859 *
860 * Writes to formatted string to the stream that created the subscription.
861 *
862 * @ingroup log
863 */
864 WL_EXPORT void
weston_log_subscription_printf(struct weston_log_subscription * sub,const char * fmt,...)865 weston_log_subscription_printf(struct weston_log_subscription *sub,
866 const char *fmt, ...)
867 {
868 va_list ap;
869
870 va_start(ap, fmt);
871 weston_log_subscription_vprintf(sub, fmt, ap);
872 va_end(ap);
873 }
874
875 /** Write debug scope name and current time into string
876 *
877 * \param[in] scope debug scope; may be NULL
878 * \param[out] buf Buffer to store the string.
879 * \param len Available size in the buffer in bytes.
880 * \return \c buf
881 *
882 * Reads the current local wall-clock time and formats it into a string.
883 * and append the debug scope name to it, if a scope is available.
884 * The string is NUL-terminated, even if truncated.
885 *
886 * @memberof weston_log_scope
887 */
888 WL_EXPORT char *
weston_log_scope_timestamp(struct weston_log_scope * scope,char * buf,size_t len)889 weston_log_scope_timestamp(struct weston_log_scope *scope,
890 char *buf, size_t len)
891 {
892 struct timeval tv;
893 struct tm *bdt;
894 char string[128];
895 size_t ret = 0;
896
897 gettimeofday(&tv, NULL);
898
899 bdt = localtime(&tv.tv_sec);
900 if (bdt)
901 ret = strftime(string, sizeof string,
902 "%Y-%m-%d %H:%M:%S", bdt);
903
904 if (ret > 0) {
905 snprintf(buf, len, "[%s.%03ld][%s]", string,
906 tv.tv_usec / 1000,
907 (scope) ? scope->name : "no scope");
908 } else {
909 snprintf(buf, len, "[?][%s]",
910 (scope) ? scope->name : "no scope");
911 }
912
913 return buf;
914 }
915
916 void
weston_log_subscriber_release(struct weston_log_subscriber * subscriber)917 weston_log_subscriber_release(struct weston_log_subscriber *subscriber)
918 {
919 struct weston_log_subscription *sub, *sub_tmp;
920
921 wl_list_for_each_safe(sub, sub_tmp, &subscriber->subscription_list, owner_link)
922 weston_log_subscription_destroy(sub);
923 }
924
925 /** Destroy a file type or a flight-rec type subscriber.
926 *
927 * They are created, respectively, with weston_log_subscriber_create_log()
928 * and weston_log_subscriber_create_flight_rec()
929 *
930 * @param subscriber the weston_log_subscriber object to destroy
931 *
932 * @ingroup log
933 */
934 WL_EXPORT void
weston_log_subscriber_destroy(struct weston_log_subscriber * subscriber)935 weston_log_subscriber_destroy(struct weston_log_subscriber *subscriber)
936 {
937 subscriber->destroy(subscriber);
938 }
939
940 /** Subscribe to a scope
941 *
942 * Creates a subscription which is used to subscribe the \p subscriber
943 * to the scope \c scope_name.
944 *
945 * If \c scope_name has already been created (using
946 * weston_log_ctx_add_log_scope or weston_compositor_add_log_scope) the
947 * subscription will take place immediately, otherwise we store the
948 * subscription into a pending list. See also weston_log_ctx_add_log_scope()
949 * and weston_compositor_add_log_scope()
950 *
951 * @param log_ctx the log context, used for accessing pending list
952 * @param subscriber the subscriber, which has to be created before
953 * @param scope_name the scope name. In case the scope is not created
954 * we temporarily store the subscription in the pending list.
955 *
956 * @ingroup log
957 */
958 WL_EXPORT void
weston_log_subscribe(struct weston_log_context * log_ctx,struct weston_log_subscriber * subscriber,const char * scope_name)959 weston_log_subscribe(struct weston_log_context *log_ctx,
960 struct weston_log_subscriber *subscriber,
961 const char *scope_name)
962 {
963 assert(log_ctx);
964 assert(subscriber);
965 assert(scope_name);
966
967 struct weston_log_scope *scope;
968
969 scope = weston_log_get_scope(log_ctx, scope_name);
970 if (scope)
971 weston_log_subscription_create(subscriber, scope);
972 else
973 /*
974 * if we don't have already as scope for it, add it to pending
975 * subscription list
976 */
977 weston_log_subscription_create_pending(subscriber, scope_name, log_ctx);
978 }
979
980 /** Iterate over all subscriptions in a scope
981 *
982 * @param scope the scope for which you want to iterate
983 * @param sub_iter the iterator, use NULL to start from the 'head'
984 * @returns the next subscription from the log scope
985 *
986 * This is (quite) useful when 'log_scope' and 'log_subscription' are opaque. Do note
987 * that \c sub_iter needs to be NULL-initialized before calling this function.
988 *
989 */
990 WL_EXPORT struct weston_log_subscription *
weston_log_subscription_iterate(struct weston_log_scope * scope,struct weston_log_subscription * sub_iter)991 weston_log_subscription_iterate(struct weston_log_scope *scope,
992 struct weston_log_subscription *sub_iter)
993 {
994 struct wl_list *list = &scope->subscription_list;
995 struct wl_list *node;
996
997 /* go to the next item in the list or if not set starts with the head */
998 if (sub_iter)
999 node = sub_iter->source_link.next;
1000 else
1001 node = list->next;
1002
1003 assert(node);
1004 assert(!sub_iter || node != &sub_iter->source_link);
1005
1006 /* if we're at the end */
1007 if (node == list)
1008 return NULL;
1009
1010 return container_of(node, struct weston_log_subscription, source_link);
1011 }
1012