1 #include "e_keyrouter_intern.h"
2 #include "e_input_intern.h"
3 #include "e_comp_wl_input_intern.h"
4 #include "e_comp_wl_intern.h"
5 #include "e_client_intern.h"
6 #include "e_config_intern.h"
7 #include "e_comp_input_intern.h"
9 #include <tizen-extension-server-protocol.h>
12 e_keyrouter_wl_event_surface_send(struct wl_resource *surface, int key, int mode)
15 struct wl_resource *res_data;
18 EINA_SAFETY_ON_NULL_RETURN(krt);
19 EINA_SAFETY_ON_NULL_RETURN(surface);
21 wc = wl_resource_get_client(surface);
22 EINA_SAFETY_ON_NULL_RETURN(wc);
24 EINA_LIST_FOREACH(krt->resources, l, res_data)
26 if (wl_resource_get_client(res_data) != wc) continue;
27 if (wl_resource_get_version(res_data) < 2) continue;
29 if (e_config->key_input_ttrace_enable)
31 TRACE_INPUT_BEGIN(tizen_keyrouter_send_event_surface);
32 ELOGF("INPUT", "tizen_keyrouter_send_event_surface|B|", NULL);
35 tizen_keyrouter_send_event_surface(res_data, surface, key, mode);
37 if (e_config->key_input_ttrace_enable)
40 ELOGF("INPUT", "tizen_keyrouter_send_event_surface|E|", NULL);
46 _e_keyrouter_wl_key_send(Ecore_Event_Key *ev, E_Device *dev, enum wl_keyboard_key_state state, Eina_List *key_list, Eina_Bool focused, struct wl_client *client, struct wl_resource *surface)
48 struct wl_resource *res;
50 uint32_t serial, keycode;
52 E_Comp_Config *comp_conf = NULL;
54 keycode = (ev->keycode - 8);
56 serial = wl_display_next_serial(e_comp_wl->wl.disp);
58 comp_conf = e_comp_config_get();
60 if (surface && !focused)
62 e_comp_wl_connection_lock();
63 e_keyrouter_wl_event_surface_send(surface, ev->keycode, TIZEN_KEYROUTER_MODE_NONE);
64 e_comp_wl_connection_unlock();
67 if (e_config->key_input_ttrace_enable)
69 TRACE_INPUT_BEGIN(wl_keyboard_send_key:%s:%s, (state ? "PRESS" : "RELEASE"), ev->keyname);
70 ELOGF("INPUT", "wl_keyboard_send_key:%s:%s|B|", NULL, (state ? "PRESS" : "RELEASE"), ev->keyname);
73 EINA_LIST_FOREACH(key_list, l, res)
75 wc = wl_resource_get_client(res);
76 if (!focused && wc != client) continue;
77 TRACE_INPUT_BEGIN(_e_comp_wl_key_send);
78 if (!e_input_thread_mode_get())
80 e_comp_wl_send_event_device(client, ev->timestamp, ev->dev, serial);
85 e_comp_wl_send_event_e_device(client, ev->timestamp, dev, serial);
88 if (comp_conf && comp_conf->input_log_enable)
89 INF("[Server] Routed Key %s (time: %d)\n", (state ? "Down" : "Up"), ev->timestamp);
91 wl_keyboard_send_key(res, serial, ev->timestamp,
96 if (e_config->key_input_ttrace_enable)
99 ELOGF("INPUT", "wl_keyboard_send_key|E|", NULL);
104 e_keyrouter_wl_key_send(Ecore_Event_Key *ev, E_Device *dev, Eina_Bool pressed, struct wl_client *client, struct wl_resource *surface, Eina_Bool focused)
107 struct wl_client *wc = NULL;
109 enum wl_keyboard_key_state state;
111 if (ev->window != e_comp->ee_win)
116 keycode = (ev->keycode - 8);
117 if (!(e_comp_wl = e_comp->wl_comp_data))
122 #ifndef E_RELEASE_BUILD
123 if ((ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) &&
124 ((ev->modifiers & ECORE_EVENT_MODIFIER_ALT) ||
125 (ev->modifiers & ECORE_EVENT_MODIFIER_ALTGR)) &&
126 eina_streq(ev->key, "BackSpace"))
132 if (pressed) state = WL_KEYBOARD_KEY_STATE_PRESSED;
133 else state = WL_KEYBOARD_KEY_STATE_RELEASED;
137 _e_keyrouter_wl_key_send(ev, dev, state, e_comp_input_key->kbd.resources, EINA_FALSE, client, surface);
141 if ((!e_client_action_get()) && (!e_comp->input_key_grabs))
143 ec = e_client_focused_get();
145 if (ec && ec->comp_data)
147 struct wl_resource *surface = e_comp_wl_client_surface_get(ec);
150 if (e_comp_input_key->kbd.focused)
152 wc = wl_resource_get_client(surface);
153 _e_keyrouter_wl_key_send(ev, dev, state, e_comp_input_key->kbd.focused, EINA_TRUE, wc, surface);
157 /* update modifier state */
158 e_comp_wl_input_keyboard_state_update(keycode, pressed);
165 e_keyrouter_keycancel_send(struct wl_client *client, struct wl_resource *surface, unsigned int key)
168 struct wl_resource *resource = NULL;
169 struct wl_client *wc = NULL;
170 E_Keyrouter_Key_List_NodePtr data;
171 Eina_List *press_ptr_list = NULL;
173 if (surface) wc = wl_resource_get_client(surface);
176 EINA_SAFETY_ON_NULL_RETURN(wc);
178 press_ptr_list = krt->HardKeys[key].press_ptr;
179 EINA_LIST_FOREACH(press_ptr_list, l, data)
183 if (surface == data->surface)
185 EINA_LIST_FOREACH(krt->resources, l, resource)
187 if (wl_resource_get_client(resource) != wc) continue;
189 tizen_keyrouter_send_key_cancel(resource, key-8);
193 else if (client == data->wc)
195 EINA_LIST_FOREACH(krt->resources, l, resource)
197 if (wl_resource_get_client(resource) != wc) continue;
199 tizen_keyrouter_send_key_cancel(resource, key-8);
206 _e_keyrouter_wl_array_length(const struct wl_array *array)
211 wl_array_for_each(data, array)
220 _e_keyrouter_input_thread_keygrab_set(void *data)
224 E_Input_Thread_Request_Keygrab_Data keygrab_data;
225 memcpy(&keygrab_data, data, sizeof(E_Input_Thread_Request_Keygrab_Data));
227 TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_set);
229 res = e_keyrouter_keygrab_set(keygrab_data.client, keygrab_data.surface, keygrab_data.key, keygrab_data.mode);
233 if (res == TIZEN_KEYROUTER_ERROR_NONE)
235 if (keygrab_data.mode == TIZEN_KEYROUTER_MODE_EXCLUSIVE)
237 KLINF("Success to %d key %s grab request (wl_client: %p, wl_surface: %p, pid: %d)", keygrab_data.key, e_keyrouter_mode_to_string(keygrab_data.mode),
238 keygrab_data.client, keygrab_data.surface, e_keyrouter_util_get_pid(keygrab_data.client, keygrab_data.surface));
242 KLDBG("Success to %d key %s grab request (wl_client: %p, wl_surface: %p, pid: %d)", keygrab_data.key, e_keyrouter_mode_to_string(keygrab_data.mode),
243 keygrab_data.client, keygrab_data.surface, e_keyrouter_util_get_pid(keygrab_data.client, keygrab_data.surface));
247 KLINF("Failed to %d key %s grab request (wl_client: %p, wl_surface: %p, pid: %d): res: %d", keygrab_data.key, e_keyrouter_mode_to_string(keygrab_data.mode),
248 keygrab_data.client, keygrab_data.surface, e_keyrouter_util_get_pid(keygrab_data.client, keygrab_data.surface), res);
250 tizen_keyrouter_send_keygrab_notify(keygrab_data.resource, keygrab_data.surface, keygrab_data.key, keygrab_data.mode, res);
253 /* tizen_keyrouter_set_keygrab request handler */
255 _e_keyrouter_cb_keygrab_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key, uint32_t mode)
257 TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_set);
259 E_Input_Thread_Request_Keygrab_Data keygrab_data;
261 keygrab_data.resource = resource;
262 keygrab_data.surface = surface;
263 keygrab_data.client = client;
264 keygrab_data.key = key;
265 keygrab_data.mode = mode;
267 INF("client: %p, surface: %p, key: %d, mode: %d\n", keygrab_data.client, keygrab_data.surface, keygrab_data.key, keygrab_data.mode);
268 e_input_thread_safe_call(_e_keyrouter_input_thread_keygrab_set, &keygrab_data, sizeof(E_Input_Thread_Request_Keygrab_Data));
272 _e_keyrouter_input_thread_keygrab_unset(void *data)
275 E_Input_Thread_Request_Keygrab_Data keygrab_data;
276 memcpy(&keygrab_data, data, sizeof(E_Input_Thread_Request_Keygrab_Data));
278 res = e_keyrouter_keygrab_unset(keygrab_data.client, keygrab_data.surface, keygrab_data.key);
282 if (res == TIZEN_KEYROUTER_ERROR_NONE)
283 KLDBG("Success to %d key ungrab request (wl_client: %p, wl_surface: %p, pid: %d)", keygrab_data.key, keygrab_data.client, keygrab_data.surface,
284 e_keyrouter_util_get_pid(keygrab_data.client, keygrab_data.surface));
286 KLINF("Failed to %d key ungrab request (wl_client: %p, wl_surface: %p, pid: %d): res: %d", keygrab_data.key, keygrab_data.client, keygrab_data.surface,
287 e_keyrouter_util_get_pid(keygrab_data.client, keygrab_data.surface), res);
289 tizen_keyrouter_send_keygrab_notify(keygrab_data.resource, keygrab_data.surface, keygrab_data.key, TIZEN_KEYROUTER_MODE_NONE, res);
292 /* tizen_keyrouter unset_keygrab request handler */
294 _e_keyrouter_cb_keygrab_unset(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key)
296 TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_unset);
298 E_Input_Thread_Request_Keygrab_Data keygrab_data;
300 keygrab_data.resource = resource;
301 keygrab_data.surface = surface;
302 keygrab_data.client = client;
303 keygrab_data.key = key;
305 INF("client: %p, surface: %p, key: %d\n", keygrab_data.client, keygrab_data.surface, keygrab_data.key);
306 e_input_thread_safe_call(_e_keyrouter_input_thread_keygrab_unset, &keygrab_data, sizeof(E_Input_Thread_Request_Keygrab_Data));
309 /* tizen_keyrouter get_keygrab_status request handler */
311 _e_keyrouter_cb_get_keygrab_status(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key)
317 int mode = TIZEN_KEYROUTER_MODE_NONE;
319 TRACE_INPUT_BEGIN(_e_keyrouter_cb_get_keygrab_status);
320 mode = e_keyrouter_find_key_in_list(surface, client, key);
323 tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, TIZEN_KEYROUTER_ERROR_NONE);
327 _e_keyrouter_cb_keygrab_set_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, struct wl_array *grab_list)
329 E_Keyrouter_Grab_Request *grab_request = NULL;
330 int res = TIZEN_KEYROUTER_ERROR_NONE;
333 TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_set_list);
335 array_len = _e_keyrouter_wl_array_length(grab_list);
337 if (0 != (array_len % 3))
339 /* FIX ME: Which way is effectively to notify invalid pair to client */
340 KLWRN("Invalid keycode and grab mode pair. Check arguments in a list");
342 tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL);
346 wl_array_for_each(grab_request, grab_list)
348 res = e_keyrouter_keygrab_set(client, surface, grab_request->key, grab_request->mode);
349 grab_request->err = res;
350 if (res == TIZEN_KEYROUTER_ERROR_NONE)
351 KLDBG("Success to %d key %s grab using list(wl_client: %p, wl_surface: %p, pid: %d)",
352 grab_request->key, e_keyrouter_mode_to_string(grab_request->mode),
353 client, surface, e_keyrouter_util_get_pid(client, surface));
355 KLINF("Failed to %d key %s grab using list(wl_client: %p, wl_surface: %p, pid: %d): res: %d",
356 grab_request->key, e_keyrouter_mode_to_string(grab_request->mode),
357 client, surface, e_keyrouter_util_get_pid(client, surface), grab_request->err);
361 tizen_keyrouter_send_keygrab_notify_list(resource, surface, grab_list);
365 _e_keyrouter_cb_keygrab_unset_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, struct wl_array *ungrab_list)
367 E_Keyrouter_Ungrab_Request *ungrab_request = NULL;
368 int res = TIZEN_KEYROUTER_ERROR_NONE;
371 TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_unset_list);
373 array_len = _e_keyrouter_wl_array_length(ungrab_list);
375 if (0 != (array_len % 2))
377 /* FIX ME: Which way is effectively to notify invalid pair to client */
378 KLWRN("Invalid keycode and error pair. Check arguments in a list");
380 tizen_keyrouter_send_keygrab_notify_list(resource, surface, ungrab_list);
384 wl_array_for_each(ungrab_request, ungrab_list)
386 res = e_keyrouter_keygrab_unset(client, surface, ungrab_request->key);
387 ungrab_request->err = res;
388 if (res == TIZEN_KEYROUTER_ERROR_NONE)
389 KLDBG("Success to ungrab using list: %d key (wl_client: %p, wl_surface: %p, pid: %d)",
390 ungrab_request->key, client, surface, e_keyrouter_util_get_pid(client, surface));
392 KLINF("Failed to ungrab using list: %d key (wl_client: %p, wl_surface: %p, pid: %d): res: %d",
393 ungrab_request->key, client, surface, e_keyrouter_util_get_pid(client, surface), ungrab_request->err);
397 tizen_keyrouter_send_keygrab_notify_list(resource, surface, ungrab_list);
401 _e_keyrouter_cb_keygrab_get_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface)
405 tizen_keyrouter_send_getgrab_notify_list(resource, surface, NULL);
409 _e_keyrouter_cb_set_register_none_key(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t data)
414 tizen_keyrouter_send_set_register_none_key_notify(resource, NULL, 0);
418 _e_keyrouter_cb_get_keyregister_status(struct wl_client *client, struct wl_resource *resource, uint32_t key)
423 tizen_keyrouter_send_keyregister_notify(resource, (int)EINA_FALSE);
427 _e_keyrouter_cb_set_input_config(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *surface EINA_UNUSED, uint32_t config_mode EINA_UNUSED, uint32_t value EINA_UNUSED)
429 tizen_keyrouter_send_set_input_config_notify(resource, 0);
433 _e_keyrouter_cb_destroy(struct wl_client *client, struct wl_resource *resource)
435 wl_resource_destroy(resource);
438 static const struct tizen_keyrouter_interface _e_keyrouter_implementation = {
439 _e_keyrouter_cb_keygrab_set,
440 _e_keyrouter_cb_keygrab_unset,
441 _e_keyrouter_cb_get_keygrab_status,
442 _e_keyrouter_cb_keygrab_set_list,
443 _e_keyrouter_cb_keygrab_unset_list,
444 _e_keyrouter_cb_keygrab_get_list,
445 _e_keyrouter_cb_set_register_none_key,
446 _e_keyrouter_cb_get_keyregister_status,
447 _e_keyrouter_cb_set_input_config,
448 _e_keyrouter_cb_destroy,
452 _e_keyrouter_cb_unbind(struct wl_resource *resource)
454 krt->resources = eina_list_remove(krt->resources, resource);
457 /* tizen_keyrouter global object bind function */
459 _e_keyrouter_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
461 E_KeyrouterPtr krt_instance = data;
462 struct wl_resource *resource;
464 resource = wl_resource_create(client, &tizen_keyrouter_interface, version, id);
466 KLDBG("wl_resource_create(...,&tizen_keyrouter_interface,...)");
470 KLERR("Failed to create resource ! (version :%d, id:%d)", version, id);
471 wl_client_post_no_memory(client);
475 krt->resources = eina_list_append(krt->resources, resource);
477 wl_resource_set_implementation(resource, &_e_keyrouter_implementation, krt_instance, _e_keyrouter_cb_unbind);
481 _e_keyrouter_wl_client_cb_destroy(struct wl_listener *l, void *data)
483 struct wl_client *client = data;
485 KLDBG("Listener(%p) called: wl_client: %p is died", l, client);
486 e_keyrouter_remove_client_from_list(NULL, client);
488 wl_list_remove(&l->link);
491 krt->grab_client_list = eina_list_remove(krt->grab_client_list, client);
495 _e_keyrouter_wl_surface_cb_destroy(struct wl_listener *l, void *data)
497 struct wl_resource *surface = (struct wl_resource *)data;
499 KLDBG("Listener(%p) called: surface: %p is died", l, surface);
500 e_keyrouter_remove_client_from_list(surface, NULL);
502 wl_list_remove(&l->link);
505 krt->grab_surface_list = eina_list_remove(krt->grab_surface_list, surface);
509 e_keyrouter_wl_add_client_destroy_listener(struct wl_client *client)
511 struct wl_listener *destroy_listener = NULL;
513 struct wl_client *wc_data;
515 if (!client) return TIZEN_KEYROUTER_ERROR_NONE;
517 EINA_LIST_FOREACH(krt->grab_client_list, l, wc_data)
521 if (wc_data == client)
523 return TIZEN_KEYROUTER_ERROR_NONE;
528 destroy_listener = E_NEW(struct wl_listener, 1);
530 if (!destroy_listener)
532 KLERR("Failed to allocate memory for wl_client destroy listener !");
533 return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES;
536 destroy_listener->notify = _e_keyrouter_wl_client_cb_destroy;
537 wl_client_add_destroy_listener(client, destroy_listener);
538 krt->grab_client_list = eina_list_append(krt->grab_client_list, client);
540 return TIZEN_KEYROUTER_ERROR_NONE;
543 /* Function for registering wl_surface destroy listener */
545 e_keyrouter_wl_add_surface_destroy_listener(struct wl_resource *surface)
547 struct wl_listener *destroy_listener = NULL;
549 struct wl_resource *surface_data;
551 if (!surface) return TIZEN_KEYROUTER_ERROR_NONE;
553 EINA_LIST_FOREACH(krt->grab_surface_list, l, surface_data)
557 if (surface_data == surface)
559 return TIZEN_KEYROUTER_ERROR_NONE;
564 destroy_listener = E_NEW(struct wl_listener, 1);
566 if (!destroy_listener)
568 KLERR("Failed to allocate memory for wl_surface destroy listener !");
569 return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES;
572 destroy_listener->notify = _e_keyrouter_wl_surface_cb_destroy;
573 wl_resource_add_destroy_listener(surface, destroy_listener);
574 krt->grab_surface_list = eina_list_append(krt->grab_surface_list, surface);
576 return TIZEN_KEYROUTER_ERROR_NONE;
581 _e_keyrouter_wl_util_cynara_log(const char *func_name, int err)
583 #define CYNARA_BUFSIZE 128
584 char buf[CYNARA_BUFSIZE] = "\0";
587 ret = cynara_strerror(err, buf, CYNARA_BUFSIZE);
588 if (ret != CYNARA_API_SUCCESS)
590 KLWRN("Failed to cynara_strerror: %d (error log about %s: %d)", ret, func_name, err);
593 KLWRN("%s is failed: %s", func_name, buf);
597 e_keyrouter_wl_util_do_privilege_check(struct wl_client *client, uint32_t mode, uint32_t keycode)
599 int ret, retry_cnt=0, len=0;
600 char *clientSmack=NULL, *client_session=NULL, uid2[16]={0, };
601 Eina_Bool res = EINA_FALSE;
603 struct wl_client *wc_data;
604 static Eina_Bool retried = EINA_FALSE;
609 /* Top position grab is always allowed. This mode do not need privilege.*/
610 if (mode == TIZEN_KEYROUTER_MODE_TOPMOST)
613 if (krt->HardKeys[keycode].no_privcheck == EINA_TRUE &&
614 mode == TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE)
617 if (!client) return EINA_FALSE;
619 /* If initialize cynara is failed, allow keygrabs regardless of the previlege permition. */
620 if (krt->p_cynara == NULL)
622 if (retried == EINA_FALSE)
625 for(retry_cnt = 0; retry_cnt < 5; retry_cnt++)
627 KLDBG("Retry cynara initialize: %d", retry_cnt+1);
628 ret = cynara_initialize(&krt->p_cynara, NULL);
629 if (EINA_UNLIKELY(CYNARA_API_SUCCESS != ret))
631 _e_keyrouter_wl_util_cynara_log("cynara_initialize", ret);
632 krt->p_cynara = NULL;
636 KLDBG("Success cynara initialize to try %d times", retry_cnt+1);
644 EINA_LIST_FOREACH(krt->grab_client_list, l, wc_data)
646 if (wc_data == client)
653 wl_client_get_credentials(client, &pid, &uid, &gid);
655 len = smack_new_label_from_process((int)pid, &clientSmack);
656 if (len <= 0) goto finish;
658 snprintf(uid2, 15, "%d", (int)uid);
659 client_session = cynara_session_from_pid(pid);
661 ret = cynara_check(krt->p_cynara, clientSmack, client_session, uid2, "http://tizen.org/privilege/keygrab");
662 if (CYNARA_API_ACCESS_ALLOWED == ret)
668 KLINF("Fail to check cynara, error : %d (pid : %d)", ret, pid);
671 if (client_session) E_FREE(client_session);
672 if (clientSmack) E_FREE(clientSmack);
679 e_keyrouter_wl_init(void)
683 EINA_SAFETY_ON_NULL_RETURN_VAL(krt, EINA_FALSE);
684 EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, EINA_FALSE);
686 krt->global = wl_global_create(e_comp_wl->wl.disp, &tizen_keyrouter_interface, 2, krt, _e_keyrouter_cb_bind);
687 EINA_SAFETY_ON_NULL_RETURN_VAL(krt->global, EINA_FALSE);
690 ret = cynara_initialize(&krt->p_cynara, NULL);
691 if (EINA_UNLIKELY(CYNARA_API_SUCCESS != ret))
693 _e_keyrouter_wl_util_cynara_log("cynara_initialize", ret);
694 krt->p_cynara = NULL;
702 e_keyrouter_wl_shutdown(void)
704 Eina_List *l, *l_next;
705 struct wl_resource *resource;
706 struct wl_client *client;
707 struct wl_listener *destroy_listener;
709 EINA_SAFETY_ON_NULL_RETURN(krt);
711 EINA_LIST_FOREACH_SAFE(krt->grab_client_list, l, l_next, client)
713 destroy_listener = wl_client_get_destroy_listener(client, _e_keyrouter_wl_client_cb_destroy);
714 if (destroy_listener)
716 wl_list_remove(&destroy_listener->link);
717 E_FREE(destroy_listener);
719 krt->grab_client_list = eina_list_remove(krt->grab_client_list, client);
721 EINA_LIST_FOREACH_SAFE(krt->grab_surface_list, l, l_next, resource)
723 destroy_listener = wl_resource_get_destroy_listener(resource, _e_keyrouter_wl_surface_cb_destroy);
724 if (destroy_listener)
726 wl_list_remove(&destroy_listener->link);
727 E_FREE(destroy_listener);
729 krt->grab_surface_list = eina_list_remove(krt->grab_surface_list, client);
732 EINA_LIST_FREE(krt->resources, resource)
733 wl_resource_destroy(resource);
735 if (krt->global) wl_global_destroy(krt->global);
738 if (krt->p_cynara) cynara_finish(krt->p_cynara);