+static char *_pbuf_(const char *fmt, va_list args, char **palloc, char *sbuf, size_t szsbuf, size_t *outlen)
+{
+ int rc;
+ va_list cp;
+
+ *palloc = NULL;
+ va_copy(cp, args);
+ rc = vsnprintf(sbuf, szsbuf, fmt, args);
+ if ((size_t)rc >= szsbuf) {
+ sbuf[szsbuf-1] = 0;
+ sbuf[szsbuf-2] = sbuf[szsbuf-3] = sbuf[szsbuf-4] = '.';
+ rc = vasprintf(palloc, fmt, cp);
+ if (rc >= 0)
+ sbuf = *palloc;
+ }
+ va_end(cp);
+ if (rc >= 0 && outlen)
+ *outlen = (size_t)rc;
+ return sbuf;
+}
+
+#if 0 /* old behaviour: use NOTICE */
+static void _hook_(const char *fmt1, const char *fmt2, va_list arg2, ...)
+{
+ char *tag, *data, *mem1, *mem2, buf1[256], buf2[2000];
+ va_list arg1;
+
+ data = _pbuf_(fmt2, arg2, &mem2, buf2, sizeof buf2, NULL);
+
+ va_start(arg1, arg2);
+ tag = _pbuf_(fmt1, arg1, &mem1, buf1, sizeof buf1, NULL);
+ va_end(arg1);
+
+ NOTICE("[HOOK %s] %s", tag, data);
+
+ free(mem1);
+ free(mem2);
+}
+#else /* new behaviour: emits directly to stderr */
+static void _hook_(const char *fmt1, const char *fmt2, va_list arg2, ...)
+{
+ static const char chars[] = "HOOK: [] \n";
+ char *mem1, *mem2, buf1[256], buf2[2000];
+ struct iovec iov[5];
+ va_list arg1;
+
+ iov[0].iov_base = (void*)&chars[0];
+ iov[0].iov_len = 7;
+
+ va_start(arg1, arg2);
+ iov[1].iov_base = _pbuf_(fmt1, arg1, &mem1, buf1, sizeof buf1, &iov[1].iov_len);
+ va_end(arg1);
+
+ iov[2].iov_base = (void*)&chars[7];
+ iov[2].iov_len = 2;
+
+ iov[3].iov_base = _pbuf_(fmt2, arg2, &mem2, buf2, sizeof buf2, &iov[3].iov_len);
+
+ iov[4].iov_base = (void*)&chars[9];
+ iov[4].iov_len = 1;
+
+ writev(2, iov, 5);
+
+ free(mem1);
+ free(mem2);
+}
+#endif
+
+static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->api, xreq->verb);
+ va_end(ap);
+}
+
+static void hook_xreq_begin_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+{
+ if (!xreq->cred)
+ _hook_xreq_(xreq, "BEGIN");
+ else
+ _hook_xreq_(xreq, "BEGIN uid=%d=%s gid=%d pid=%d label=%s id=%s",
+ (int)xreq->cred->uid,
+ xreq->cred->user,
+ (int)xreq->cred->gid,
+ (int)xreq->cred->pid,
+ xreq->cred->label?:"(null)",
+ xreq->cred->id?:"(null)"
+ );
+}
+
+static void hook_xreq_end_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+{
+ _hook_xreq_(xreq, "END");
+}
+
+static void hook_xreq_json_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj)
+{
+ _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj));
+}
+
+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)
+{
+ _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
+}
+
+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)
+{
+ _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info);
+}
+
+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)
+{
+ _hook_xreq_(xreq, "fail(%s, %s)", status, info);
+}
+
+static void hook_xreq_context_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value)
+{
+ _hook_xreq_(xreq, "context_get() -> %p", value);
+}
+
+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*))
+{
+ _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value);
+}
+
+static void hook_xreq_addref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+{
+ _hook_xreq_(xreq, "addref()");
+}
+
+static void hook_xreq_unref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+{
+ _hook_xreq_(xreq, "unref()");
+}
+
+static void hook_xreq_session_close_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
+{
+ _hook_xreq_(xreq, "session_close()");
+}
+
+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)
+{
+ _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result);
+}
+
+static void hook_xreq_subscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result)
+{
+ _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_event_fullname(eventid), afb_evt_event_id(eventid), result);
+}
+
+static void hook_xreq_unsubscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result)
+{
+ _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_event_fullname(eventid), afb_evt_event_id(eventid), result);
+}
+
+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)
+{
+ _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
+}
+
+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)
+{
+ _hook_xreq_(xreq, " ...subcall... -> %d: %s", status, json_object_to_json_string(result));
+}
+
+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)
+{
+ _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
+}
+
+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)
+{
+ _hook_xreq_(xreq, " ...subcallsync... -> %d: %s", status, json_object_to_json_string(result));
+}
+
+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)