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