print button event always
[adaptation/xorg/driver/xserver-xorg-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     XDBG_RETURN_IF_FAIL (evinfo != NULL);
84
85     write_len = sizeof (int) +
86                 sizeof (EvlogType) +
87                 sizeof (int) +
88                 sizeof (CARD32);
89
90     if (evinfo->mask & EVLOG_MASK_CLIENT)
91         write_len += sizeof (EvlogClient);
92
93     if (evinfo->mask & EVLOG_MASK_REQUEST)
94         write_len += (sizeof (EvlogRequest) + (evinfo->req.length * 4));
95
96     if (evinfo->mask & EVLOG_MASK_EVENT)
97         write_len += (sizeof (EvlogEvent) + sizeof (xEvent));
98
99     if (write (fd, &write_len, sizeof(int)) == -1)
100     {
101         XDBG_ERROR (MXDBG, "failed: write write_len\n");
102         return;
103     }
104     if (write (fd, &evinfo->time, sizeof(CARD32)) == -1)
105     {
106         XDBG_ERROR (MXDBG, "failed: write msec\n");
107         return;
108     }
109     if (write (fd, &evinfo->type, sizeof(EvlogType)) == -1)
110     {
111         XDBG_ERROR (MXDBG, "failed: write type\n");
112         return;
113     }
114     if (write (fd, &evinfo->mask, sizeof(int)) == -1)
115     {
116         XDBG_ERROR (MXDBG, "failed: write mask\n");
117         return;
118     }
119
120     if (evinfo->mask & EVLOG_MASK_CLIENT)
121         if (write (fd, &evinfo->client, sizeof (EvlogClient)) == -1)
122         {
123             XDBG_ERROR (MXDBG, "failed: write client\n");
124             return;
125         }
126
127     if (evinfo->mask & EVLOG_MASK_REQUEST)
128     {
129         if (write (fd, &evinfo->req, sizeof (EvlogRequest)) == -1)
130         {
131             XDBG_ERROR (MXDBG, "failed: write request\n");
132             return;
133         }
134         if (write (fd, evinfo->req.ptr, (evinfo->req.length * 4)) == -1)
135         {
136             XDBG_ERROR (MXDBG, "failed: write request\n");
137             return;
138         }
139     }
140     if (evinfo->mask & EVLOG_MASK_EVENT)
141     {
142         if (write (fd, &evinfo->evt, sizeof (EvlogEvent)) == -1)
143         {
144             XDBG_ERROR (MXDBG, "failed: write event\n");
145             return;
146         }
147         if (write (fd, evinfo->evt.ptr, sizeof (xEvent)) == -1)
148         {
149             XDBG_ERROR (MXDBG, "failed: write event\n");
150             return;
151         }
152     }
153 }
154
155 static void evtPrintF (int fd, EvlogInfo *evinfo)
156 {
157     char log[1024];
158     int size = sizeof (log);
159
160     xDbgEvlogFillLog (evinfo, log, &size);
161
162     if (fd < 0)
163         ErrorF ("%s", log);
164     else
165         dprintf (fd, "%s", log);
166 }
167
168 static void evtPrint (EvlogType type, ClientPtr client, xEvent *ev)
169 {
170     EvlogInfo evinfo = {0,};
171
172     /* evinfo.type */
173     evinfo.type = type;
174
175     /* evinfo.client */
176     if (client)
177     {
178         ModuleClientInfo *info = GetClientInfo (client);
179         XDBG_RETURN_IF_FAIL (info != NULL);
180
181         evinfo.mask |= EVLOG_MASK_CLIENT;
182         evinfo.client.index = info->index;
183         evinfo.client.pid = info->pid;
184         evinfo.client.gid = info->gid;
185         evinfo.client.uid = info->uid;
186         strncpy (evinfo.client.command, info->command, strlen (info->command));
187
188         /* evinfo.req */
189         if (type == REQUEST)
190         {
191             REQUEST (xReq);
192
193             evinfo.mask |= EVLOG_MASK_REQUEST;
194             evinfo.req.id = stuff->reqType;
195             evinfo.req.length = client->req_len;
196             evinfo.req.ptr = client->requestBuffer;
197
198             if (stuff->reqType < EXTENSION_BASE)
199                 snprintf (evinfo.req.name, sizeof (evinfo.req.name), "%s",
200                           LookupRequestName (stuff->reqType, 0));
201             else
202                 snprintf (evinfo.req.name, sizeof (evinfo.req.name), "%s",
203                           LookupRequestName (stuff->reqType, stuff->data));
204         }
205     }
206
207     /* evinfo.evt */
208     if (ev)
209     {
210         XDBG_RETURN_IF_FAIL (type == EVENT);
211
212         evinfo.mask |= EVLOG_MASK_EVENT;
213         evinfo.evt.ptr = ev;
214         snprintf (evinfo.evt.name, sizeof (evinfo.evt.name), "%s",
215                   LookupEventName ((int)(ev->u.u.type)));
216     }
217
218     /* evinfo.time */
219     evinfo.time = GetTimeInMillis ();
220
221     if (!xDbgEvlogRuleValidate (&evinfo))
222         return;
223
224     if (xev_trace_record_fd >= 0)
225         evtRecord (xev_trace_record_fd, &evinfo);
226     else
227         evtPrintF (xev_trace_fd, &evinfo);
228
229 }
230
231 static const char*
232 _traceGetWindowName (ClientPtr client, Window window)
233 {
234     int rc;
235     WindowPtr pWin;
236     Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess;
237     Atom property;
238     PropertyPtr pProp;
239     static char winname[128];
240     int datalen;
241
242     rc = dixLookupWindow (&pWin, window, client, win_mode);
243     if (rc != Success)
244         return NULL;
245
246     property = MakeAtom ("WM_NAME", strlen ("WM_NAME"), TRUE);
247     while (pWin)
248     {
249         rc = dixLookupProperty (&pProp, pWin, property, client, prop_mode);
250         if (rc == Success && pProp->data)
251         {
252             datalen = (pProp->size>127) ?127:pProp->size;
253             strncpy (winname, pProp->data, datalen);
254             winname[datalen] = 0;
255
256             return winname;
257         }
258
259         pWin = pWin->parent;
260     }
261
262     return NULL;
263 }
264
265 static void
266 _traceFlush (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
267 {
268     if (xev_trace_on == FALSE)
269         return;
270
271     evtPrint (FLUSH, NULL, NULL);
272 }
273
274 static void
275 _traceAReply (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
276 {
277     if (xev_trace_on == FALSE)
278         return;
279
280     ReplyInfoRec *pri = (ReplyInfoRec*)calldata;
281
282     evtPrint (REPLY, pri->client, NULL);
283 }
284
285 static void
286 _traceEvent (CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
287 {
288     EventInfoRec *pei = (EventInfoRec*)calldata;
289     ClientPtr pClient;
290     ModuleClientInfo *info;
291     int ev; /* event index */
292     static int xi2_opcode = -1;
293     xEvent *pev;
294     static char* ename[]=
295     {
296         "KeyPress",
297         "KeyRelease",
298         "ButtonPress",
299         "ButtonRelease",
300     };
301
302     XDBG_RETURN_IF_FAIL (pei != NULL);
303
304     pClient = pei->client;
305     XDBG_RETURN_IF_FAIL (pClient != NULL);
306
307     pev = pei->events;
308     XDBG_RETURN_IF_FAIL (pev != NULL);
309
310     info = GetClientInfo (pClient);
311     XDBG_RETURN_IF_FAIL (info != NULL);
312
313     for (ev=0; ev < pei->count; ev++, pev++)
314     {
315         int type = pev->u.u.type & 0177;
316
317         if (type < LASTEvent)
318         {
319             switch (type)
320             {
321             case KeyPress:
322             case KeyRelease:
323                 XDBG_INFO (MXDBG, "%s(%d)_%d(%s.%d : %s.0x%lx) root(%d,%d) win(%d,%d)\n"
324                         , ename[type-KeyPress], pev->u.u.detail, pev->u.u.type
325                         , info->command, info->pid
326                         , _traceGetWindowName (pClient, pev->u.keyButtonPointer.event), pev->u.keyButtonPointer.event
327                         , pev->u.keyButtonPointer.rootX, pev->u.keyButtonPointer.rootY
328                         , pev->u.keyButtonPointer.eventX, pev->u.keyButtonPointer.eventY);
329                 break;
330
331             case ButtonPress:
332             case ButtonRelease:
333                 XDBG_INFO (MXDBG, "%s(%d)_%d(%s.%d : %s.0x%lx) root(%d,%d) win(%d,%d)\n"
334                         , ename[type-KeyPress], pev->u.u.detail, pev->u.u.type
335                         , info->command, info->pid
336                         , _traceGetWindowName (pClient, pev->u.keyButtonPointer.event), pev->u.keyButtonPointer.event
337                         , pev->u.keyButtonPointer.rootX, pev->u.keyButtonPointer.rootY
338                         , pev->u.keyButtonPointer.eventX, pev->u.keyButtonPointer.eventY);
339                 break;
340             case GenericEvent:
341                 if(!xi2_opcode) break;
342                 if(xi2_opcode < 0)
343                 {
344                     ExtensionEntry *pExt = CheckExtension("XInputExtension");
345                     if(!pExt) xi2_opcode = 0;
346                     else xi2_opcode = pExt->base;
347                 }
348
349                 if(((xGenericEvent*)pev)->extension != xi2_opcode) break;
350
351                 xXIDeviceEvent *xidev = (xXIDeviceEvent *)pev;
352                 if(xidev->deviceid==2) break;
353                 if(xidev->evtype==XI_ButtonPress)
354                     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));
355                 else if(xidev->evtype==XI_ButtonRelease)
356                     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));
357                 else if(xidev->evtype==XI_Motion)
358                     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));
359                 break;
360             default:
361                 break;
362             }
363         }
364
365         if (xev_trace_on)
366             evtPrint (EVENT, pClient, pev);
367     }
368 }
369
370 static void
371 _traceACoreEvents (CallbackListPtr *pcbl, pointer unused, pointer calldata)
372 {
373     if (xev_trace_on == FALSE)
374         return;
375
376     XaceCoreDispatchRec *rec = calldata;
377
378     XDBG_RETURN_IF_FAIL (rec != NULL);
379
380     evtPrint (REQUEST, rec->client, NULL);
381 }
382
383 static void
384 _traceAExtEvents (CallbackListPtr *pcbl, pointer unused, pointer calldata)
385 {
386     if (xev_trace_on == FALSE)
387         return;
388
389     XaceExtAccessRec *rec = calldata;
390
391     XDBG_RETURN_IF_FAIL (rec != NULL);
392
393     evtPrint (REQUEST, rec->client, NULL);
394 }
395
396 static void
397 _traceProperty (CallbackListPtr *pcbl, pointer unused, pointer calldata)
398 {
399     XacePropertyAccessRec *rec = calldata;
400     ModuleClientInfo *info = GetClientInfo (rec->client);
401     PropertyPtr pProp = *rec->ppProp;
402     Atom name = pProp->propertyName;
403
404     /* Don't care about the new content check */
405     if (rec->client == serverClient || rec->access_mode & DixPostAccess)
406         return;
407
408     if (name == atom_client_pid && (rec->access_mode & DixWriteAccess))
409     {
410         XDBG_WARNING (MXDBG, "Invalid access X_CLINET_PID pid:%d, uid:%d\n", info->pid, info->uid);
411         rec->status = BadAccess;
412         return;
413     }
414
415     rec->status = Success;
416     return;
417 }
418
419 static void
420 _traceResource (CallbackListPtr *pcbl, pointer unused, pointer calldata)
421 {
422     XaceResourceAccessRec *rec = calldata;
423     Mask access_mode = rec->access_mode;
424     ModuleClientInfo *info = GetClientInfo (rec->client);
425
426     /* Perform the background none check on windows */
427     if (access_mode & DixCreateAccess && rec->rtype == RT_WINDOW)
428     {
429         WindowPtr pWin = (WindowPtr) rec->res;
430         int rc;
431         int pid = info->pid;
432
433         rc = dixChangeWindowProperty (serverClient,
434                                       pWin, atom_client_pid, XA_CARDINAL, 32,
435                                       PropModeReplace, 1, &pid, FALSE);
436         if (rc != Success)
437             XDBG_ERROR (MXDBG, "failed : set X_CLIENT_PID to %d.\n", pid);
438     }
439 }
440
441 static void
442 _traceReceive (CallbackListPtr *pcbl, pointer unused, pointer calldata)
443 {
444     XaceReceiveAccessRec *rec = calldata;
445
446     if (rec->events->u.u.type != VisibilityNotify)
447         return;
448
449     rec->status = BadAccess;
450 }
451
452 Bool
453 xDbgModuleEvlogInstallHooks (XDbgModule *pMod)
454 {
455     int ret = TRUE;
456
457     ret &= AddCallback (&EventCallback, _traceEvent, NULL);
458     ret &= XaceRegisterCallback (XACE_PROPERTY_ACCESS, _traceProperty, NULL);
459     ret &= XaceRegisterCallback (XACE_RESOURCE_ACCESS, _traceResource, NULL);
460
461     /*Disable Visibility Event*/
462     ret &= XaceRegisterCallback (XACE_RECEIVE_ACCESS, _traceReceive, NULL);
463
464     if (atom_client_pid == None)
465         atom_client_pid = MakeAtom ("X_CLIENT_PID", 12, TRUE);
466     if (atom_rotate == None)
467         atom_rotate = MakeAtom ("_E_ILLUME_ROTATE_ROOT_ANGLE", 12, TRUE);
468
469     if (!ret)
470     {
471         XDBG_ERROR (MXDBG, "failed: register one or more callbacks\n");
472         return FALSE;
473     }
474
475     if (pMod && pMod->evlog_path)
476         xDbgModuleEvlogSetEvlogPath (pMod, -1, pMod->evlog_path, NULL, NULL);
477
478     return TRUE;
479 }
480
481 void
482 xDbgModuleEvlogUninstallHooks (XDbgModule *pMod)
483 {
484     DeleteCallback (&EventCallback, _traceEvent, NULL);
485     XaceDeleteCallback (XACE_PROPERTY_ACCESS, _traceProperty, NULL);
486     XaceDeleteCallback (XACE_RESOURCE_ACCESS, _traceResource, NULL);
487 }
488
489 void
490 xDbgModuleEvlogPrintEvents (XDbgModule *pMod, Bool on, const char * client_name, char *reply, int *len)
491 {
492     int ret = TRUE;
493
494     on = (on)?TRUE:FALSE;
495     if (xev_trace_on == on)
496         return;
497
498     xev_trace_on = on;
499
500     if (xev_trace_on)
501     {
502         int i;
503
504         //Find client's pid
505         for (i=1 ; i< currentMaxClients ; i++)
506         {
507             ClientPtr pClient;
508             ModuleClientInfo *info;
509
510             pClient = clients[i];
511             if (!pClient)
512                 continue;
513
514             info = GetClientInfo (pClient);
515             if (!info)
516                 continue;
517
518             if (strlen (info->command) > 0 && strstr (client_name, info->command))
519             {
520                 char fd_name[256];
521
522                 if (xev_trace_fd >= 0)
523                     close (xev_trace_fd);
524
525                 snprintf (fd_name, 256, "/proc/%d/fd/1", info->pid);
526                 xev_trace_fd = open (fd_name, O_RDWR);
527                 if (xev_trace_fd < 0)
528                     XDBG_REPLY ("failed: open consol '%s'. (%s)\n", fd_name, strerror(errno));
529             }
530         }
531
532         ret &= AddCallback (&FlushCallback, _traceFlush, NULL);
533         ret &= AddCallback (&ReplyCallback, _traceAReply, NULL);
534         ret &= XaceRegisterCallback (XACE_CORE_DISPATCH, _traceACoreEvents, NULL);
535         ret &= XaceRegisterCallback (XACE_EXT_DISPATCH, _traceAExtEvents, NULL);
536
537         if (!ret)
538         {
539             XDBG_REPLY ("failed: register one or more callbacks.\n");
540             return;
541         }
542     }
543     else
544     {
545         DeleteCallback (&FlushCallback, _traceFlush, NULL);
546         DeleteCallback (&ReplyCallback, _traceAReply, NULL);
547         XaceDeleteCallback (XACE_CORE_DISPATCH, _traceACoreEvents, NULL);
548         XaceDeleteCallback (XACE_EXT_DISPATCH, _traceAExtEvents, NULL);
549     }
550
551     return;
552 }
553
554 int
555 xDbgModuleEvlogInfoSetRule (XDbgModule *pMod, const int argc, const char ** argv, char *reply, int *len)
556 {
557     return xDbgEvlogRuleSet (argc, argv, reply, len);
558 }
559
560 Bool
561 xDbgModuleEvlogSetEvlogPath (XDbgModule *pMod, int pid, char *path, char *reply, int *len)
562 {
563     char fd_name[XDBG_PATH_MAX];
564     char *temp[3] = {"/", "./", "../"};
565     Bool valid = FALSE;
566     int i;
567
568     if (!path || strlen (path) <= 0)
569     {
570         XDBG_REPLY ("failed: invalid path\n");
571         return FALSE;
572     }
573
574     if (xev_trace_record_fd >= 0)
575     {
576         close (xev_trace_record_fd);
577         xev_trace_record_fd = -1;
578     }
579
580     if (!strcmp (path, "console"))
581     {
582         if (pid > 0)
583         {
584             char fd_name[256];
585
586             if (xev_trace_fd >= 0)
587                 close (xev_trace_fd);
588
589             snprintf (fd_name, sizeof (fd_name), "/proc/%d/fd/1", pid);
590
591             xev_trace_fd = open (fd_name, O_RDWR);
592             if (xev_trace_fd < 0)
593                 XDBG_REPLY ("failed: open consol '%s'. (%s)\n", fd_name, strerror(errno));
594         }
595
596         return TRUE;
597     }
598
599     for (i = 0; i < sizeof (temp) / sizeof (char*); i++)
600         if (path == strstr (path, temp[i]))
601         {
602             valid = TRUE;
603             break;
604         }
605
606     if (!valid)
607     {
608         XDBG_REPLY ("failed: invalid path(%s)\n", path);
609         return FALSE;
610     }
611
612     if (path[0] == '/')
613         snprintf (fd_name, XDBG_PATH_MAX, "%s", path);
614     else
615     {
616         char cwd[128];
617         if (getcwd (cwd, sizeof (cwd)))
618             snprintf (fd_name, XDBG_PATH_MAX, "%s/%s", cwd, path);
619         else
620             snprintf (fd_name, XDBG_PATH_MAX, "%s", path);
621     }
622
623     xev_trace_record_fd = open (fd_name, O_CREAT|O_RDWR|O_APPEND, 0755);
624     if (xev_trace_record_fd < 0)
625     {
626         XDBG_REPLY ("failed: open file '%s'. (%s)\n", fd_name, strerror(errno));
627         return FALSE;
628     }
629
630     return TRUE;
631 }