2 * Copyright (C) 2016, 2017 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
28 #include <json-c/json.h>
30 #include <afb/afb-req-common.h>
31 #include <afb/afb-event-itf.h>
33 #include "afb-context.h"
35 #include "afb-session.h"
44 * Definition of a hook for xreq
46 struct afb_hook_xreq {
47 struct afb_hook_xreq *next; /**< next hook */
48 unsigned refcount; /**< reference count */
49 char *api; /**< api hooked or NULL for any */
50 char *verb; /**< verb hooked or NULL for any */
51 struct afb_session *session; /**< session hooked or NULL if any */
52 unsigned flags; /**< hook flags */
53 struct afb_hook_xreq_itf *itf; /**< interface of hook */
54 void *closure; /**< closure for callbacks */
58 * Definition of a hook for ditf
60 struct afb_hook_ditf {
61 struct afb_hook_ditf *next; /**< next hook */
62 unsigned refcount; /**< reference count */
63 char *api; /**< api hooked or NULL for any */
64 unsigned flags; /**< hook flags */
65 struct afb_hook_ditf_itf *itf; /**< interface of hook */
66 void *closure; /**< closure for callbacks */
70 * Definition of a hook for svc
73 struct afb_hook_svc *next; /**< next hook */
74 unsigned refcount; /**< reference count */
75 char *api; /**< api hooked or NULL for any */
76 unsigned flags; /**< hook flags */
77 struct afb_hook_svc_itf *itf; /**< interface of hook */
78 void *closure; /**< closure for callbacks */
82 * Definition of a hook for evt
85 struct afb_hook_evt *next; /**< next hook */
86 unsigned refcount; /**< reference count */
87 char *pattern; /**< event pattern name hooked or NULL for any */
88 unsigned flags; /**< hook flags */
89 struct afb_hook_evt_itf *itf; /**< interface of hook */
90 void *closure; /**< closure for callbacks */
94 * Definition of a hook for global
96 struct afb_hook_global {
97 struct afb_hook_global *next; /**< next hook */
98 unsigned refcount; /**< reference count */
99 unsigned flags; /**< hook flags */
100 struct afb_hook_global_itf *itf; /**< interface of hook */
101 void *closure; /**< closure for callbacks */
104 /* synchronisation across threads */
105 static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
107 /* list of hooks for xreq */
108 static struct afb_hook_xreq *list_of_xreq_hooks = NULL;
110 /* list of hooks for ditf */
111 static struct afb_hook_ditf *list_of_ditf_hooks = NULL;
113 /* list of hooks for svc */
114 static struct afb_hook_svc *list_of_svc_hooks = NULL;
116 /* list of hooks for evt */
117 static struct afb_hook_evt *list_of_evt_hooks = NULL;
119 /* list of hooks for global */
120 static struct afb_hook_global *list_of_global_hooks = NULL;
123 static unsigned next_hookid = 0;
125 /******************************************************************************
127 *****************************************************************************/
128 static void init_hookid(struct afb_hookid *hookid)
130 hookid->id = __atomic_add_fetch(&next_hookid, 1, __ATOMIC_RELAXED);
131 clock_gettime(CLOCK_MONOTONIC, &hookid->time);
134 /******************************************************************************
135 * section: default callbacks for tracing requests
136 *****************************************************************************/
138 static char *_pbuf_(const char *fmt, va_list args, char **palloc, char *sbuf, size_t szsbuf)
145 rc = vsnprintf(sbuf, szsbuf, fmt, args);
146 if ((size_t)rc >= szsbuf) {
148 sbuf[szsbuf-2] = sbuf[szsbuf-3] = sbuf[szsbuf-4] = '.';
149 rc = vasprintf(palloc, fmt, cp);
157 static void _hook_(const char *fmt1, const char *fmt2, va_list arg2, ...)
159 char *tag, *data, *mem1, *mem2, buf1[256], buf2[2000];
162 data = _pbuf_(fmt2, arg2, &mem2, buf2, sizeof buf2);
164 va_start(arg1, arg2);
165 tag = _pbuf_(fmt1, arg1, &mem1, buf1, sizeof buf1);
168 NOTICE("[HOOK %s] %s", tag, data);
174 static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...)
177 va_start(ap, format);
178 _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->api, xreq->verb);
182 static void hook_xreq_begin_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
185 _hook_xreq_(xreq, "BEGIN");
187 _hook_xreq_(xreq, "BEGIN uid=%d=%s gid=%d pid=%d label=%s id=%s",
188 (int)xreq->cred->uid,
190 (int)xreq->cred->gid,
191 (int)xreq->cred->pid,
192 xreq->cred->label?:"(null)",
193 xreq->cred->id?:"(null)"
197 static void hook_xreq_end_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
199 _hook_xreq_(xreq, "END");
202 static void hook_xreq_json_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj)
204 _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj));
207 static void hook_xreq_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
209 _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
212 static void hook_xreq_success_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
214 _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info);
217 static void hook_xreq_fail_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info)
219 _hook_xreq_(xreq, "fail(%s, %s)", status, info);
222 static void hook_xreq_context_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value)
224 _hook_xreq_(xreq, "context_get() -> %p", value);
227 static void hook_xreq_context_set_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
229 _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value);
232 static void hook_xreq_addref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
234 _hook_xreq_(xreq, "addref()");
237 static void hook_xreq_unref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
239 _hook_xreq_(xreq, "unref()");
242 static void hook_xreq_session_close_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
244 _hook_xreq_(xreq, "session_close()");
247 static void hook_xreq_session_set_LOA_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result)
249 _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result);
252 static void hook_xreq_subscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event event, int result)
254 _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_event_name(event), afb_evt_event_id(event), result);
257 static void hook_xreq_unsubscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event event, int result)
259 _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_event_name(event), afb_evt_event_id(event), result);
262 static void hook_xreq_subcall_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
264 _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
267 static void hook_xreq_subcall_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
269 _hook_xreq_(xreq, " ...subcall... -> %d: %s", status, json_object_to_json_string(result));
272 static void hook_xreq_subcallsync_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
274 _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
277 static void hook_xreq_subcallsync_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
279 _hook_xreq_(xreq, " ...subcallsync... -> %d: %s", status, json_object_to_json_string(result));
282 static void hook_xreq_vverbose_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
289 len = vasprintf(&msg, fmt, ap);
293 _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt);
295 _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg);
300 static void hook_xreq_store_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq)
302 _hook_xreq_(xreq, "store() -> %p", sreq);
305 static void hook_xreq_unstore_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
307 _hook_xreq_(xreq, "unstore()");
310 static void hook_xreq_subcall_req_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
312 _hook_xreq_(xreq, "subcall_req(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
315 static void hook_xreq_subcall_req_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
317 _hook_xreq_(xreq, " ...subcall_req... -> %d: %s", status, json_object_to_json_string(result));
320 static void hook_xreq_has_permission_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result)
322 _hook_xreq_(xreq, "has_permission(%s) -> %d", permission, result);
325 static struct afb_hook_xreq_itf hook_xreq_default_itf = {
326 .hook_xreq_begin = hook_xreq_begin_default_cb,
327 .hook_xreq_end = hook_xreq_end_default_cb,
328 .hook_xreq_json = hook_xreq_json_default_cb,
329 .hook_xreq_get = hook_xreq_get_default_cb,
330 .hook_xreq_success = hook_xreq_success_default_cb,
331 .hook_xreq_fail = hook_xreq_fail_default_cb,
332 .hook_xreq_context_get = hook_xreq_context_get_default_cb,
333 .hook_xreq_context_set = hook_xreq_context_set_default_cb,
334 .hook_xreq_addref = hook_xreq_addref_default_cb,
335 .hook_xreq_unref = hook_xreq_unref_default_cb,
336 .hook_xreq_session_close = hook_xreq_session_close_default_cb,
337 .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_default_cb,
338 .hook_xreq_subscribe = hook_xreq_subscribe_default_cb,
339 .hook_xreq_unsubscribe = hook_xreq_unsubscribe_default_cb,
340 .hook_xreq_subcall = hook_xreq_subcall_default_cb,
341 .hook_xreq_subcall_result = hook_xreq_subcall_result_default_cb,
342 .hook_xreq_subcallsync = hook_xreq_subcallsync_default_cb,
343 .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb,
344 .hook_xreq_vverbose = hook_xreq_vverbose_default_cb,
345 .hook_xreq_store = hook_xreq_store_default_cb,
346 .hook_xreq_unstore = hook_xreq_unstore_default_cb,
347 .hook_xreq_subcall_req = hook_xreq_subcall_req_default_cb,
348 .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result_default_cb,
349 .hook_xreq_has_permission = hook_xreq_has_permission_default_cb
352 /******************************************************************************
353 * section: hooks for tracing requests
354 *****************************************************************************/
356 #define _HOOK_XREQ_(what,...) \
357 struct afb_hook_xreq *hook; \
358 struct afb_hookid hookid; \
359 pthread_rwlock_rdlock(&rwlock); \
360 init_hookid(&hookid); \
361 hook = list_of_xreq_hooks; \
363 if (hook->itf->hook_xreq_##what \
364 && (hook->flags & afb_hook_flag_req_##what) != 0 \
365 && (!hook->session || hook->session == xreq->context.session) \
366 && (!hook->api || !strcasecmp(hook->api, xreq->api)) \
367 && (!hook->verb || !strcasecmp(hook->verb, xreq->verb))) { \
368 hook->itf->hook_xreq_##what(hook->closure, &hookid, __VA_ARGS__); \
372 pthread_rwlock_unlock(&rwlock);
375 void afb_hook_xreq_begin(const struct afb_xreq *xreq)
377 _HOOK_XREQ_(begin, xreq);
380 void afb_hook_xreq_end(const struct afb_xreq *xreq)
382 _HOOK_XREQ_(end, xreq);
385 struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj)
387 _HOOK_XREQ_(json, xreq, obj);
391 struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
393 _HOOK_XREQ_(get, xreq, name, arg);
397 void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info)
399 _HOOK_XREQ_(success, xreq, obj, info);
402 void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info)
404 _HOOK_XREQ_(fail, xreq, status, info);
407 void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value)
409 _HOOK_XREQ_(context_get, xreq, value);
413 void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
415 _HOOK_XREQ_(context_set, xreq, value, free_value);
418 void afb_hook_xreq_addref(const struct afb_xreq *xreq)
420 _HOOK_XREQ_(addref, xreq);
423 void afb_hook_xreq_unref(const struct afb_xreq *xreq)
425 _HOOK_XREQ_(unref, xreq);
428 void afb_hook_xreq_session_close(const struct afb_xreq *xreq)
430 _HOOK_XREQ_(session_close, xreq);
433 int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result)
435 _HOOK_XREQ_(session_set_LOA, xreq, level, result);
439 int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
441 _HOOK_XREQ_(subscribe, xreq, event, result);
445 int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
447 _HOOK_XREQ_(unsubscribe, xreq, event, result);
451 void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
453 _HOOK_XREQ_(subcall, xreq, api, verb, args);
456 void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result)
458 _HOOK_XREQ_(subcall_result, xreq, status, result);
461 void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
463 _HOOK_XREQ_(subcallsync, xreq, api, verb, args);
466 int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result)
468 _HOOK_XREQ_(subcallsync_result, xreq, status, result);
472 void afb_hook_xreq_vverbose(const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
474 _HOOK_XREQ_(vverbose, xreq, level, file ?: "?", line, func ?: "?", fmt, args);
477 void afb_hook_xreq_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq)
479 _HOOK_XREQ_(store, xreq, sreq);
482 void afb_hook_xreq_unstore(const struct afb_xreq *xreq)
484 _HOOK_XREQ_(unstore, xreq);
487 void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
489 _HOOK_XREQ_(subcall_req, xreq, api, verb, args);
492 void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result)
494 _HOOK_XREQ_(subcall_req_result, xreq, status, result);
497 int afb_hook_xreq_has_permission(const struct afb_xreq *xreq, const char *permission, int result)
499 _HOOK_XREQ_(has_permission, xreq, permission, result);
503 /******************************************************************************
504 * section: hooking xreqs
505 *****************************************************************************/
507 void afb_hook_init_xreq(struct afb_xreq *xreq)
513 struct afb_hook_xreq *hook;
515 /* scan hook list to get the expected flags */
517 pthread_rwlock_rdlock(&rwlock);
518 hook = list_of_xreq_hooks;
520 f = hook->flags & afb_hook_flags_req_all;
522 && (!hook->session || hook->session == xreq->context.session)
523 && (!hook->api || !strcasecmp(hook->api, xreq->api))
524 && (!hook->verb || !strcasecmp(hook->verb, xreq->verb));
529 pthread_rwlock_unlock(&rwlock);
531 /* store the hooking data */
532 xreq->hookflags = flags;
534 pthread_rwlock_wrlock(&rwlock);
537 xreq->hookindex = reqindex;
538 pthread_rwlock_unlock(&rwlock);
542 struct afb_hook_xreq *afb_hook_create_xreq(const char *api, const char *verb, struct afb_session *session, int flags, struct afb_hook_xreq_itf *itf, void *closure)
544 struct afb_hook_xreq *hook;
546 /* alloc the result */
547 hook = calloc(1, sizeof *hook);
551 /* get a copy of the names */
552 hook->api = api ? strdup(api) : NULL;
553 hook->verb = verb ? strdup(verb) : NULL;
554 if ((api && !hook->api) || (verb && !hook->verb)) {
561 /* initialise the rest */
562 hook->session = session;
564 afb_session_addref(session);
567 hook->itf = itf ? itf : &hook_xreq_default_itf;
568 hook->closure = closure;
570 /* record the hook */
571 pthread_rwlock_wrlock(&rwlock);
572 hook->next = list_of_xreq_hooks;
573 list_of_xreq_hooks = hook;
574 pthread_rwlock_unlock(&rwlock);
580 struct afb_hook_xreq *afb_hook_addref_xreq(struct afb_hook_xreq *hook)
582 pthread_rwlock_wrlock(&rwlock);
584 pthread_rwlock_unlock(&rwlock);
588 void afb_hook_unref_xreq(struct afb_hook_xreq *hook)
590 struct afb_hook_xreq **prv;
593 pthread_rwlock_wrlock(&rwlock);
594 if (--hook->refcount)
598 prv = &list_of_xreq_hooks;
599 while (*prv && *prv != hook)
604 pthread_rwlock_unlock(&rwlock);
610 afb_session_unref(hook->session);
616 /******************************************************************************
617 * section: default callbacks for tracing daemon interface
618 *****************************************************************************/
620 static void _hook_ditf_(const struct afb_ditf *ditf, const char *format, ...)
623 va_start(ap, format);
624 _hook_("ditf-%s", format, ap, ditf->api);
628 static void hook_ditf_event_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *name, struct json_object *object)
630 _hook_ditf_(ditf, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object));
633 static void hook_ditf_event_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
635 _hook_ditf_(ditf, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result);
638 static void hook_ditf_get_event_loop_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, struct sd_event *result)
640 _hook_ditf_(ditf, "get_event_loop() -> %p", result);
643 static void hook_ditf_get_user_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, struct sd_bus *result)
645 _hook_ditf_(ditf, "get_user_bus() -> %p", result);
648 static void hook_ditf_get_system_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, struct sd_bus *result)
650 _hook_ditf_(ditf, "get_system_bus() -> %p", result);
653 static void hook_ditf_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
660 len = vasprintf(&msg, fmt, ap);
664 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, function, fmt);
666 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, function, msg);
671 static void hook_ditf_event_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *name, struct afb_event result)
673 _hook_ditf_(ditf, "event_make(%s) -> %s:%d", name, afb_evt_event_name(result), afb_evt_event_id(result));
676 static void hook_ditf_rootdir_get_fd_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, int result)
680 _hook_ditf_(ditf, "rootdir_get_fd() -> %d, %m", result);
682 sprintf(path, "/proc/self/fd/%d", result);
683 readlink(path, path, sizeof path);
684 _hook_ditf_(ditf, "rootdir_get_fd() -> %d = %s", result, path);
688 static void hook_ditf_rootdir_open_locale_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
694 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result);
696 sprintf(path, "/proc/self/fd/%d", result);
697 readlink(path, path, sizeof path);
698 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path);
702 static void hook_ditf_queue_job_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
704 _hook_ditf_(ditf, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result);
707 static void hook_ditf_unstore_req_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, struct afb_stored_req *sreq)
709 _hook_ditf_(ditf, "unstore_req(%p)", sreq);
712 static void hook_ditf_require_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *name, int initialized)
714 _hook_ditf_(ditf, "require_api(%s, %d)...", name, initialized);
717 static void hook_ditf_require_api_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *name, int initialized, int result)
719 _hook_ditf_(ditf, "...require_api(%s, %d) -> %d", name, initialized, result);
722 static struct afb_hook_ditf_itf hook_ditf_default_itf = {
723 .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before_cb,
724 .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after_cb,
725 .hook_ditf_get_event_loop = hook_ditf_get_event_loop_cb,
726 .hook_ditf_get_user_bus = hook_ditf_get_user_bus_cb,
727 .hook_ditf_get_system_bus = hook_ditf_get_system_bus_cb,
728 .hook_ditf_vverbose = hook_ditf_vverbose_cb,
729 .hook_ditf_event_make = hook_ditf_event_make_cb,
730 .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd_cb,
731 .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale_cb,
732 .hook_ditf_queue_job = hook_ditf_queue_job_cb,
733 .hook_ditf_unstore_req = hook_ditf_unstore_req_cb,
734 .hook_ditf_require_api = hook_ditf_require_api_cb,
735 .hook_ditf_require_api_result = hook_ditf_require_api_result_cb
738 /******************************************************************************
739 * section: hooks for tracing daemon interface (ditf)
740 *****************************************************************************/
742 #define _HOOK_DITF_(what,...) \
743 struct afb_hook_ditf *hook; \
744 struct afb_hookid hookid; \
745 pthread_rwlock_rdlock(&rwlock); \
746 init_hookid(&hookid); \
747 hook = list_of_ditf_hooks; \
749 if (hook->itf->hook_ditf_##what \
750 && (hook->flags & afb_hook_flag_ditf_##what) != 0 \
751 && (!hook->api || !strcasecmp(hook->api, ditf->api))) { \
752 hook->itf->hook_ditf_##what(hook->closure, &hookid, __VA_ARGS__); \
756 pthread_rwlock_unlock(&rwlock);
758 void afb_hook_ditf_event_broadcast_before(const struct afb_ditf *ditf, const char *name, struct json_object *object)
760 _HOOK_DITF_(event_broadcast_before, ditf, name, object);
763 int afb_hook_ditf_event_broadcast_after(const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
765 _HOOK_DITF_(event_broadcast_after, ditf, name, object, result);
769 struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_ditf *ditf, struct sd_event *result)
771 _HOOK_DITF_(get_event_loop, ditf, result);
775 struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_ditf *ditf, struct sd_bus *result)
777 _HOOK_DITF_(get_user_bus, ditf, result);
781 struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_ditf *ditf, struct sd_bus *result)
783 _HOOK_DITF_(get_system_bus, ditf, result);
787 void afb_hook_ditf_vverbose(const struct afb_ditf *ditf, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
789 _HOOK_DITF_(vverbose, ditf, level, file, line, function, fmt, args);
792 struct afb_event afb_hook_ditf_event_make(const struct afb_ditf *ditf, const char *name, struct afb_event result)
794 _HOOK_DITF_(event_make, ditf, name, result);
798 int afb_hook_ditf_rootdir_get_fd(const struct afb_ditf *ditf, int result)
800 _HOOK_DITF_(rootdir_get_fd, ditf, result);
804 int afb_hook_ditf_rootdir_open_locale(const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
806 _HOOK_DITF_(rootdir_open_locale, ditf, filename, flags, locale, result);
810 int afb_hook_ditf_queue_job(const struct afb_ditf *ditf, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
812 _HOOK_DITF_(queue_job, ditf, callback, argument, group, timeout, result);
816 void afb_hook_ditf_unstore_req(const struct afb_ditf *ditf, struct afb_stored_req *sreq)
818 _HOOK_DITF_(unstore_req, ditf, sreq);
821 void afb_hook_ditf_require_api(const struct afb_ditf *ditf, const char *name, int initialized)
823 _HOOK_DITF_(require_api, ditf, name, initialized);
826 int afb_hook_ditf_require_api_result(const struct afb_ditf *ditf, const char *name, int initialized, int result)
828 _HOOK_DITF_(require_api_result, ditf, name, initialized, result);
832 /******************************************************************************
833 * section: hooking ditf
834 *****************************************************************************/
836 int afb_hook_flags_ditf(const char *api)
839 struct afb_hook_ditf *hook;
841 pthread_rwlock_rdlock(&rwlock);
843 hook = list_of_ditf_hooks;
845 if (!api || !hook->api || !strcasecmp(hook->api, api))
846 flags |= hook->flags;
849 pthread_rwlock_unlock(&rwlock);
853 struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure)
855 struct afb_hook_ditf *hook;
857 /* alloc the result */
858 hook = calloc(1, sizeof *hook);
862 /* get a copy of the names */
863 hook->api = api ? strdup(api) : NULL;
864 if (api && !hook->api) {
869 /* initialise the rest */
872 hook->itf = itf ? itf : &hook_ditf_default_itf;
873 hook->closure = closure;
875 /* record the hook */
876 pthread_rwlock_wrlock(&rwlock);
877 hook->next = list_of_ditf_hooks;
878 list_of_ditf_hooks = hook;
879 pthread_rwlock_unlock(&rwlock);
885 struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook)
887 pthread_rwlock_wrlock(&rwlock);
889 pthread_rwlock_unlock(&rwlock);
893 void afb_hook_unref_ditf(struct afb_hook_ditf *hook)
895 struct afb_hook_ditf **prv;
898 pthread_rwlock_wrlock(&rwlock);
899 if (--hook->refcount)
903 prv = &list_of_ditf_hooks;
904 while (*prv && *prv != hook)
909 pthread_rwlock_unlock(&rwlock);
918 /******************************************************************************
919 * section: default callbacks for tracing service interface (svc)
920 *****************************************************************************/
922 static void _hook_svc_(const struct afb_svc *svc, const char *format, ...)
925 va_start(ap, format);
926 _hook_("svc-%s", format, ap, svc->api);
930 static void hook_svc_start_before_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc)
932 _hook_svc_(svc, "start.before");
935 static void hook_svc_start_after_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, int status)
937 _hook_svc_(svc, "start.after -> %d", status);
940 static void hook_svc_on_event_before_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
942 _hook_svc_(svc, "on_event.before(%s, %d, %s)", event, eventid, json_object_to_json_string(object));
945 static void hook_svc_on_event_after_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
947 _hook_svc_(svc, "on_event.after(%s, %d, %s)", event, eventid, json_object_to_json_string(object));
950 static void hook_svc_call_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
952 _hook_svc_(svc, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
955 static void hook_svc_call_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, int status, struct json_object *result)
957 _hook_svc_(svc, " ...call... -> %d: %s", status, json_object_to_json_string(result));
960 static void hook_svc_callsync_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
962 _hook_svc_(svc, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
965 static void hook_svc_callsync_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, int status, struct json_object *result)
967 _hook_svc_(svc, " ...callsync... -> %d: %s", status, json_object_to_json_string(result));
970 static struct afb_hook_svc_itf hook_svc_default_itf = {
971 .hook_svc_start_before = hook_svc_start_before_default_cb,
972 .hook_svc_start_after = hook_svc_start_after_default_cb,
973 .hook_svc_on_event_before = hook_svc_on_event_before_default_cb,
974 .hook_svc_on_event_after = hook_svc_on_event_after_default_cb,
975 .hook_svc_call = hook_svc_call_default_cb,
976 .hook_svc_call_result = hook_svc_call_result_default_cb,
977 .hook_svc_callsync = hook_svc_callsync_default_cb,
978 .hook_svc_callsync_result = hook_svc_callsync_result_default_cb
981 /******************************************************************************
982 * section: hooks for tracing service interface (svc)
983 *****************************************************************************/
985 #define _HOOK_SVC_(what,...) \
986 struct afb_hook_svc *hook; \
987 struct afb_hookid hookid; \
988 pthread_rwlock_rdlock(&rwlock); \
989 init_hookid(&hookid); \
990 hook = list_of_svc_hooks; \
992 if (hook->itf->hook_svc_##what \
993 && (hook->flags & afb_hook_flag_svc_##what) != 0 \
994 && (!hook->api || !strcasecmp(hook->api, svc->api))) { \
995 hook->itf->hook_svc_##what(hook->closure, &hookid, __VA_ARGS__); \
999 pthread_rwlock_unlock(&rwlock);
1001 void afb_hook_svc_start_before(const struct afb_svc *svc)
1003 _HOOK_SVC_(start_before, svc);
1006 int afb_hook_svc_start_after(const struct afb_svc *svc, int status)
1008 _HOOK_SVC_(start_after, svc, status);
1012 void afb_hook_svc_on_event_before(const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
1014 _HOOK_SVC_(on_event_before, svc, event, eventid, object);
1017 void afb_hook_svc_on_event_after(const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
1019 _HOOK_SVC_(on_event_after, svc, event, eventid, object);
1022 void afb_hook_svc_call(const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
1024 _HOOK_SVC_(call, svc, api, verb, args);
1027 void afb_hook_svc_call_result(const struct afb_svc *svc, int status, struct json_object *result)
1029 _HOOK_SVC_(call_result, svc, status, result);
1032 void afb_hook_svc_callsync(const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
1034 _HOOK_SVC_(callsync, svc, api, verb, args);
1037 int afb_hook_svc_callsync_result(const struct afb_svc *svc, int status, struct json_object *result)
1039 _HOOK_SVC_(callsync_result, svc, status, result);
1043 /******************************************************************************
1044 * section: hooking services (svc)
1045 *****************************************************************************/
1047 int afb_hook_flags_svc(const char *api)
1050 struct afb_hook_svc *hook;
1052 pthread_rwlock_rdlock(&rwlock);
1054 hook = list_of_svc_hooks;
1056 if (!api || !hook->api || !strcasecmp(hook->api, api))
1057 flags |= hook->flags;
1060 pthread_rwlock_unlock(&rwlock);
1064 struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_hook_svc_itf *itf, void *closure)
1066 struct afb_hook_svc *hook;
1068 /* alloc the result */
1069 hook = calloc(1, sizeof *hook);
1073 /* get a copy of the names */
1074 hook->api = api ? strdup(api) : NULL;
1075 if (api && !hook->api) {
1080 /* initialise the rest */
1082 hook->flags = flags;
1083 hook->itf = itf ? itf : &hook_svc_default_itf;
1084 hook->closure = closure;
1086 /* record the hook */
1087 pthread_rwlock_wrlock(&rwlock);
1088 hook->next = list_of_svc_hooks;
1089 list_of_svc_hooks = hook;
1090 pthread_rwlock_unlock(&rwlock);
1096 struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook)
1098 pthread_rwlock_wrlock(&rwlock);
1100 pthread_rwlock_unlock(&rwlock);
1104 void afb_hook_unref_svc(struct afb_hook_svc *hook)
1106 struct afb_hook_svc **prv;
1109 pthread_rwlock_wrlock(&rwlock);
1110 if (--hook->refcount)
1114 prv = &list_of_svc_hooks;
1115 while (*prv && *prv != hook)
1116 prv = &(*prv)->next;
1120 pthread_rwlock_unlock(&rwlock);
1129 /******************************************************************************
1130 * section: default callbacks for tracing service interface (evt)
1131 *****************************************************************************/
1133 static void _hook_evt_(const char *evt, int id, const char *format, ...)
1136 va_start(ap, format);
1137 _hook_("evt-%s:%d", format, ap, evt, id);
1141 static void hook_evt_create_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1143 _hook_evt_(evt, id, "create");
1146 static void hook_evt_push_before_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
1148 _hook_evt_(evt, id, "push.before(%s)", json_object_to_json_string(obj));
1152 static void hook_evt_push_after_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
1154 _hook_evt_(evt, id, "push.after(%s) -> %d", json_object_to_json_string(obj), result);
1157 static void hook_evt_broadcast_before_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
1159 _hook_evt_(evt, id, "broadcast.before(%s)", json_object_to_json_string(obj));
1162 static void hook_evt_broadcast_after_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
1164 _hook_evt_(evt, id, "broadcast.after(%s) -> %d", json_object_to_json_string(obj), result);
1167 static void hook_evt_name_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1169 _hook_evt_(evt, id, "name");
1172 static void hook_evt_drop_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1174 _hook_evt_(evt, id, "drop");
1177 static struct afb_hook_evt_itf hook_evt_default_itf = {
1178 .hook_evt_create = hook_evt_create_default_cb,
1179 .hook_evt_push_before = hook_evt_push_before_default_cb,
1180 .hook_evt_push_after = hook_evt_push_after_default_cb,
1181 .hook_evt_broadcast_before = hook_evt_broadcast_before_default_cb,
1182 .hook_evt_broadcast_after = hook_evt_broadcast_after_default_cb,
1183 .hook_evt_name = hook_evt_name_default_cb,
1184 .hook_evt_drop = hook_evt_drop_default_cb
1187 /******************************************************************************
1188 * section: hooks for tracing events interface (evt)
1189 *****************************************************************************/
1191 #define _HOOK_EVT_(what,...) \
1192 struct afb_hook_evt *hook; \
1193 struct afb_hookid hookid; \
1194 pthread_rwlock_rdlock(&rwlock); \
1195 init_hookid(&hookid); \
1196 hook = list_of_evt_hooks; \
1198 if (hook->itf->hook_evt_##what \
1199 && (hook->flags & afb_hook_flag_evt_##what) != 0 \
1200 && (!hook->pattern || !fnmatch(hook->pattern, evt, FNM_CASEFOLD))) { \
1201 hook->itf->hook_evt_##what(hook->closure, &hookid, __VA_ARGS__); \
1203 hook = hook->next; \
1205 pthread_rwlock_unlock(&rwlock);
1207 void afb_hook_evt_create(const char *evt, int id)
1209 _HOOK_EVT_(create, evt, id);
1212 void afb_hook_evt_push_before(const char *evt, int id, struct json_object *obj)
1214 _HOOK_EVT_(push_before, evt, id, obj);
1217 int afb_hook_evt_push_after(const char *evt, int id, struct json_object *obj, int result)
1219 _HOOK_EVT_(push_after, evt, id, obj, result);
1223 void afb_hook_evt_broadcast_before(const char *evt, int id, struct json_object *obj)
1225 _HOOK_EVT_(broadcast_before, evt, id, obj);
1228 int afb_hook_evt_broadcast_after(const char *evt, int id, struct json_object *obj, int result)
1230 _HOOK_EVT_(broadcast_after, evt, id, obj, result);
1234 void afb_hook_evt_name(const char *evt, int id)
1236 _HOOK_EVT_(name, evt, id);
1239 void afb_hook_evt_drop(const char *evt, int id)
1241 _HOOK_EVT_(drop, evt, id);
1244 /******************************************************************************
1245 * section: hooking services (evt)
1246 *****************************************************************************/
1248 int afb_hook_flags_evt(const char *name)
1251 struct afb_hook_evt *hook;
1253 pthread_rwlock_rdlock(&rwlock);
1255 hook = list_of_evt_hooks;
1257 if (!name || !hook->pattern || !fnmatch(hook->pattern, name, FNM_CASEFOLD))
1258 flags |= hook->flags;
1261 pthread_rwlock_unlock(&rwlock);
1265 struct afb_hook_evt *afb_hook_create_evt(const char *pattern, int flags, struct afb_hook_evt_itf *itf, void *closure)
1267 struct afb_hook_evt *hook;
1269 /* alloc the result */
1270 hook = calloc(1, sizeof *hook);
1274 /* get a copy of the names */
1275 hook->pattern = pattern ? strdup(pattern) : NULL;
1276 if (pattern && !hook->pattern) {
1281 /* initialise the rest */
1283 hook->flags = flags;
1284 hook->itf = itf ? itf : &hook_evt_default_itf;
1285 hook->closure = closure;
1287 /* record the hook */
1288 pthread_rwlock_wrlock(&rwlock);
1289 hook->next = list_of_evt_hooks;
1290 list_of_evt_hooks = hook;
1291 pthread_rwlock_unlock(&rwlock);
1297 struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook)
1299 pthread_rwlock_wrlock(&rwlock);
1301 pthread_rwlock_unlock(&rwlock);
1305 void afb_hook_unref_evt(struct afb_hook_evt *hook)
1307 struct afb_hook_evt **prv;
1310 pthread_rwlock_wrlock(&rwlock);
1311 if (--hook->refcount)
1315 prv = &list_of_evt_hooks;
1316 while (*prv && *prv != hook)
1317 prv = &(*prv)->next;
1321 pthread_rwlock_unlock(&rwlock);
1324 free(hook->pattern);
1330 /******************************************************************************
1331 * section: default callbacks for globals (global)
1332 *****************************************************************************/
1334 static void _hook_global_(const char *format, ...)
1337 va_start(ap, format);
1338 _hook_("global", format, ap);
1342 static void hook_global_vverbose_default_cb(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
1349 len = vasprintf(&msg, fmt, ap);
1353 _hook_global_("vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt);
1355 _hook_global_("vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg);
1360 static struct afb_hook_global_itf hook_global_default_itf = {
1361 .hook_global_vverbose = hook_global_vverbose_default_cb
1364 /******************************************************************************
1365 * section: hooks for tracing globals (global)
1366 *****************************************************************************/
1368 #define _HOOK_GLOBAL_(what,...) \
1369 struct afb_hook_global *hook; \
1370 struct afb_hookid hookid; \
1371 pthread_rwlock_rdlock(&rwlock); \
1372 init_hookid(&hookid); \
1373 hook = list_of_global_hooks; \
1375 if (hook->itf->hook_global_##what \
1376 && (hook->flags & afb_hook_flag_global_##what) != 0) { \
1377 hook->itf->hook_global_##what(hook->closure, &hookid, __VA_ARGS__); \
1379 hook = hook->next; \
1381 pthread_rwlock_unlock(&rwlock);
1383 static void afb_hook_global_vverbose(int level, const char *file, int line, const char *func, const char *fmt, va_list args)
1385 _HOOK_GLOBAL_(vverbose, level, file ?: "?", line, func ?: "?", fmt, args);
1388 /******************************************************************************
1389 * section: hooking globals (global)
1390 *****************************************************************************/
1392 static void update_global()
1394 struct afb_hook_global *hook;
1397 pthread_rwlock_rdlock(&rwlock);
1398 hook = list_of_global_hooks;
1400 flags = hook->flags;
1403 verbose_observer = (flags & afb_hook_flag_global_vverbose) ? afb_hook_global_vverbose : NULL;
1404 pthread_rwlock_unlock(&rwlock);
1407 struct afb_hook_global *afb_hook_create_global(int flags, struct afb_hook_global_itf *itf, void *closure)
1409 struct afb_hook_global *hook;
1411 /* alloc the result */
1412 hook = calloc(1, sizeof *hook);
1416 /* initialise the rest */
1418 hook->flags = flags;
1419 hook->itf = itf ? itf : &hook_global_default_itf;
1420 hook->closure = closure;
1422 /* record the hook */
1423 pthread_rwlock_wrlock(&rwlock);
1424 hook->next = list_of_global_hooks;
1425 list_of_global_hooks = hook;
1426 pthread_rwlock_unlock(&rwlock);
1428 /* update hooking */
1435 struct afb_hook_global *afb_hook_addref_global(struct afb_hook_global *hook)
1437 pthread_rwlock_wrlock(&rwlock);
1439 pthread_rwlock_unlock(&rwlock);
1443 void afb_hook_unref_global(struct afb_hook_global *hook)
1445 struct afb_hook_global **prv;
1448 pthread_rwlock_wrlock(&rwlock);
1449 if (--hook->refcount)
1453 prv = &list_of_global_hooks;
1454 while (*prv && *prv != hook)
1455 prv = &(*prv)->next;
1459 pthread_rwlock_unlock(&rwlock);
1464 /* update hooking */