Improve log output format
[src/app-framework-binder.git] / src / afb-hook.c
1 /*
2  * Copyright (C) 2016, 2017 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
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
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <pthread.h>
25 #include <unistd.h>
26 #include <fnmatch.h>
27
28 #include <json-c/json.h>
29
30 #include <afb/afb-req-itf.h>
31 #include <afb/afb-event-itf.h>
32
33 #include "afb-context.h"
34 #include "afb-hook.h"
35 #include "afb-session.h"
36 #include "afb-cred.h"
37 #include "afb-xreq.h"
38 #include "afb-ditf.h"
39 #include "afb-svc.h"
40 #include "afb-evt.h"
41 #include "verbose.h"
42
43 /**
44  * Definition of a hook for xreq
45  */
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 */
55 };
56
57 /**
58  * Definition of a hook for ditf
59  */
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 */
67 };
68
69 /**
70  * Definition of a hook for svc
71  */
72 struct afb_hook_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 */
79 };
80
81 /**
82  * Definition of a hook for evt
83  */
84 struct afb_hook_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 */
91 };
92
93 /* synchronisation across threads */
94 static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
95
96 /* list of hooks for xreq */
97 static struct afb_hook_xreq *list_of_xreq_hooks = NULL;
98
99 /* list of hooks for ditf */
100 static struct afb_hook_ditf *list_of_ditf_hooks = NULL;
101
102 /* list of hooks for svc */
103 static struct afb_hook_svc *list_of_svc_hooks = NULL;
104
105 /* list of hooks for evt */
106 static struct afb_hook_evt *list_of_evt_hooks = NULL;
107
108 /******************************************************************************
109  * section: default callbacks for tracing requests
110  *****************************************************************************/
111
112 static char *_pbuf_(const char *fmt, va_list args, char **palloc, char *sbuf, size_t szsbuf)
113 {
114         int rc;
115         va_list cp;
116
117         *palloc = NULL;
118         va_copy(cp, args);
119         rc = vsnprintf(sbuf, szsbuf, fmt, args);
120         if ((size_t)rc >= szsbuf) {
121                 sbuf[szsbuf-1] = 0;
122                 sbuf[szsbuf-2] = sbuf[szsbuf-3] = sbuf[szsbuf-4] = '.';
123                 rc = vasprintf(palloc, fmt, cp);
124                 if (rc >= 0)
125                         sbuf = *palloc;
126         }
127         va_end(cp);
128         return sbuf;
129 }
130
131 static void _hook_(const char *fmt1, const char *fmt2, va_list arg2, ...)
132 {
133         char *tag, *data, *mem1, *mem2, buf1[256], buf2[2000];
134         va_list arg1;
135
136         data = _pbuf_(fmt2, arg2, &mem2, buf2, sizeof buf2);
137
138         va_start(arg1, arg2);
139         tag = _pbuf_(fmt1, arg1, &mem1, buf1, sizeof buf1);
140         va_end(arg1);
141
142         NOTICE("[HOOK %s] %s", tag, data);
143
144         free(mem1);
145         free(mem2);
146 }
147
148 static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...)
149 {
150         va_list ap;
151         va_start(ap, format);
152         _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->api, xreq->verb);
153         va_end(ap);
154 }
155
156 static void hook_xreq_begin_default_cb(void * closure, const struct afb_xreq *xreq)
157 {
158         if (!xreq->cred)
159                 _hook_xreq_(xreq, "BEGIN");
160         else
161                 _hook_xreq_(xreq, "BEGIN uid=%d=%s gid=%d pid=%d label=%s id=%s",
162                         (int)xreq->cred->uid,
163                         xreq->cred->user,
164                         (int)xreq->cred->gid,
165                         (int)xreq->cred->pid,
166                         xreq->cred->label?:"(null)",
167                         xreq->cred->id?:"(null)"
168                 );
169 }
170
171 static void hook_xreq_end_default_cb(void * closure, const struct afb_xreq *xreq)
172 {
173         _hook_xreq_(xreq, "END");
174 }
175
176 static void hook_xreq_json_default_cb(void * closure, const struct afb_xreq *xreq, struct json_object *obj)
177 {
178         _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj));
179 }
180
181 static void hook_xreq_get_default_cb(void * closure, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
182 {
183         _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
184 }
185
186 static void hook_xreq_success_default_cb(void * closure, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
187 {
188         _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info);
189 }
190
191 static void hook_xreq_fail_default_cb(void * closure, const struct afb_xreq *xreq, const char *status, const char *info)
192 {
193         _hook_xreq_(xreq, "fail(%s, %s)", status, info);
194 }
195
196 static void hook_xreq_context_get_default_cb(void * closure, const struct afb_xreq *xreq, void *value)
197 {
198         _hook_xreq_(xreq, "context_get() -> %p", value);
199 }
200
201 static void hook_xreq_context_set_default_cb(void * closure, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
202 {
203         _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value);
204 }
205
206 static void hook_xreq_addref_default_cb(void * closure, const struct afb_xreq *xreq)
207 {
208         _hook_xreq_(xreq, "addref()");
209 }
210
211 static void hook_xreq_unref_default_cb(void * closure, const struct afb_xreq *xreq)
212 {
213         _hook_xreq_(xreq, "unref()");
214 }
215
216 static void hook_xreq_session_close_default_cb(void * closure, const struct afb_xreq *xreq)
217 {
218         _hook_xreq_(xreq, "session_close()");
219 }
220
221 static void hook_xreq_session_set_LOA_default_cb(void * closure, const struct afb_xreq *xreq, unsigned level, int result)
222 {
223         _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result);
224 }
225
226 static void hook_xreq_subscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result)
227 {
228         _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_event_name(event), afb_evt_event_id(event), result);
229 }
230
231 static void hook_xreq_unsubscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result)
232 {
233         _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_event_name(event), afb_evt_event_id(event), result);
234 }
235
236 static void hook_xreq_subcall_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
237 {
238         _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
239 }
240
241 static void hook_xreq_subcall_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
242 {
243         _hook_xreq_(xreq, "    ...subcall... -> %d: %s", status, json_object_to_json_string(result));
244 }
245
246 static void hook_xreq_subcallsync_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
247 {
248         _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
249 }
250
251 static void hook_xreq_subcallsync_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
252 {
253         _hook_xreq_(xreq, "    ...subcallsync... -> %d: %s", status, json_object_to_json_string(result));
254 }
255
256 static void hook_xreq_vverbose_default_cb(void * closure, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
257 {
258         int len;
259         char *msg;
260         va_list ap;
261
262         va_copy(ap, args);
263         len = vasprintf(&msg, fmt, ap);
264         va_end(ap);
265
266         if (len < 0)
267                 _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt);
268         else {
269                 _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg);
270                 free(msg);
271         }
272 }
273
274 static struct afb_hook_xreq_itf hook_xreq_default_itf = {
275         .hook_xreq_begin = hook_xreq_begin_default_cb,
276         .hook_xreq_end = hook_xreq_end_default_cb,
277         .hook_xreq_json = hook_xreq_json_default_cb,
278         .hook_xreq_get = hook_xreq_get_default_cb,
279         .hook_xreq_success = hook_xreq_success_default_cb,
280         .hook_xreq_fail = hook_xreq_fail_default_cb,
281         .hook_xreq_context_get = hook_xreq_context_get_default_cb,
282         .hook_xreq_context_set = hook_xreq_context_set_default_cb,
283         .hook_xreq_addref = hook_xreq_addref_default_cb,
284         .hook_xreq_unref = hook_xreq_unref_default_cb,
285         .hook_xreq_session_close = hook_xreq_session_close_default_cb,
286         .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_default_cb,
287         .hook_xreq_subscribe = hook_xreq_subscribe_default_cb,
288         .hook_xreq_unsubscribe = hook_xreq_unsubscribe_default_cb,
289         .hook_xreq_subcall = hook_xreq_subcall_default_cb,
290         .hook_xreq_subcall_result = hook_xreq_subcall_result_default_cb,
291         .hook_xreq_subcallsync = hook_xreq_subcallsync_default_cb,
292         .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb,
293         .hook_xreq_vverbose = hook_xreq_vverbose_default_cb
294 };
295
296 /******************************************************************************
297  * section: hooks for tracing requests
298  *****************************************************************************/
299
300 #define _HOOK_XREQ_(what,...)   \
301         struct afb_hook_xreq *hook; \
302         pthread_rwlock_rdlock(&rwlock); \
303         hook = list_of_xreq_hooks; \
304         while (hook) { \
305                 if (hook->itf->hook_xreq_##what \
306                  && (hook->flags & afb_hook_flag_req_##what) != 0 \
307                  && (!hook->session || hook->session == xreq->context.session) \
308                  && (!hook->api || !strcasecmp(hook->api, xreq->api)) \
309                  && (!hook->verb || !strcasecmp(hook->verb, xreq->verb))) { \
310                         hook->itf->hook_xreq_##what(hook->closure, __VA_ARGS__); \
311                 } \
312                 hook = hook->next; \
313         } \
314         pthread_rwlock_unlock(&rwlock);
315
316
317 void afb_hook_xreq_begin(const struct afb_xreq *xreq)
318 {
319         _HOOK_XREQ_(begin, xreq);
320 }
321
322 void afb_hook_xreq_end(const struct afb_xreq *xreq)
323 {
324         _HOOK_XREQ_(end, xreq);
325 }
326
327 struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj)
328 {
329         _HOOK_XREQ_(json, xreq, obj);
330         return obj;
331 }
332
333 struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
334 {
335         _HOOK_XREQ_(get, xreq, name, arg);
336         return arg;
337 }
338
339 void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info)
340 {
341         _HOOK_XREQ_(success, xreq, obj, info);
342 }
343
344 void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info)
345 {
346         _HOOK_XREQ_(fail, xreq, status, info);
347 }
348
349 void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value)
350 {
351         _HOOK_XREQ_(context_get, xreq, value);
352         return value;
353 }
354
355 void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
356 {
357         _HOOK_XREQ_(context_set, xreq, value, free_value);
358 }
359
360 void afb_hook_xreq_addref(const struct afb_xreq *xreq)
361 {
362         _HOOK_XREQ_(addref, xreq);
363 }
364
365 void afb_hook_xreq_unref(const struct afb_xreq *xreq)
366 {
367         _HOOK_XREQ_(unref, xreq);
368 }
369
370 void afb_hook_xreq_session_close(const struct afb_xreq *xreq)
371 {
372         _HOOK_XREQ_(session_close, xreq);
373 }
374
375 int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result)
376 {
377         _HOOK_XREQ_(session_set_LOA, xreq, level, result);
378         return result;
379 }
380
381 int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
382 {
383         _HOOK_XREQ_(subscribe, xreq, event, result);
384         return result;
385 }
386
387 int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
388 {
389         _HOOK_XREQ_(unsubscribe, xreq, event, result);
390         return result;
391 }
392
393 void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
394 {
395         _HOOK_XREQ_(subcall, xreq, api, verb, args);
396 }
397
398 void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result)
399 {
400         _HOOK_XREQ_(subcall_result, xreq, status, result);
401 }
402
403 void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
404 {
405         _HOOK_XREQ_(subcallsync, xreq, api, verb, args);
406 }
407
408 int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result)
409 {
410         _HOOK_XREQ_(subcallsync_result, xreq, status, result);
411         return status;
412 }
413
414 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)
415 {
416         _HOOK_XREQ_(vverbose, xreq, level, file ?: "?", line, func ?: "?", fmt, args);
417 }
418
419 /******************************************************************************
420  * section: hooking xreqs
421  *****************************************************************************/
422
423 void afb_hook_init_xreq(struct afb_xreq *xreq)
424 {
425         static int reqindex;
426
427         int f, flags;
428         int add;
429         struct afb_hook_xreq *hook;
430
431         /* scan hook list to get the expected flags */
432         flags = 0;
433         pthread_rwlock_rdlock(&rwlock);
434         hook = list_of_xreq_hooks;
435         while (hook) {
436                 f = hook->flags & afb_hook_flags_req_all;
437                 add = f != 0
438                    && (!hook->session || hook->session == xreq->context.session)
439                    && (!hook->api || !strcasecmp(hook->api, xreq->api))
440                    && (!hook->verb || !strcasecmp(hook->verb, xreq->verb));
441                 if (add)
442                         flags |= f;
443                 hook = hook->next;
444         }
445         pthread_rwlock_unlock(&rwlock);
446
447         /* store the hooking data */
448         xreq->hookflags = flags;
449         if (flags) {
450                 pthread_rwlock_wrlock(&rwlock);
451                 if (++reqindex < 0)
452                         reqindex = 1;
453                 xreq->hookindex = reqindex;
454                 pthread_rwlock_unlock(&rwlock);
455         }
456 }
457
458 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)
459 {
460         struct afb_hook_xreq *hook;
461
462         /* alloc the result */
463         hook = calloc(1, sizeof *hook);
464         if (hook == NULL)
465                 return NULL;
466
467         /* get a copy of the names */
468         hook->api = api ? strdup(api) : NULL;
469         hook->verb = verb ? strdup(verb) : NULL;
470         if ((api && !hook->api) || (verb && !hook->verb)) {
471                 free(hook->api);
472                 free(hook->verb);
473                 free(hook);
474                 return NULL;
475         }
476
477         /* initialise the rest */
478         hook->session = session;
479         if (session)
480                 afb_session_addref(session);
481         hook->refcount = 1;
482         hook->flags = flags;
483         hook->itf = itf ? itf : &hook_xreq_default_itf;
484         hook->closure = closure;
485
486         /* record the hook */
487         pthread_rwlock_wrlock(&rwlock);
488         hook->next = list_of_xreq_hooks;
489         list_of_xreq_hooks = hook;
490         pthread_rwlock_unlock(&rwlock);
491
492         /* returns it */
493         return hook;
494 }
495
496 struct afb_hook_xreq *afb_hook_addref_xreq(struct afb_hook_xreq *hook)
497 {
498         pthread_rwlock_wrlock(&rwlock);
499         hook->refcount++;
500         pthread_rwlock_unlock(&rwlock);
501         return hook;
502 }
503
504 void afb_hook_unref_xreq(struct afb_hook_xreq *hook)
505 {
506         struct afb_hook_xreq **prv;
507
508         if (hook) {
509                 pthread_rwlock_wrlock(&rwlock);
510                 if (--hook->refcount)
511                         hook = NULL;
512                 else {
513                         /* unlink */
514                         prv = &list_of_xreq_hooks;
515                         while (*prv && *prv != hook)
516                                 prv = &(*prv)->next;
517                         if(*prv)
518                                 *prv = hook->next;
519                 }
520                 pthread_rwlock_unlock(&rwlock);
521                 if (hook) {
522                         /* free */
523                         free(hook->api);
524                         free(hook->verb);
525                         if (hook->session)
526                                 afb_session_unref(hook->session);
527                         free(hook);
528                 }
529         }
530 }
531
532 /******************************************************************************
533  * section: default callbacks for tracing daemon interface
534  *****************************************************************************/
535
536 static void _hook_ditf_(const struct afb_ditf *ditf, const char *format, ...)
537 {
538         va_list ap;
539         va_start(ap, format);
540         _hook_("ditf-%s", format, ap, ditf->api);
541         va_end(ap);
542 }
543
544 static void hook_ditf_event_broadcast_before_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct json_object *object)
545 {
546         _hook_ditf_(ditf, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object));
547 }
548
549 static void hook_ditf_event_broadcast_after_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
550 {
551         _hook_ditf_(ditf, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result);
552 }
553
554 static void hook_ditf_get_event_loop_cb(void *closure, const struct afb_ditf *ditf, struct sd_event *result)
555 {
556         _hook_ditf_(ditf, "get_event_loop() -> %p", result);
557 }
558
559 static void hook_ditf_get_user_bus_cb(void *closure, const struct afb_ditf *ditf, struct sd_bus *result)
560 {
561         _hook_ditf_(ditf, "get_user_bus() -> %p", result);
562 }
563
564 static void hook_ditf_get_system_bus_cb(void *closure, const struct afb_ditf *ditf, struct sd_bus *result)
565 {
566         _hook_ditf_(ditf, "get_system_bus() -> %p", result);
567 }
568
569 static void hook_ditf_vverbose_cb(void*closure, const struct afb_ditf *ditf, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
570 {
571         int len;
572         char *msg;
573         va_list ap;
574
575         va_copy(ap, args);
576         len = vasprintf(&msg, fmt, ap);
577         va_end(ap);
578
579         if (len < 0)
580                 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, function, fmt);
581         else {
582                 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, function, msg);
583                 free(msg);
584         }
585 }
586
587 static void hook_ditf_event_make_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct afb_event result)
588 {
589         _hook_ditf_(ditf, "event_make(%s) -> %s:%d", name, afb_evt_event_name(result), afb_evt_event_id(result));
590 }
591
592 static void hook_ditf_rootdir_get_fd_cb(void *closure, const struct afb_ditf *ditf, int result)
593 {
594         char path[PATH_MAX];
595         if (result < 0)
596                 _hook_ditf_(ditf, "rootdir_get_fd() -> %d, %m", result);
597         else {
598                 sprintf(path, "/proc/self/fd/%d", result);
599                 readlink(path, path, sizeof path);
600                 _hook_ditf_(ditf, "rootdir_get_fd() -> %d = %s", result, path);
601         }
602 }
603
604 static void hook_ditf_rootdir_open_locale_cb(void *closure, const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
605 {
606         char path[PATH_MAX];
607         if (!locale)
608                 locale = "(null)";
609         if (result < 0)
610                 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result);
611         else {
612                 sprintf(path, "/proc/self/fd/%d", result);
613                 readlink(path, path, sizeof path);
614                 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path);
615         }
616 }
617
618 static void hook_ditf_queue_job(void *closure, const struct afb_ditf *ditf, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
619 {
620         _hook_ditf_(ditf, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result);
621 }
622
623 static struct afb_hook_ditf_itf hook_ditf_default_itf = {
624         .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before_cb,
625         .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after_cb,
626         .hook_ditf_get_event_loop = hook_ditf_get_event_loop_cb,
627         .hook_ditf_get_user_bus = hook_ditf_get_user_bus_cb,
628         .hook_ditf_get_system_bus = hook_ditf_get_system_bus_cb,
629         .hook_ditf_vverbose = hook_ditf_vverbose_cb,
630         .hook_ditf_event_make = hook_ditf_event_make_cb,
631         .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd_cb,
632         .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale_cb,
633         .hook_ditf_queue_job = hook_ditf_queue_job
634 };
635
636 /******************************************************************************
637  * section: hooks for tracing daemon interface (ditf)
638  *****************************************************************************/
639
640 #define _HOOK_DITF_(what,...)   \
641         struct afb_hook_ditf *hook; \
642         pthread_rwlock_rdlock(&rwlock); \
643         hook = list_of_ditf_hooks; \
644         while (hook) { \
645                 if (hook->itf->hook_ditf_##what \
646                  && (hook->flags & afb_hook_flag_ditf_##what) != 0 \
647                  && (!hook->api || !strcasecmp(hook->api, ditf->api))) { \
648                         hook->itf->hook_ditf_##what(hook->closure, __VA_ARGS__); \
649                 } \
650                 hook = hook->next; \
651         } \
652         pthread_rwlock_unlock(&rwlock);
653
654 void afb_hook_ditf_event_broadcast_before(const struct afb_ditf *ditf, const char *name, struct json_object *object)
655 {
656         _HOOK_DITF_(event_broadcast_before, ditf, name, object);
657 }
658
659 int afb_hook_ditf_event_broadcast_after(const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
660 {
661         _HOOK_DITF_(event_broadcast_after, ditf, name, object, result);
662         return result;
663 }
664
665 struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_ditf *ditf, struct sd_event *result)
666 {
667         _HOOK_DITF_(get_event_loop, ditf, result);
668         return result;
669 }
670
671 struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_ditf *ditf, struct sd_bus *result)
672 {
673         _HOOK_DITF_(get_user_bus, ditf, result);
674         return result;
675 }
676
677 struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_ditf *ditf, struct sd_bus *result)
678 {
679         _HOOK_DITF_(get_system_bus, ditf, result);
680         return result;
681 }
682
683 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)
684 {
685         _HOOK_DITF_(vverbose, ditf, level, file, line, function, fmt, args);
686 }
687
688 struct afb_event afb_hook_ditf_event_make(const struct afb_ditf *ditf, const char *name, struct afb_event result)
689 {
690         _HOOK_DITF_(event_make, ditf, name, result);
691         return result;
692 }
693
694 int afb_hook_ditf_rootdir_get_fd(const struct afb_ditf *ditf, int result)
695 {
696         _HOOK_DITF_(rootdir_get_fd, ditf, result);
697         return result;
698 }
699
700 int afb_hook_ditf_rootdir_open_locale(const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
701 {
702         _HOOK_DITF_(rootdir_open_locale, ditf, filename, flags, locale, result);
703         return result;
704 }
705
706 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)
707 {
708         _HOOK_DITF_(queue_job, ditf, callback, argument, group, timeout, result);
709         return result;
710 }
711
712 /******************************************************************************
713  * section: hooking ditf
714  *****************************************************************************/
715
716 int afb_hook_flags_ditf(const char *api)
717 {
718         int flags;
719         struct afb_hook_ditf *hook;
720
721         pthread_rwlock_rdlock(&rwlock);
722         flags = 0;
723         hook = list_of_ditf_hooks;
724         while (hook) {
725                 if (!api || !hook->api || !strcasecmp(hook->api, api))
726                         flags |= hook->flags;
727                 hook = hook->next;
728         }
729         pthread_rwlock_unlock(&rwlock);
730         return flags;
731 }
732
733 struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure)
734 {
735         struct afb_hook_ditf *hook;
736
737         /* alloc the result */
738         hook = calloc(1, sizeof *hook);
739         if (hook == NULL)
740                 return NULL;
741
742         /* get a copy of the names */
743         hook->api = api ? strdup(api) : NULL;
744         if (api && !hook->api) {
745                 free(hook);
746                 return NULL;
747         }
748
749         /* initialise the rest */
750         hook->refcount = 1;
751         hook->flags = flags;
752         hook->itf = itf ? itf : &hook_ditf_default_itf;
753         hook->closure = closure;
754
755         /* record the hook */
756         pthread_rwlock_wrlock(&rwlock);
757         hook->next = list_of_ditf_hooks;
758         list_of_ditf_hooks = hook;
759         pthread_rwlock_unlock(&rwlock);
760
761         /* returns it */
762         return hook;
763 }
764
765 struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook)
766 {
767         pthread_rwlock_wrlock(&rwlock);
768         hook->refcount++;
769         pthread_rwlock_unlock(&rwlock);
770         return hook;
771 }
772
773 void afb_hook_unref_ditf(struct afb_hook_ditf *hook)
774 {
775         struct afb_hook_ditf **prv;
776
777         if (hook) {
778                 pthread_rwlock_wrlock(&rwlock);
779                 if (--hook->refcount)
780                         hook = NULL;
781                 else {
782                         /* unlink */
783                         prv = &list_of_ditf_hooks;
784                         while (*prv && *prv != hook)
785                                 prv = &(*prv)->next;
786                         if(*prv)
787                                 *prv = hook->next;
788                 }
789                 pthread_rwlock_unlock(&rwlock);
790                 if (hook) {
791                         /* free */
792                         free(hook->api);
793                         free(hook);
794                 }
795         }
796 }
797
798 /******************************************************************************
799  * section: default callbacks for tracing service interface (svc)
800  *****************************************************************************/
801
802 static void _hook_svc_(const struct afb_svc *svc, const char *format, ...)
803 {
804         va_list ap;
805         va_start(ap, format);
806         _hook_("svc-%s", format, ap, svc->api);
807         va_end(ap);
808 }
809
810 static void hook_svc_start_before_default_cb(void *closure, const struct afb_svc *svc)
811 {
812         _hook_svc_(svc, "start.before");
813 }
814
815 static void hook_svc_start_after_default_cb(void *closure, const struct afb_svc *svc, int status)
816 {
817         _hook_svc_(svc, "start.after -> %d", status);
818 }
819
820 static void hook_svc_on_event_before_default_cb(void *closure, const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
821 {
822         _hook_svc_(svc, "on_event.before(%s, %d, %s)", event, eventid, json_object_to_json_string(object));
823 }
824
825 static void hook_svc_on_event_after_default_cb(void *closure, const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
826 {
827         _hook_svc_(svc, "on_event.after(%s, %d, %s)", event, eventid, json_object_to_json_string(object));
828 }
829
830 static void hook_svc_call_default_cb(void *closure, const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
831 {
832         _hook_svc_(svc, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
833 }
834
835 static void hook_svc_call_result_default_cb(void *closure, const struct afb_svc *svc, int status, struct json_object *result)
836 {
837         _hook_svc_(svc, "    ...call... -> %d: %s", status, json_object_to_json_string(result));
838 }
839
840 static void hook_svc_callsync_default_cb(void *closure, const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
841 {
842         _hook_svc_(svc, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
843 }
844
845 static void hook_svc_callsync_result_default_cb(void *closure, const struct afb_svc *svc, int status, struct json_object *result)
846 {
847         _hook_svc_(svc, "    ...callsync... -> %d: %s", status, json_object_to_json_string(result));
848 }
849
850 static struct afb_hook_svc_itf hook_svc_default_itf = {
851         .hook_svc_start_before = hook_svc_start_before_default_cb,
852         .hook_svc_start_after = hook_svc_start_after_default_cb,
853         .hook_svc_on_event_before = hook_svc_on_event_before_default_cb,
854         .hook_svc_on_event_after = hook_svc_on_event_after_default_cb,
855         .hook_svc_call = hook_svc_call_default_cb,
856         .hook_svc_call_result = hook_svc_call_result_default_cb,
857         .hook_svc_callsync = hook_svc_callsync_default_cb,
858         .hook_svc_callsync_result = hook_svc_callsync_result_default_cb
859 };
860
861 /******************************************************************************
862  * section: hooks for tracing service interface (svc)
863  *****************************************************************************/
864
865 #define _HOOK_SVC_(what,...)   \
866         struct afb_hook_svc *hook; \
867         pthread_rwlock_rdlock(&rwlock); \
868         hook = list_of_svc_hooks; \
869         while (hook) { \
870                 if (hook->itf->hook_svc_##what \
871                  && (hook->flags & afb_hook_flag_svc_##what) != 0 \
872                  && (!hook->api || !strcasecmp(hook->api, svc->api))) { \
873                         hook->itf->hook_svc_##what(hook->closure, __VA_ARGS__); \
874                 } \
875                 hook = hook->next; \
876         } \
877         pthread_rwlock_unlock(&rwlock);
878
879 void afb_hook_svc_start_before(const struct afb_svc *svc)
880 {
881         _HOOK_SVC_(start_before, svc);
882 }
883
884 int afb_hook_svc_start_after(const struct afb_svc *svc, int status)
885 {
886         _HOOK_SVC_(start_after, svc, status);
887         return status;
888 }
889
890 void afb_hook_svc_on_event_before(const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
891 {
892         _HOOK_SVC_(on_event_before, svc, event, eventid, object);
893 }
894
895 void afb_hook_svc_on_event_after(const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
896 {
897         _HOOK_SVC_(on_event_after, svc, event, eventid, object);
898 }
899
900 void afb_hook_svc_call(const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
901 {
902         _HOOK_SVC_(call, svc, api, verb, args);
903 }
904
905 void afb_hook_svc_call_result(const struct afb_svc *svc, int status, struct json_object *result)
906 {
907         _HOOK_SVC_(call_result, svc, status, result);
908 }
909
910 void afb_hook_svc_callsync(const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
911 {
912         _HOOK_SVC_(callsync, svc, api, verb, args);
913 }
914
915 int afb_hook_svc_callsync_result(const struct afb_svc *svc, int status, struct json_object *result)
916 {
917         _HOOK_SVC_(callsync_result, svc, status, result);
918         return status;
919 }
920
921 /******************************************************************************
922  * section: hooking services (svc)
923  *****************************************************************************/
924
925 int afb_hook_flags_svc(const char *api)
926 {
927         int flags;
928         struct afb_hook_svc *hook;
929
930         pthread_rwlock_rdlock(&rwlock);
931         flags = 0;
932         hook = list_of_svc_hooks;
933         while (hook) {
934                 if (!api || !hook->api || !strcasecmp(hook->api, api))
935                         flags |= hook->flags;
936                 hook = hook->next;
937         }
938         pthread_rwlock_unlock(&rwlock);
939         return flags;
940 }
941
942 struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_hook_svc_itf *itf, void *closure)
943 {
944         struct afb_hook_svc *hook;
945
946         /* alloc the result */
947         hook = calloc(1, sizeof *hook);
948         if (hook == NULL)
949                 return NULL;
950
951         /* get a copy of the names */
952         hook->api = api ? strdup(api) : NULL;
953         if (api && !hook->api) {
954                 free(hook);
955                 return NULL;
956         }
957
958         /* initialise the rest */
959         hook->refcount = 1;
960         hook->flags = flags;
961         hook->itf = itf ? itf : &hook_svc_default_itf;
962         hook->closure = closure;
963
964         /* record the hook */
965         pthread_rwlock_wrlock(&rwlock);
966         hook->next = list_of_svc_hooks;
967         list_of_svc_hooks = hook;
968         pthread_rwlock_unlock(&rwlock);
969
970         /* returns it */
971         return hook;
972 }
973
974 struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook)
975 {
976         pthread_rwlock_wrlock(&rwlock);
977         hook->refcount++;
978         pthread_rwlock_unlock(&rwlock);
979         return hook;
980 }
981
982 void afb_hook_unref_svc(struct afb_hook_svc *hook)
983 {
984         struct afb_hook_svc **prv;
985
986         if (hook) {
987                 pthread_rwlock_wrlock(&rwlock);
988                 if (--hook->refcount)
989                         hook = NULL;
990                 else {
991                         /* unlink */
992                         prv = &list_of_svc_hooks;
993                         while (*prv && *prv != hook)
994                                 prv = &(*prv)->next;
995                         if(*prv)
996                                 *prv = hook->next;
997                 }
998                 pthread_rwlock_unlock(&rwlock);
999                 if (hook) {
1000                         /* free */
1001                         free(hook->api);
1002                         free(hook);
1003                 }
1004         }
1005 }
1006
1007 /******************************************************************************
1008  * section: default callbacks for tracing service interface (evt)
1009  *****************************************************************************/
1010
1011 static void _hook_evt_(const char *evt, int id, const char *format, ...)
1012 {
1013         va_list ap;
1014         va_start(ap, format);
1015         _hook_("evt-%s:%d", format, ap, evt, id);
1016         va_end(ap);
1017 }
1018
1019 static void hook_evt_create_default_cb(void *closure, const char *evt, int id)
1020 {
1021         _hook_evt_(evt, id, "create");
1022 }
1023
1024 static void hook_evt_push_before_default_cb(void *closure, const char *evt, int id, struct json_object *obj)
1025 {
1026         _hook_evt_(evt, id, "push.before(%s)", json_object_to_json_string(obj));
1027 }
1028
1029
1030 static void hook_evt_push_after_default_cb(void *closure, const char *evt, int id, struct json_object *obj, int result)
1031 {
1032         _hook_evt_(evt, id, "push.after(%s) -> %d", json_object_to_json_string(obj), result);
1033 }
1034
1035 static void hook_evt_broadcast_before_default_cb(void *closure, const char *evt, int id, struct json_object *obj)
1036 {
1037         _hook_evt_(evt, id, "broadcast.before(%s)", json_object_to_json_string(obj));
1038 }
1039
1040 static void hook_evt_broadcast_after_default_cb(void *closure, const char *evt, int id, struct json_object *obj, int result)
1041 {
1042         _hook_evt_(evt, id, "broadcast.after(%s) -> %d", json_object_to_json_string(obj), result);
1043 }
1044
1045 static void hook_evt_name_default_cb(void *closure, const char *evt, int id)
1046 {
1047         _hook_evt_(evt, id, "name");
1048 }
1049
1050 static void hook_evt_drop_default_cb(void *closure, const char *evt, int id)
1051 {
1052         _hook_evt_(evt, id, "drop");
1053 }
1054
1055 static struct afb_hook_evt_itf hook_evt_default_itf = {
1056         .hook_evt_create = hook_evt_create_default_cb,
1057         .hook_evt_push_before = hook_evt_push_before_default_cb,
1058         .hook_evt_push_after = hook_evt_push_after_default_cb,
1059         .hook_evt_broadcast_before = hook_evt_broadcast_before_default_cb,
1060         .hook_evt_broadcast_after = hook_evt_broadcast_after_default_cb,
1061         .hook_evt_name = hook_evt_name_default_cb,
1062         .hook_evt_drop = hook_evt_drop_default_cb
1063 };
1064
1065 /******************************************************************************
1066  * section: hooks for tracing service interface (evt)
1067  *****************************************************************************/
1068
1069 #define _HOOK_EVT_(what,...)   \
1070         struct afb_hook_evt *hook; \
1071         pthread_rwlock_rdlock(&rwlock); \
1072         hook = list_of_evt_hooks; \
1073         while (hook) { \
1074                 if (hook->itf->hook_evt_##what \
1075                  && (hook->flags & afb_hook_flag_evt_##what) != 0 \
1076                  && (!hook->pattern || !fnmatch(hook->pattern, evt, FNM_CASEFOLD))) { \
1077                         hook->itf->hook_evt_##what(hook->closure, __VA_ARGS__); \
1078                 } \
1079                 hook = hook->next; \
1080         } \
1081         pthread_rwlock_unlock(&rwlock);
1082
1083 void afb_hook_evt_create(const char *evt, int id)
1084 {
1085         _HOOK_EVT_(create, evt, id);
1086 }
1087
1088 void afb_hook_evt_push_before(const char *evt, int id, struct json_object *obj)
1089 {
1090         _HOOK_EVT_(push_before, evt, id, obj);
1091 }
1092
1093 int afb_hook_evt_push_after(const char *evt, int id, struct json_object *obj, int result)
1094 {
1095         _HOOK_EVT_(push_after, evt, id, obj, result);
1096         return result;
1097 }
1098
1099 void afb_hook_evt_broadcast_before(const char *evt, int id, struct json_object *obj)
1100 {
1101         _HOOK_EVT_(broadcast_before, evt, id, obj);
1102 }
1103
1104 int afb_hook_evt_broadcast_after(const char *evt, int id, struct json_object *obj, int result)
1105 {
1106         _HOOK_EVT_(broadcast_after, evt, id, obj, result);
1107         return result;
1108 }
1109
1110 void afb_hook_evt_name(const char *evt, int id)
1111 {
1112         _HOOK_EVT_(name, evt, id);
1113 }
1114
1115 void afb_hook_evt_drop(const char *evt, int id)
1116 {
1117         _HOOK_EVT_(drop, evt, id);
1118 }
1119
1120 /******************************************************************************
1121  * section: hooking services (evt)
1122  *****************************************************************************/
1123
1124 int afb_hook_flags_evt(const char *name)
1125 {
1126         int flags;
1127         struct afb_hook_evt *hook;
1128
1129         pthread_rwlock_rdlock(&rwlock);
1130         flags = 0;
1131         hook = list_of_evt_hooks;
1132         while (hook) {
1133                 if (!name || !hook->pattern || !fnmatch(hook->pattern, name, FNM_CASEFOLD))
1134                         flags |= hook->flags;
1135                 hook = hook->next;
1136         }
1137         pthread_rwlock_unlock(&rwlock);
1138         return flags;
1139 }
1140
1141 struct afb_hook_evt *afb_hook_create_evt(const char *pattern, int flags, struct afb_hook_evt_itf *itf, void *closure)
1142 {
1143         struct afb_hook_evt *hook;
1144
1145         /* alloc the result */
1146         hook = calloc(1, sizeof *hook);
1147         if (hook == NULL)
1148                 return NULL;
1149
1150         /* get a copy of the names */
1151         hook->pattern = pattern ? strdup(pattern) : NULL;
1152         if (pattern && !hook->pattern) {
1153                 free(hook);
1154                 return NULL;
1155         }
1156
1157         /* initialise the rest */
1158         hook->refcount = 1;
1159         hook->flags = flags;
1160         hook->itf = itf ? itf : &hook_evt_default_itf;
1161         hook->closure = closure;
1162
1163         /* record the hook */
1164         pthread_rwlock_wrlock(&rwlock);
1165         hook->next = list_of_evt_hooks;
1166         list_of_evt_hooks = hook;
1167         pthread_rwlock_unlock(&rwlock);
1168
1169         /* returns it */
1170         return hook;
1171 }
1172
1173 struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook)
1174 {
1175         pthread_rwlock_wrlock(&rwlock);
1176         hook->refcount++;
1177         pthread_rwlock_unlock(&rwlock);
1178         return hook;
1179 }
1180
1181 void afb_hook_unref_evt(struct afb_hook_evt *hook)
1182 {
1183         struct afb_hook_evt **prv;
1184
1185         if (hook) {
1186                 pthread_rwlock_wrlock(&rwlock);
1187                 if (--hook->refcount)
1188                         hook = NULL;
1189                 else {
1190                         /* unlink */
1191                         prv = &list_of_evt_hooks;
1192                         while (*prv && *prv != hook)
1193                                 prv = &(*prv)->next;
1194                         if(*prv)
1195                                 *prv = hook->next;
1196                 }
1197                 pthread_rwlock_unlock(&rwlock);
1198                 if (hook) {
1199                         /* free */
1200                         free(hook->pattern);
1201                         free(hook);
1202                 }
1203         }
1204 }