• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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