hooks: Allow to remove hooking (and/or trace)
[src/app-framework-binder.git] / src / afb-hook-flags.c
1 /*
2  * Copyright (C) 2018, 2019 "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 #if WITH_AFB_HOOK  /***********************************************************/
19
20 #define _GNU_SOURCE
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25
26 #include "afb-hook.h"
27 #include "afb-hook-flags.h"
28
29 /* structure for searching flags by names */
30 struct flag
31 {
32         const char *name;       /** the name */
33         int value;              /** the value */
34 };
35
36 struct flags
37 {
38         struct flag *flags;
39         int count;
40 };
41
42 #define FLAGS(x)   ((struct flags){ .flags = x, .count = (int)(sizeof x / sizeof * x) })
43
44 static struct flag xreq_flags[] = { /* must be sorted by names */
45                 { "addref",             afb_hook_flag_req_addref },
46                 { "all",                afb_hook_flags_req_all },
47                 { "args",               afb_hook_flags_req_args },
48                 { "begin",              afb_hook_flag_req_begin },
49                 { "common",             afb_hook_flags_req_common },
50                 { "context",            afb_hook_flags_req_context },
51                 { "context_get",        afb_hook_flag_req_legacy_context_get },
52                 { "context_make",       afb_hook_flag_req_context_make },
53                 { "context_set",        afb_hook_flag_req_legacy_context_set },
54                 { "end",                afb_hook_flag_req_end },
55                 { "event",              afb_hook_flags_req_event },
56                 { "extra",              afb_hook_flags_req_extra },
57                 { "get",                afb_hook_flag_req_get },
58                 { "get_application_id", afb_hook_flag_req_get_application_id },
59                 { "get_client_info",    afb_hook_flag_req_get_client_info },
60                 { "get_uid",            afb_hook_flag_req_get_uid },
61                 { "has_permission",     afb_hook_flag_req_has_permission },
62                 { "json",               afb_hook_flag_req_json },
63                 { "life",               afb_hook_flags_req_life },
64                 { "ref",                afb_hook_flags_req_ref },
65                 { "reply",              afb_hook_flag_req_reply },
66                 { "security",           afb_hook_flags_req_security },
67                 { "session",            afb_hook_flags_req_session },
68                 { "session_close",      afb_hook_flag_req_session_close },
69                 { "session_set_LOA",    afb_hook_flag_req_session_set_LOA },
70                 { "store",              afb_hook_flag_req_legacy_store },
71                 { "stores",             afb_hook_flags_req_stores },
72                 { "subcall",            afb_hook_flag_req_subcall },
73                 { "subcall_result",     afb_hook_flag_req_subcall_result },
74                 { "subcalls",           afb_hook_flags_req_subcalls },
75                 { "subcallsync",        afb_hook_flag_req_subcallsync },
76                 { "subcallsync_result", afb_hook_flag_req_subcallsync_result },
77                 { "subscribe",          afb_hook_flag_req_subscribe },
78                 { "unref",              afb_hook_flag_req_unref },
79                 { "unstore",            afb_hook_flag_req_legacy_unstore },
80                 { "unsubscribe",        afb_hook_flag_req_unsubscribe },
81                 { "vverbose",           afb_hook_flag_req_vverbose },
82 };
83
84 static struct flag api_flags[] = { /* must be sorted by names */
85                 { "add_alias",          afb_hook_flag_api_add_alias },
86                 { "all",                afb_hook_flags_api_all },
87                 { "api_add_verb",       afb_hook_flag_api_api_add_verb },
88                 { "api",                afb_hook_flags_api_api },
89                 { "api_del_verb",       afb_hook_flag_api_api_del_verb },
90                 { "api_seal",           afb_hook_flag_api_api_seal },
91                 { "api_set_on_event",   afb_hook_flag_api_api_set_on_event },
92                 { "api_set_on_init",    afb_hook_flag_api_api_set_on_init },
93                 { "api_set_verbs",      afb_hook_flag_api_api_set_verbs },
94                 { "call",               afb_hook_flag_api_call },
95                 { "callsync",           afb_hook_flag_api_callsync },
96                 { "class_provide",      afb_hook_flag_api_class_provide },
97                 { "class_require",      afb_hook_flag_api_class_require },
98                 { "common",             afb_hook_flags_api_common },
99                 { "delete_api",         afb_hook_flag_api_delete_api },
100                 { "event",              afb_hook_flags_api_event },
101                 { "event_broadcast",    afb_hook_flag_api_event_broadcast },
102                 { "event_handler_add",  afb_hook_flag_api_event_handler_add },
103                 { "event_handler_del",  afb_hook_flag_api_event_handler_del },
104                 { "event_make",         afb_hook_flag_api_event_make },
105                 { "extra",              afb_hook_flags_api_extra },
106                 { "get_event_loop",     afb_hook_flag_api_get_event_loop },
107                 { "get_system_bus",     afb_hook_flag_api_get_system_bus },
108                 { "get_user_bus",       afb_hook_flag_api_get_user_bus },
109                 { "legacy_unstore_req", afb_hook_flag_api_legacy_unstore_req },
110                 { "new_api",            afb_hook_flag_api_new_api },
111                 { "on_event",           afb_hook_flag_api_on_event },
112                 { "on_event_handler",   afb_hook_flag_api_on_event_handler },
113                 { "queue_job",          afb_hook_flag_api_queue_job },
114                 { "require_api",        afb_hook_flag_api_require_api },
115                 { "rootdir_get_fd",     afb_hook_flag_api_rootdir_get_fd },
116                 { "rootdir_open_locale",afb_hook_flag_api_rootdir_open_locale },
117                 { "settings",           afb_hook_flag_api_settings },
118                 { "start",              afb_hook_flag_api_start },
119                 { "vverbose",           afb_hook_flag_api_vverbose },
120 };
121
122 static struct flag evt_flags[] = { /* must be sorted by names */
123                 { "addref",             afb_hook_flag_evt_addref },
124                 { "all",                afb_hook_flags_evt_all },
125                 { "broadcast_after",    afb_hook_flag_evt_broadcast_after },
126                 { "broadcast_before",   afb_hook_flag_evt_broadcast_before },
127                 { "common",             afb_hook_flags_evt_common },
128                 { "create",             afb_hook_flag_evt_create },
129                 { "extra",              afb_hook_flags_evt_extra },
130                 { "name",               afb_hook_flag_evt_name },
131                 { "push_after",         afb_hook_flag_evt_push_after },
132                 { "push_before",        afb_hook_flag_evt_push_before },
133                 { "unref",              afb_hook_flag_evt_unref },
134 };
135
136 static struct flag session_flags[] = { /* must be sorted by names */
137                 { "addref",             afb_hook_flag_session_addref },
138                 { "all",                afb_hook_flags_session_all },
139                 { "close",              afb_hook_flag_session_close },
140                 { "common",             afb_hook_flags_session_common },
141                 { "create",             afb_hook_flag_session_create },
142                 { "destroy",            afb_hook_flag_session_destroy },
143                 { "renew",              afb_hook_flag_session_renew },
144                 { "unref",              afb_hook_flag_session_unref },
145 };
146
147 static struct flag global_flags[] = { /* must be sorted by names */
148                 { "all",                afb_hook_flags_global_all },
149                 { "vverbose",           afb_hook_flag_global_vverbose },
150 };
151
152 static int compare(const char *query, const char *value, size_t query_length)
153 {
154         size_t i;
155         char q, v;
156
157         for (i = 0 ; i < query_length ; i++) {
158                 v = value[i];
159                 q = query[i];
160                 if (!v)
161                         return -1;
162                 v = v == '_' ? '-' : (char)toupper(v);
163                 q = q == '_' ? '-' : (char)toupper(q);
164                 if (q != v)
165                         return (int)((unsigned)q - (unsigned)v);
166         }
167         return !!value[i];
168 }
169
170 /* get the value of the flag of 'name' in the array 'flags' of 'count elements */
171 static int get_flag(const char *name, struct flags flags, size_t length)
172 {
173         /* replace "*" by "all" */
174         if (length == 1 && *name == '*') {
175                 name = "all";
176                 length = 3;
177         }
178
179         /* dichotomic search */
180         int lower = 0, upper = flags.count;
181         while (lower < upper) {
182                 int mid = (lower + upper) >> 1;
183                 int cmp = compare(name, flags.flags[mid].name, length);
184                 if (!cmp)
185                         return flags.flags[mid].value;
186                 if (cmp < 0)
187                         upper = mid;
188                 else
189                         lower = mid + 1;
190         }
191
192         return -(compare(name, "no", length) && compare(name, "none", length));
193 }
194
195 static int from_text(const char *text, struct flags flags)
196 {
197         static const char sep[] = " \t,";
198         size_t s;
199         int result = 0, val;
200
201         if (text) {
202                 for (;;) {
203                         text += strspn(text, sep);
204                         if (!*text)
205                                 break;
206                         s = strcspn(text, sep);
207                         val = get_flag(text, flags, s);
208                         if (val == -1)
209                                 return val;
210                         result |= val;
211                         text += s;
212                 }
213         }
214         return result;
215 }
216
217 static char *to_text(int value, struct flags flags)
218 {
219         int borrow = 0, mask = 0, i, v, imask;
220         size_t s = 0;
221         char *result = NULL;
222
223         if (!value)
224                 return strdup("none");
225
226         do {
227                 if (s) {
228                         result = malloc(s + 1);
229                         if (!result)
230                                 break;
231                 }
232                 borrow = 0;
233                 while (borrow != value) {
234                         mask = imask = 0;
235                         i = flags.count;
236                         while (i) {
237                                 v = flags.flags[--i].value;
238                                 if ((mask & v) == mask && (borrow & v) == 0 && (value & v) == v) {
239                                         mask = v;
240                                         imask = i;
241                                 }
242                         }
243                         if (mask == 0)
244                                 borrow = value;
245                         else {
246                                 if (!result)
247                                         s += strlen(flags.flags[imask].name) + !!s;
248                                 else {
249                                         if (s)
250                                                 result[s++] = ',';
251                                         strcpy(&result[s], flags.flags[imask].name);
252                                         s += strlen(flags.flags[imask].name);
253                                 }
254                         }
255                 }
256         } while (!result);
257         return result;
258 }
259
260 int afb_hook_flags_xreq_from_text(const char *text)
261 {
262         return from_text(text, FLAGS(xreq_flags));
263 }
264
265 int afb_hook_flags_api_from_text(const char *text)
266 {
267         return from_text(text, FLAGS(api_flags));
268 }
269
270 int afb_hook_flags_evt_from_text(const char *text)
271 {
272         return from_text(text, FLAGS(evt_flags));
273 }
274
275 int afb_hook_flags_session_from_text(const char *text)
276 {
277         return from_text(text, FLAGS(session_flags));
278 }
279
280 int afb_hook_flags_global_from_text(const char *text)
281 {
282         return from_text(text, FLAGS(global_flags));
283 }
284
285 char *afb_hook_flags_xreq_to_text(int value)
286 {
287         return to_text(value, FLAGS(xreq_flags));
288 }
289
290 char *afb_hook_flags_api_to_text(int value)
291 {
292         return to_text(value, FLAGS(api_flags));
293 }
294
295 char *afb_hook_flags_evt_to_text(int value)
296 {
297         return to_text(value, FLAGS(evt_flags));
298 }
299
300 char *afb_hook_flags_session_to_text(int value)
301 {
302         return to_text(value, FLAGS(session_flags));
303 }
304
305 char *afb_hook_flags_global_to_text(int value)
306 {
307         return to_text(value, FLAGS(global_flags));
308 }
309
310 #if !defined(REMOVE_LEGACY_TRACE)
311 static struct flag legacy_ditf_flags[] = { /* must be sorted by names */
312                 { "all",                        afb_hook_flags_api_ditf_all },
313                 { "common",                     afb_hook_flags_api_ditf_common },
314                 { "event_broadcast_after",      afb_hook_flag_api_event_broadcast },
315                 { "event_broadcast_before",     afb_hook_flag_api_event_broadcast },
316                 { "event_make",                 afb_hook_flag_api_event_make },
317                 { "extra",                      afb_hook_flags_api_ditf_extra },
318                 { "get_event_loop",             afb_hook_flag_api_get_event_loop },
319                 { "get_system_bus",             afb_hook_flag_api_get_system_bus },
320                 { "get_user_bus",               afb_hook_flag_api_get_user_bus },
321                 { "queue_job",                  afb_hook_flag_api_queue_job },
322                 { "require_api",                afb_hook_flag_api_require_api },
323                 { "require_api_result",         afb_hook_flag_api_require_api },
324                 { "rootdir_get_fd",             afb_hook_flag_api_rootdir_get_fd },
325                 { "rootdir_open_locale",        afb_hook_flag_api_rootdir_open_locale },
326                 { "unstore_req",                afb_hook_flag_api_legacy_unstore_req },
327                 { "vverbose",                   afb_hook_flag_api_vverbose },
328 };
329
330 static struct flag legacy_svc_flags[] = { /* must be sorted by names */
331                 { "all",                afb_hook_flags_api_svc_all },
332                 { "call",               afb_hook_flag_api_call },
333                 { "call_result",        afb_hook_flag_api_call },
334                 { "callsync",           afb_hook_flag_api_callsync },
335                 { "callsync_result",    afb_hook_flag_api_callsync },
336                 { "on_event_after",     afb_hook_flag_api_on_event },
337                 { "on_event_before",    afb_hook_flag_api_on_event },
338                 { "start_after",        afb_hook_flag_api_start },
339                 { "start_before",       afb_hook_flag_api_start },
340 };
341
342 int afb_hook_flags_legacy_ditf_from_text(const char *text)
343 {
344         return from_text(text, FLAGS(legacy_ditf_flags));
345 }
346
347 int afb_hook_flags_legacy_svc_from_text(const char *text)
348 {
349         return from_text(text, FLAGS(legacy_svc_flags));
350 }
351
352 char *afb_hook_flags_legacy_ditf_to_text(int value)
353 {
354         return to_text(value, FLAGS(legacy_ditf_flags));
355 }
356
357 char *afb_hook_flags_legacy_svc_to_text(int value)
358 {
359         return to_text(value, FLAGS(legacy_svc_flags));
360 }
361 #endif
362
363 #endif /* WITH_AFB_HOOK *******************************************************/