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