c1c96a21c60114e5ee0696c40e1d157b95eb3b35
[platform/adaptation/xf86-module-xdbg.git] / module / xdbg_module_evlog.c
1 /**************************************************************************
2
3 xdbg
4
5 Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
6
7 Contact: Boram Park <boram1288.park@samsung.com>
8          Sangjin LEE <lsj119@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <sys/types.h>
40 #include <sys/fcntl.h>
41 #include <unistd.h>
42 #include <stdarg.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <time.h>
46
47 #define __USE_GNU
48 #include <sys/socket.h>
49 #include <linux/socket.h>
50
51 #ifdef HAS_GETPEERUCRED
52 # include <ucred.h>
53 #endif
54
55 #include <xace.h>
56 #include <xacestr.h>
57 #include <X11/Xatom.h>
58 #include <X11/extensions/XI2proto.h>
59 #include <windowstr.h>
60
61 #include <xdbg.h>
62 #include "xdbg_types.h"
63 #include "xdbg_module.h"
64 #include "xdbg_module_evlog.h"
65 #include "xdbg_evlog.h"
66
67 #define XREGISTRY
68 #include "registry.h"
69
70 #define FP1616toDBL(x) ((x) * 1.0 / (1 << 16))
71
72 static Bool     xev_trace_on = FALSE;
73 static int  xev_trace_fd = -1;
74 static int  xev_trace_record_fd = -1;
75 static Atom atom_rotate = None;
76 static Atom atom_client_pid = None;
77
78 static void evtRecord (int fd, EvlogInfo *evinfo)
79 {
80     int write_len = 0;
81
82     XDBG_RETURN_IF_FAIL (fd >= 0)
83
84     if (evinfo)
85     {
86         evinfo->mask = 0;
87
88         write_len = sizeof (int) +
89                     sizeof (EvlogType) +
90                     sizeof (int) +
91                     sizeof (CARD32);
92
93         evinfo->mask |= EVLOG_MASK_CLIENT;
94         write_len += sizeof (EvlogClient);
95
96         if (evinfo->type == REQUEST)
97         {
98             evinfo->mask |= EVLOG_MASK_REQUEST;
99             write_len += sizeof (EvlogRequest) + sizeof (xReq);
100         }
101         else if (evinfo->type == EVENT)
102         {
103             evinfo->mask |= EVLOG_MASK_EVENT;
104             write_len += sizeof (EvlogEvent) + sizeof (xEvent);
105         }
106     }
107
108     if (write (xev_trace_record_fd, &write_len, sizeof(int)) == -1)
109     {
110         XDBG_ERROR (MXDBG, "failed: write write_len\n");
111         return;
112     }
113
114     if (evinfo)
115     {
116         if (write (xev_trace_record_fd, &evinfo->time, sizeof(CARD32)) == -1)
117         {
118             XDBG_ERROR (MXDBG, "failed: write msec\n");
119             return;
120         }
121         if (write (xev_trace_record_fd, &evinfo->type, sizeof(EvlogType)) == -1)
122         {
123             XDBG_ERROR (MXDBG, "failed: write type\n");
124             return;
125         }
126         if (write (xev_trace_record_fd, &evinfo->mask, sizeof(int)) == -1)
127         {
128             XDBG_ERROR (MXDBG, "failed: write mask\n");
129             return;
130         }
131         if (write (xev_trace_record_fd, &evinfo->client, sizeof (EvlogClient)) == -1)
132         {
133             XDBG_ERROR (MXDBG, "failed: write client\n");
134             return;
135         }
136
137         if (evinfo->type == REQUEST)
138         {
139             if (write (xev_trace_record_fd, &evinfo->req, sizeof (EvlogRequest)) == -1)
140             {
141                 XDBG_ERROR (MXDBG, "failed: write request\n");
142                 return;
143             }
144             if (write (xev_trace_record_fd, evinfo->req.ptr, sizeof (xReq)) == -1)
145             {
146                 XDBG_ERROR (MXDBG, "failed: write request\n");
147                 return;
148             }
149         }
150         else if (evinfo->type == EVENT)
151         {
152             if (write (xev_trace_record_fd, &evinfo->evt, sizeof (EvlogEvent)) == -1)
153             {
154                 XDBG_ERROR (MXDBG, "failed: write event\n");
155                 return;
156             }
157             if (write (xev_trace_record_fd, evinfo->evt.ptr, sizeof (xEvent)) == -1)
158             {
159                 XDBG_ERROR (MXDBG, "failed: write event\n");
160                 return;
161             }
162         }
163     }
164 }
165
166 static void evtPrintF (int fd, EvlogInfo *evinfo)
167 {
168     char log[1024];
169     int size = sizeof (log);
170
171     xDbgEvlogFillLog (evinfo, log, &size);
172
173     if (fd < 0)
174         ErrorF ("%s", log);
175     else
176         dprintf (fd, "%s", log);
177 }
178
179 static void evtPrint (EvlogType type, ClientPtr client, xEvent *ev)
180 {
181     EvlogInfo evinfo = {0,};
182
183     /* evinfo.type */
184     evinfo.type = type;
185
186     /* evinfo.client */
187     if (client)
188     {
189         ModuleClientInfo *info = GetClientInfo (client);
190         XDBG_RETURN_IF_FAIL (info != NULL);
191
192         evinfo.mask |= EVLOG_MASK_CLIENT;
193         evinfo.client.index = info->index;
194         evinfo.client.pid = info->pid;
195         evinfo.client.gid = info->gid;
196         evinfo.client.uid = info->uid;
197         strncpy (evinfo.client.command, info->command, strlen (info->command));
198
199         /* evinfo.req */
200         if (type == REQUEST)
201         {
202             REQUEST (xReq);
203
204             evinfo.mask |= EVLOG_MASK_REQUEST;
205             evinfo.req.id = stuff->reqType;
206             evinfo.req.length = client->req_len;
207             evinfo.req.ptr = client->requestBuffer;
208
209             if (stuff->reqType < EXTENSION_BASE)
210                 snprintf (evinfo.req.name, sizeof (evinfo.req.name), "%s",
211                           LookupRequestName (stuff->reqType, 0));
212             else
213                 snprintf (evinfo.req.name, sizeof (evinfo.req.name), "%s",
214                           LookupRequestName (stuff->reqType, stuff->data));
215         }
216     }
217
218     /* evinfo.evt */
219     if (ev)
220     {
221         XDBG_RETURN_IF_FAIL (type == EVENT);
222
223         evinfo.mask |= EVLOG_MASK_EVENT;
224         evinfo.evt.ptr = ev;
225         snprintf (evinfo.evt.name, sizeof (evinfo.evt.name), "%s",
226                   LookupEventName ((int)(ev->u.u.type)));
227     }
228
229     /* evinfo.time */
230     evinfo.time = GetTimeInMillis ();
231
232     if (!xDbgEvlogRuleValidate (&evinfo))
233         return;
234
235     if (xev_trace_record_fd >= 0)
236         evtRecord (xev_trace_record_fd, &evinfo);
237     else
238         evtPrintF (xev_trace_fd, &evinfo);
239
240 }
241
242 static const char*
243 _traceGetWindowName (ClientPtr client, Window window)
244 {
245     int rc;
246     WindowPtr pWin;
247     Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess;
248     Atom property;
249     PropertyPtr pProp;
250     static char winname[128];
251     int datalen;
252
253     rc = dixLookupWindow (&pWin, window, client, win_mode);
254     if (rc != Success)
255         return NULL;
256
257     property = MakeAtom ("WM_NAME", strlen ("WM_NAME"), TRUE);
258     while (pWin)
259     {
260         rc = dixLookupProperty (&pProp, pWin, property, client, prop_mode);
261         if (rc == Success && pProp->data)
262         {
263             datalen = (pProp->size>127) ?127:pProp->size;
264             strncpy (winname, pProp->data, datalen);
265             winname[datalen] = 0;
266
267             return winname;
268         }
269
270         pWin = pWin->parent;
271     }
272
273     return NULL;
274 }
275
276 static void
277 _traceFlush (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
278 {
279     if (xev_trace_on == FALSE)
280         return;
281
282     evtPrint (FLUSH, NULL, NULL);
283 }
284
285 static void
286 _traceAReply (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
287 {
288     if (xev_trace_on == FALSE)
289         return;
290
291     ReplyInfoRec *pri = (ReplyInfoRec*)calldata;
292
293     evtPrint (REPLY, pri->client, NULL);
294 }
295
296 static void
297 _traceEvent (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
298 {
299     EventInfoRec *pei = (EventInfoRec*)calldata;
300     ClientPtr pClient;
301     ModuleClientInfo *info;
302     int ev; /* event index */
303     static int xi2_opcode = -1;
304     xEvent *pev;
305     static char* ename[]=
306     {
307         "KeyPress",
308         "KeyRelease",
309         "ButtonPress",
310         "ButtonRelease",
311     };
312
313     XDBG_RETURN_IF_FAIL (pei != NULL);
314
315     pClient = pei->client;
316     XDBG_RETURN_IF_FAIL (pClient != NULL);
317
318     pev = pei->events;
319     XDBG_RETURN_IF_FAIL (pev != NULL);
320
321     info = GetClientInfo (pClient);
322     XDBG_RETURN_IF_FAIL (info != NULL);
323
324     for (ev=0; ev < pei->count; ev++, pev++)
325     {
326         int type = pev->u.u.type & 0177;
327
328         if (type < LASTEvent)
329         {
330             switch (type)
331             {
332             case KeyPress:
333             case KeyRelease:
334                 XDBG_INFO (MXDBG, "%s(%d)_%d(%s.%d : %s.0x%lx) root(%d,%d) win(%d,%d)\n"
335                         , ename[type-KeyPress], pev->u.u.detail, pev->u.u.type
336                         , info->command, info->pid
337                         , _traceGetWindowName (pClient, pev->u.keyButtonPointer.event), pev->u.keyButtonPointer.event
338                         , pev->u.keyButtonPointer.rootX, pev->u.keyButtonPointer.rootY
339                         , pev->u.keyButtonPointer.eventX, pev->u.keyButtonPointer.eventY);
340                 break;
341
342             case ButtonPress:
343             case ButtonRelease:
344                 XDBG_INFO (MXDBG, "%s(%d)_%d(%s.%d : %s.0x%lx) root(%d,%d) win(%d,%d)\n"
345                         , ename[type-KeyPress], pev->u.u.detail, pev->u.u.type
346                         , info->command, info->pid
347                         , _traceGetWindowName (pClient, pev->u.keyButtonPointer.event), pev->u.keyButtonPointer.event
348                         , pev->u.keyButtonPointer.rootX, pev->u.keyButtonPointer.rootY
349                         , pev->u.keyButtonPointer.eventX, pev->u.keyButtonPointer.eventY);
350                 break;
351             case GenericEvent:
352                 if(!xi2_opcode) break;
353                 if(xi2_opcode < 0)
354                 {
355                     ExtensionEntry *pExt = CheckExtension("XInputExtension");
356                     if(!pExt) xi2_opcode = 0;
357                     else xi2_opcode = pExt->base;
358                 }
359
360                 if(((xGenericEvent*)pev)->extension != xi2_opcode) break;
361
362                 xXIDeviceEvent *xidev = (xXIDeviceEvent *)pev;
363                 if(xidev->deviceid==2) break;
364                 if(xidev->evtype==XI_ButtonPress)
365                     XDBG_TRACE (MXDBG, "XI_ButtonPress(%d) device(%d), event win(0x%x), child(0x%x), root(%.f,%.f), win(%.f, %.f)\n", XI_ButtonPress, xidev->deviceid, xidev->event, xidev->child, FP1616toDBL(xidev->root_x), FP1616toDBL(xidev->root_y), FP1616toDBL(xidev->event_x), FP1616toDBL(xidev->event_y));
366                 else if(xidev->evtype==XI_ButtonRelease)
367                     XDBG_TRACE (MXDBG, "XI_ButtonRelease(%d) device(%d), event win(0x%x), child(0x%x), root(%.f,%.f), win(%.f, %.f)\n", XI_ButtonRelease,  xidev->deviceid, xidev->event, xidev->child, FP1616toDBL(xidev->root_x), FP1616toDBL(xidev->root_y), FP1616toDBL(xidev->event_x), FP1616toDBL(xidev->event_y));
368                 else if(xidev->evtype==XI_Motion)
369                     XDBG_TRACE (MXDBG, "XI_Motion(%d) device(%d), event win(0x%x), child(0x%x), root(%.f,%.f), win(%.f, %.f)\n", XI_Motion, xidev->deviceid, xidev->event, xidev->child, FP1616toDBL(xidev->root_x), FP1616toDBL(xidev->root_y), FP1616toDBL(xidev->event_x), FP1616toDBL(xidev->event_y));
370                 break;
371             default:
372                 break;
373             }
374         }
375
376         if (xev_trace_on)
377             evtPrint (EVENT, pClient, pev);
378     }
379 }
380
381 static void
382 _traceACoreEvents (CallbackListPtr *pcbl, pointer unused, pointer calldata)
383 {
384     if (xev_trace_on == FALSE)
385         return;
386
387     XaceCoreDispatchRec *rec = calldata;
388
389     XDBG_RETURN_IF_FAIL (rec != NULL);
390
391     evtPrint (REQUEST, rec->client, NULL);
392 }
393
394 static void
395 _traceAExtEvents (CallbackListPtr *pcbl, pointer unused, pointer calldata)
396 {
397     if (xev_trace_on == FALSE)
398         return;
399
400     XaceExtAccessRec *rec = calldata;
401
402     XDBG_RETURN_IF_FAIL (rec != NULL);
403
404     evtPrint (REQUEST, rec->client, NULL);
405 }
406
407 static void
408 _traceProperty (CallbackListPtr *pcbl, pointer unused, pointer calldata)
409 {
410     XacePropertyAccessRec *rec = calldata;
411     ModuleClientInfo *info = GetClientInfo (rec->client);
412     PropertyPtr pProp = *rec->ppProp;
413     Atom name = pProp->propertyName;
414
415     /* Don't care about the new content check */
416     if (rec->client == serverClient || rec->access_mode & DixPostAccess)
417         return;
418
419     if (name == atom_client_pid && (rec->access_mode & DixWriteAccess))
420     {
421         XDBG_WARNING (MXDBG, "Invalid access X_CLINET_PID pid:%d, uid:%d\n", info->pid, info->uid);
422         rec->status = BadAccess;
423         return;
424     }
425
426     rec->status = Success;
427     return;
428 }
429
430 static void
431 _traceResource (CallbackListPtr *pcbl, pointer unused, pointer calldata)
432 {
433     XaceResourceAccessRec *rec = calldata;
434     Mask access_mode = rec->access_mode;
435     ModuleClientInfo *info = GetClientInfo (rec->client);
436
437     /* Perform the background none check on windows */
438     if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW)
439     {
440         WindowPtr pWin = (WindowPtr) rec->res;
441         int rc;
442         int pid = info->pid;
443
444         rc = dixChangeWindowProperty (serverClient,
445                                       pWin, atom_client_pid, XA_CARDINAL, 32,
446                                       PropModeReplace, 1, &pid, FALSE);
447         if (rc != Success)
448             XDBG_ERROR (MXDBG, "failed : set X_CLIENT_PID to %d.\n", pid);
449     }
450 }
451
452 static void
453 _traceReceive (CallbackListPtr *pcbl, pointer unused, pointer calldata)
454 {
455     XaceReceiveAccessRec *rec = calldata;
456
457     if (rec->events->u.u.type != VisibilityNotify)
458         return;
459
460     rec->status = BadAccess;
461 }
462
463 Bool
464 xDbgModuleEvlogInstallHooks (XDbgModule *pMod)
465 {
466     int ret = TRUE;
467
468     ret &= AddCallback (&EventCallback, _traceEvent, NULL);
469     ret &= AddCallback (&FlushCallback, _traceFlush, NULL);
470     ret &= AddCallback (&ReplyCallback, _traceAReply, NULL);
471     ret &= XaceRegisterCallback (XACE_PROPERTY_ACCESS, _traceProperty, NULL);
472     ret &= XaceRegisterCallback (XACE_RESOURCE_ACCESS, _traceResource, NULL);
473
474     /*Disable Visibility Event*/
475     ret &= XaceRegisterCallback (XACE_RECEIVE_ACCESS, _traceReceive, NULL);
476
477     if (atom_client_pid == None)
478         atom_client_pid = MakeAtom ("X_CLIENT_PID", 12, TRUE);
479     if (atom_rotate == None)
480         atom_rotate = MakeAtom ("_E_ILLUME_ROTATE_ROOT_ANGLE", 12, TRUE);
481
482     if (!ret)
483     {
484         XDBG_ERROR (MXDBG, "failed: register one or more callbacks\n");
485         return FALSE;
486     }
487
488     if (pMod && pMod->evlog_path)
489         xDbgModuleEvlogSetEvlogPath (pMod, -1, pMod->evlog_path, NULL, NULL);
490
491     return TRUE;
492 }
493
494 void
495 xDbgModuleEvlogUninstallHooks (XDbgModule *pMod)
496 {
497     DeleteCallback (&EventCallback, _traceEvent, NULL);
498     DeleteCallback (&FlushCallback, _traceFlush, NULL);
499     DeleteCallback (&ReplyCallback, _traceAReply, NULL);
500     XaceDeleteCallback (XACE_PROPERTY_ACCESS, _traceProperty, NULL);
501     XaceDeleteCallback (XACE_RESOURCE_ACCESS, _traceResource, NULL);
502 }
503
504 void
505 xDbgModuleEvlogPrintEvents (XDbgModule *pMod, Bool on, const char * client_name, char *reply, int *len)
506 {
507     int ret = TRUE;
508
509     on = (on)?TRUE:FALSE;
510     if (xev_trace_on == on)
511         return;
512
513     xev_trace_on = on;
514
515     if (xev_trace_on)
516     {
517         int i;
518
519         //Find client's pid
520         for (i=1 ; i< currentMaxClients ; i++)
521         {
522             ClientPtr pClient;
523             ModuleClientInfo *info;
524
525             pClient = clients[i];
526             if (!pClient)
527                 continue;
528
529             info = GetClientInfo (pClient);
530             if (!info)
531                 continue;
532
533             if (strlen (info->command) > 0 && strstr (client_name, info->command))
534             {
535                 char fd_name[256];
536
537                 if (xev_trace_fd >= 0)
538                     close (xev_trace_fd);
539
540                 snprintf (fd_name, 256, "/proc/%d/fd/1", info->pid);
541                 xev_trace_fd = open (fd_name, O_RDWR);
542                 if (xev_trace_fd < 0)
543                     XDBG_REPLY ("failed: open consol '%s'. (%s)\n", fd_name, strerror(errno));
544             }
545         }
546
547
548         ret &= XaceRegisterCallback (XACE_CORE_DISPATCH, _traceACoreEvents, NULL);
549         ret &= XaceRegisterCallback (XACE_EXT_DISPATCH, _traceAExtEvents, NULL);
550
551         if (!ret)
552         {
553             XDBG_REPLY ("failed: register one or more callbacks.\n");
554             return;
555         }
556     }
557     else
558     {
559         XaceDeleteCallback (XACE_CORE_DISPATCH, _traceACoreEvents, NULL);
560         XaceDeleteCallback (XACE_EXT_DISPATCH, _traceAExtEvents, NULL);
561     }
562
563     return;
564 }
565
566 int
567 xDbgModuleEvlogInfoSetRule (XDbgModule *pMod, const int argc, const char ** argv, char *reply, int *len)
568 {
569     return xDbgEvlogRuleSet (argc, argv, reply, len);
570 }
571
572 Bool
573 xDbgModuleEvlogSetEvlogPath (XDbgModule *pMod, int pid, char *path, char *reply, int *len)
574 {
575     char fd_name[XDBG_PATH_MAX];
576     char *temp[3] = {"/", "./", "../"};
577     Bool valid = FALSE;
578     int i;
579
580     if (!path || strlen (path) <= 0)
581     {
582         XDBG_REPLY ("failed: invalid path\n");
583         return FALSE;
584     }
585
586     if (xev_trace_record_fd >= 0)
587     {
588         close (xev_trace_record_fd);
589         xev_trace_record_fd = -1;
590     }
591
592     if (!strcmp (path, "console"))
593     {
594         if (pid > 0)
595         {
596             char fd_name[256];
597
598             if (xev_trace_fd >= 0)
599                 close (xev_trace_fd);
600
601             snprintf (fd_name, sizeof (fd_name), "/proc/%d/fd/1", pid);
602
603             xev_trace_fd = open (fd_name, O_RDWR);
604             if (xev_trace_fd < 0)
605                 XDBG_REPLY ("failed: open consol '%s'. (%s)\n", fd_name, strerror(errno));
606         }
607
608         return TRUE;
609     }
610
611     for (i = 0; i < sizeof (temp) / sizeof (char*); i++)
612         if (path == strstr (path, temp[i]))
613         {
614             valid = TRUE;
615             break;
616         }
617
618     if (!valid)
619     {
620         XDBG_REPLY ("failed: invalid path(%s)\n", path);
621         return FALSE;
622     }
623
624     if (path[0] == '/')
625         snprintf (fd_name, XDBG_PATH_MAX, "%s", path);
626     else
627     {
628         char cwd[128];
629         if (getcwd (cwd, sizeof (cwd)))
630             snprintf (fd_name, XDBG_PATH_MAX, "%s/%s", cwd, path);
631         else
632             snprintf (fd_name, XDBG_PATH_MAX, "%s", path);
633     }
634
635     xev_trace_record_fd = open (fd_name, O_CREAT|O_RDWR|O_APPEND, 0755);
636     if (xev_trace_record_fd < 0)
637     {
638         XDBG_REPLY ("failed: open file '%s'. (%s)\n", fd_name, strerror(errno));
639         return FALSE;
640     }
641
642     return TRUE;
643 }