system-monitor: removed now implicit MRP_LUA_CLASS_PRIVREFS.
[profile/ivi/murphy.git] / src / plugins / system-monitor / process-watch.c
1 /*
2  * Copyright (c) 2014, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *  * Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *  * Neither the name of Intel Corporation nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <errno.h>
31 #include <string.h>
32 #include <pwd.h>
33 #include <grp.h>
34 #include <sys/types.h>
35
36 #include <murphy/common/macros.h>
37 #include <murphy/common/debug.h>
38 #include <murphy/common/log.h>
39 #include <murphy/common/mm.h>
40 #include <murphy/core/lua-utils/object.h>
41 #include <murphy/core/lua-utils/funcbridge.h>
42 #include <murphy/core/lua-bindings/murphy.h>
43
44 #include "process-watch.h"
45
46 /*
47  * process watch object
48  */
49
50 #define PROCESS_WATCH_LUA_CLASS MRP_LUA_CLASS(process_watch, lua)
51 #define RO                      MRP_LUA_CLASS_READONLY
52 #define NOINIT                  MRP_LUA_CLASS_NOINIT
53 #define NOFLAGS                 MRP_LUA_CLASS_NOFLAGS
54 #define setmember               process_watch_setmember
55 #define getmember               process_watch_getmember
56
57 static int process_watch_no_constructor(lua_State *L);
58 static void process_watch_destroy(void *data);
59 static void process_watch_changed(void *data, lua_State *L, int member);
60 static ssize_t process_watch_tostring(mrp_lua_tostr_mode_t mode, char *buf,
61                                       size_t size, lua_State *L, void *data);
62 static int process_watch_setmember(void *data, lua_State *L, int member,
63                                    mrp_lua_value_t *v);
64 static int process_watch_getmember(void *data, lua_State *L, int member,
65                                    mrp_lua_value_t *v);
66 static int process_watch_delete(lua_State *L);
67
68 static int setup_filter(process_watch_lua_t *w, lua_State *L, int filterref);
69
70
71 MRP_LUA_METHOD_LIST_TABLE(process_watch_methods,
72     MRP_LUA_METHOD_CONSTRUCTOR(process_watch_no_constructor)
73     MRP_LUA_METHOD(delete, process_watch_delete));
74
75 MRP_LUA_METHOD_LIST_TABLE(process_watch_overrides,
76     MRP_LUA_OVERRIDE_CALL(process_watch_no_constructor));
77
78 MRP_LUA_MEMBER_LIST_TABLE(process_watch_members,
79     MRP_LUA_CLASS_INTEGER("events", 0, setmember, getmember, RO)
80     MRP_LUA_CLASS_ANY    ("filter", 0, setmember, getmember, RO)
81     MRP_LUA_CLASS_ANY    ("notify", 0, setmember, getmember, RO));
82
83 MRP_LUA_DEFINE_CLASS(process_watch, lua, process_watch_lua_t,
84                      process_watch_destroy, process_watch_methods,
85                      process_watch_overrides, process_watch_members, NULL,
86                      process_watch_changed, process_watch_tostring, NULL,
87                      MRP_LUA_CLASS_EXTENSIBLE);
88
89 MRP_LUA_CLASS_CHECKER(process_watch_lua_t, process_watch_lua,
90                       PROCESS_WATCH_LUA_CLASS);
91
92 typedef enum {
93     PROCESS_WATCH_MEMBER_EVENTS,
94     PROCESS_WATCH_MEMBER_FILTER,
95     PROCESS_WATCH_MEMBER_NOTIFY
96 } process_watch_member_t;
97
98
99 /*
100  * process event object
101  */
102
103 #define PROCESS_EVENT_CLASS MRP_LUA_CLASS_SIMPLE(ProcessEvent)
104
105 typedef struct {
106     mrp_proc_event_t *event;
107 } ProcessEvent_t;
108
109 typedef ProcessEvent_t process_event_lua_t;
110
111 static int event_no_constructor(lua_State *L);
112 static void *event_create(lua_State *L, mrp_proc_event_t *e);
113 static int event_setfield(lua_State *L);
114 static int event_getfield(lua_State *L);
115 static void event_destroy(void *data);
116 static process_event_lua_t *event_check(lua_State *L, int idx);
117 static bool register_event_class(lua_State *L);
118
119 MRP_LUA_CLASS_DEF_SIMPLE(
120     ProcessEvent,
121     ProcessEvent_t,
122     event_destroy,
123     MRP_LUA_METHOD_LIST(
124         MRP_LUA_METHOD_CONSTRUCTOR(event_no_constructor)),
125     MRP_LUA_METHOD_LIST(
126         MRP_LUA_OVERRIDE_CALL(event_no_constructor)
127         MRP_LUA_OVERRIDE_GETFIELD(event_getfield)
128         MRP_LUA_OVERRIDE_SETFIELD(event_setfield)));
129
130 static int process_watch_no_constructor(lua_State *L)
131 {
132     return luaL_error(L, "trying to create a process watch via constructor.");
133 }
134
135
136 static void process_watch_notify(process_watch_lua_t *w, lua_State *L,
137                                  mrp_proc_event_t *e)
138 {
139     mrp_funcbridge_value_t args[3], rv;
140     char                            rt;
141
142     if (L == NULL || w->notify == NULL)
143         return;
144
145     mrp_debug("notifying process watch %p", w);
146
147     args[0].pointer = w;
148     args[1].pointer = event_create(L, e);
149
150     if (!mrp_funcbridge_call_from_c(L, w->notify, "OO", &args[0], &rt, &rv)) {
151         mrp_log_error("Failed to notify process watch %p.", w);
152         mrp_free((char *)rv.string);
153     }
154 }
155
156
157 static void event_cb(mrp_proc_watch_t *pw, mrp_proc_event_t *e, void *user_data)
158 {
159     process_watch_lua_t *w = (process_watch_lua_t *)user_data;
160
161     MRP_UNUSED(pw);
162
163     mrp_debug("got notification (0x%x) for process watch %p", e->type, w);
164
165     process_watch_notify(w, mrp_lua_get_lua_state(), e);
166 }
167
168
169 process_watch_lua_t *process_watch_create(sysmon_lua_t *sm, lua_State *L)
170 {
171     process_watch_lua_t *w;
172     mrp_context_t       *ctx;
173     mrp_proc_filter_t   *f;
174     char                 e[256];
175
176     luaL_checktype(L, 2, LUA_TTABLE);
177
178     w = (process_watch_lua_t *)mrp_lua_create_object(L, PROCESS_WATCH_LUA_CLASS,
179                                                      NULL, 0);
180
181     mrp_list_init(&w->hook);
182     w->sysmon     = sm;
183     w->watchref   = LUA_NOREF;
184     w->filterref  = LUA_NOREF;
185     w->filter.uid = -1;
186     w->filter.gid = -1;
187
188     if (mrp_lua_init_members(w, L, 2, e, sizeof(e)) != 1) {
189         luaL_error(L, "failed to initialize process watch (error: %s)",
190                    *e ? e : "<unknown error>");
191         return NULL;
192     }
193
194     if (w->notify == NULL) {
195         luaL_error(L, "process watch notification callback not set");
196         return NULL;
197     }
198
199     if (w->filter.pid != 0 || w->filter.path || w->filter.comm ||
200         w->filter.uid != (uid_t)-1 || w->filter.gid != (gid_t)-1)
201         f = &w->filter;
202     else
203         f = NULL;
204
205     ctx  = mrp_lua_get_murphy_context();
206     w->w = mrp_add_proc_watch(ctx->ml, w->mask, f, event_cb, w);
207
208     if (w->w != NULL)
209         return w;
210     else {
211         luaL_error(L, "failed to create process watch");
212         return NULL;
213     }
214 }
215
216
217 static void process_watch_destroy(void *data)
218 {
219     mrp_debug("process watch %p destroyed", data);
220 }
221
222
223 static int process_watch_delete(lua_State *L)
224 {
225     process_watch_lua_t *w = process_watch_lua_check(L, 1);
226
227     mrp_lua_object_unref_value(w, L, w->filterref);
228     w->filterref = LUA_NOREF;
229
230     mrp_del_proc_watch(w->w);
231     sysmon_del_process_watch(w->sysmon, w);
232
233     return 0;
234 }
235
236
237 static void process_watch_changed(void *data, lua_State *L, int member)
238 {
239     MRP_UNUSED(data);
240     MRP_UNUSED(L);
241     MRP_UNUSED(member);
242 }
243
244
245 static int process_watch_setmember(void *data, lua_State *L, int member,
246                                    mrp_lua_value_t *v)
247 {
248     process_watch_lua_t *w = (process_watch_lua_t *)data;
249
250     switch (member) {
251     case PROCESS_WATCH_MEMBER_EVENTS:
252         w->mask = v->s32;
253         return 1;
254
255     case PROCESS_WATCH_MEMBER_FILTER:
256         if (v->any != LUA_NOREF)
257             return setup_filter(w, L, v->any);
258         else
259             return 1;
260
261     case PROCESS_WATCH_MEMBER_NOTIFY:
262         if (!mrp_lua_object_deref_value(w, L, v->any, false))
263             return 0;
264         switch (lua_type(L, -1)) {
265         case LUA_TFUNCTION:
266             w->notify = mrp_funcbridge_create_luafunc(L, -1);
267             break;
268         default:
269             w->notify = NULL;
270             break;
271         }
272         lua_pop(L, 1);
273         mrp_lua_object_unref_value(w, L, v->any);
274
275         return (w->notify != NULL ? 1 : 0);
276
277     default:
278         mrp_log_error("Can't set read-only process watch member #%d.", member);
279         return 0;
280     }
281 }
282
283
284 static int process_watch_getmember(void *data, lua_State *L, int member,
285                                    mrp_lua_value_t *v)
286 {
287     process_watch_lua_t *w = (process_watch_lua_t *)data;
288
289     MRP_UNUSED(data);
290     MRP_UNUSED(L);
291
292     switch (member) {
293     case PROCESS_WATCH_MEMBER_EVENTS:
294         v->s32 = w->mask;
295         return 1;
296
297     case PROCESS_WATCH_MEMBER_FILTER:
298         v->any = w->filterref;
299         return 1;
300
301     default:
302         v->any = LUA_REFNIL;
303         return 1;
304     }
305 }
306
307
308 static ssize_t process_watch_tostring(mrp_lua_tostr_mode_t mode, char *buf,
309                                       size_t size, lua_State *L, void *data)
310 {
311     process_watch_lua_t *w = (process_watch_lua_t *)data;
312
313     MRP_UNUSED(L);
314
315     switch (mode & MRP_LUA_TOSTR_MODEMASK) {
316     case MRP_LUA_TOSTR_LUA:
317     default:
318         return snprintf(buf, size, "{process watch %p}", w);
319     }
320 }
321
322
323 int process_event_mask(lua_State *L, int idx)
324 {
325     mrp_proc_event_type_t  mask;
326     const char            *event, *name;
327     int                    ktype, type, i;
328     size_t                 len;
329
330     mask = 0;
331     MRP_LUA_FOREACH_ALL(L, i, idx, ktype, name, len) {
332         if (ktype != LUA_TNUMBER || (type = lua_type(L, -1)) != LUA_TSTRING) {
333             mrp_log_warning("ignoring invalid event (0x%x: 0x%x)", ktype, type);
334             continue;
335         }
336         else
337             event = lua_tolstring(L, -1, &len);
338
339         switch (len) {
340         case 3:
341             if (!strcmp(event, "uid"))
342                 mask |= MRP_PROC_EVENT_UID;
343             else if (!strcmp(event, "gid"))
344                 mask |= MRP_PROC_EVENT_GID;
345             else if (!strcmp(event, "sid"))
346                 mask |= MRP_PROC_EVENT_SID;
347             else
348                 goto unknown;
349             break;
350
351         case 4:
352             if (!strcmp(event, "none"))
353                 mask |= MRP_PROC_EVENT_NONE;
354             else if (!strcmp(event, "fork"))
355                 mask |= MRP_PROC_EVENT_FORK;
356             else if (!strcmp(event, "exec"))
357                 mask |= MRP_PROC_EVENT_EXEC;
358             else if (!strcmp(event, "exit"))
359                 mask |= MRP_PROC_EVENT_EXIT;
360             else if (!strcmp(event, "user"))
361                 mask |= MRP_PROC_EVENT_UID;
362             else if (!strcmp(event, "comm"))
363                 mask |= MRP_PROC_EVENT_COMM;
364             else if (!strcmp(event, "core"))
365                 mask |= MRP_PROC_EVENT_COREDUMP;
366             else
367                 goto unknown;
368             break;
369
370         case 5:
371             if (!strcmp(event, "trace"))
372                 mask |= MRP_PROC_EVENT_PTRACE;
373             else if (!strcmp(event, "group"))
374                 mask |= MRP_PROC_EVENT_GID;
375             else
376                 goto unknown;
377             break;
378
379         case 6:
380             if (!strcmp(event, "ptrace"))
381                 mask |= MRP_PROC_EVENT_PTRACE;
382             else
383                 goto unknown;
384             break;
385
386         case 7:
387             if (!strcmp(event, "session"))
388                 mask |= MRP_PROC_EVENT_SID;
389             else if (!strcmp(event, "recurse"))
390                 mask |= MRP_PROC_RECURSE;
391             else
392                 goto unknown;
393             break;
394
395         case 8:
396             if (!strcmp(event, "coredump"))
397                 mask |= MRP_PROC_EVENT_COREDUMP;
398             else
399                 goto unknown;
400             break;
401
402         case 9:
403             if (!strcmp(event, "nothreads"))
404                 mask |= MRP_PROC_IGNORE_THREADS;
405             else
406                 goto unknown;
407             break;
408
409         case 13:
410             if (!strcmp(event, "ignorethreads"))
411                 mask |= MRP_PROC_IGNORE_THREADS;
412             else
413                 goto unknown;
414             break;
415
416         unknown:
417         default:
418             mrp_log_warning("ignoring unknown process event '%s'", event);
419             break;
420         }
421     }
422
423     lua_pushinteger(L, mask);
424     return 1;
425 }
426
427
428 static int setup_filter(process_watch_lua_t *w, lua_State *L, int filterref)
429 {
430     int         top = lua_gettop(L);
431     int         ktype, i;
432     const char *kname, *usr, *grp;
433     size_t      klen, len;
434
435     if (!mrp_lua_object_deref_value(w, L, filterref, false)) {
436         mrp_log_error("Failed to dereference process watch filter table.");
437         return 0;
438     }
439
440     MRP_LUA_FOREACH_ALL(L, i, top + 1, ktype, kname, klen) {
441         if (ktype != LUA_TSTRING) {
442             mrp_log_error("Invalid process watch filter (non-string key).");
443             goto fail;
444         }
445
446         kname = lua_tolstring(L, -2, &len);
447
448         if (!strcmp(kname, "pid") || !strcmp(kname, "process")) {
449             if (lua_type(L, -1) != LUA_TNUMBER) {
450                 mrp_log_error("Invalid process watch filter pid.");
451                 goto fail;
452             }
453
454             w->filter.pid = lua_tointeger(L, -1);
455             continue;
456         }
457
458         if (!strcmp(kname, "path")) {
459             if (lua_type(L, -1) != LUA_TSTRING) {
460                 mrp_log_error("Invalid process watch filter path.");
461                 goto fail;
462             }
463
464             w->filter.path = mrp_strdup(lua_tostring(L, -1));
465             continue;
466         }
467
468         if (!strcmp(kname, "comm") || !strcmp(kname, "name")) {
469             if (lua_type(L, -1) != LUA_TSTRING) {
470                 mrp_log_error("Invalid process watch filter comm.");
471                 goto fail;
472             }
473
474             w->filter.comm = mrp_strdup(lua_tostring(L, -1));
475             continue;
476         }
477
478         if (!strcmp(kname, "uid") || !strcmp(kname, "user")) {
479             if (lua_type(L, -1) == LUA_TNUMBER) {
480                 w->filter.uid = lua_tointeger(L, -1);
481                 continue;
482             }
483
484             if (lua_type(L, -1) == LUA_TSTRING) {
485                 struct passwd *pw = getpwnam(usr = lua_tolstring(L, -1, &len));
486
487                 if (pw == NULL) {
488                     mrp_log_error("Unknown process watch filter user '%s'.",
489                                   usr);
490                     goto fail;
491                 }
492
493                 w->filter.uid = pw->pw_uid;
494                 continue;
495             }
496
497             mrp_log_error("Invalid process watch filter user.");
498             goto fail;
499         }
500
501         if (!strcmp(kname, "gid") || !strcmp(kname, "group")) {
502             if (lua_type(L, -1) == LUA_TNUMBER) {
503                 w->filter.gid = lua_tointeger(L, -1);
504                 continue;
505             }
506
507             if (lua_type(L, -1) == LUA_TSTRING) {
508                 struct group *gr = getgrnam(grp = lua_tolstring(L, -1, &len));
509
510                 if (gr == NULL) {
511                     mrp_log_error("Unknown process watch filter group '%s'.",
512                                   grp);
513                     goto fail;
514                 }
515
516                 w->filter.gid = gr->gr_gid;
517                 continue;
518             }
519
520             mrp_log_error("Invalid process watch filter group.");
521             goto fail;
522         }
523
524         mrp_log_error("Invalid process watch filter field '%s'.", kname);
525         goto fail;
526     }
527
528     w->filterref = mrp_lua_object_ref_value(w, L, top + 1);
529     lua_settop(L, top);
530
531     return 1;
532
533  fail:
534     lua_settop(L, top);
535     return 0;
536 }
537
538
539 static bool register_event_class(lua_State *L)
540 {
541     mrp_lua_create_object_class(L, PROCESS_EVENT_CLASS);
542
543     return true;
544 }
545
546
547 static int event_no_constructor(lua_State *L)
548 {
549     return luaL_error(L, "trying to create a process event via constructor.");
550 }
551
552
553 static void *event_create(lua_State *L, mrp_proc_event_t *event)
554 {
555     static bool          eclass = false;
556     process_event_lua_t *e;
557
558     if (!eclass)
559         if (!(eclass = register_event_class(L)))
560             return NULL;
561
562     e = (process_event_lua_t *)mrp_lua_create_object(L, PROCESS_EVENT_CLASS,
563                                                      NULL, 0);
564
565     if (e == NULL || (e->event = mrp_allocz(sizeof(*e->event))) == NULL) {
566         mrp_log_error("Failed to allocate process event.");
567         return NULL;
568     }
569
570     memcpy(e->event, event, sizeof(*e->event));
571
572     return e;
573 }
574
575
576 static int event_setfield(lua_State *L)
577 {
578     event_check(L, 1);
579     return luaL_error(L, "trying to set field on read-only process event");
580 }
581
582
583 static int event_getfield(lua_State *L)
584 {
585     process_event_lua_t *e = event_check(L, -2);
586     const char          *name, *type;;
587
588     if (lua_type(L, -1) != LUA_TSTRING)
589         return luaL_error(L, "process event has only string fields");
590
591     if (e->event == NULL) {
592         lua_pushnil(L);
593         return 1;
594     }
595
596     name = lua_tostring(L, -1);
597
598     if (!strcmp(name, "type")) {
599         switch (e->event->type) {
600         case MRP_PROC_EVENT_NONE:     type = "<none>"   ; break;
601         case MRP_PROC_EVENT_FORK:     type = "fork"     ; break;
602         case MRP_PROC_EVENT_EXEC:     type = "exec"     ; break;
603         case MRP_PROC_EVENT_EXIT:     type = "exit"     ; break;
604         case MRP_PROC_EVENT_UID:      type = "uid"      ; break;
605         case MRP_PROC_EVENT_GID:      type = "gid"      ; break;
606         case MRP_PROC_EVENT_SID:      type = "sid"      ; break;
607         case MRP_PROC_EVENT_PTRACE:   type = "ptrace"   ; break;
608         case MRP_PROC_EVENT_COMM:     type = "comm"     ; break;
609         case MRP_PROC_EVENT_COREDUMP: type = "coredump" ; break;
610         default:                      type = "<unknown>"; break;
611         }
612
613         lua_pushstring(L, type);
614         return 1;
615     }
616
617     if (!strcmp(name, "pid") || !strcmp(name, "process_pid")) {
618         if (e->event->type != MRP_PROC_EVENT_FORK)
619             lua_pushinteger(L, e->event->raw->event_data.exec.process_pid);
620         else
621             lua_pushnil(L);
622         return 1;
623     }
624
625     if (!strcmp(name, "tgid") || !strcmp(name, "process_tgid")) {
626         if (e->event->type != MRP_PROC_EVENT_FORK)
627             lua_pushinteger(L, e->event->raw->event_data.exec.process_tgid);
628         else
629             lua_pushnil(L);
630         return 1;
631     }
632
633     if (e->event->type == MRP_PROC_EVENT_FORK) {
634         if (!strcmp(name, "parent_pid"))
635             lua_pushinteger(L, e->event->raw->event_data.fork.parent_pid);
636         else if (!strcmp(name, "parent_tgid"))
637             lua_pushinteger(L, e->event->raw->event_data.fork.parent_tgid);
638         else if (!strcmp(name, "child_pid"))
639             lua_pushinteger(L, e->event->raw->event_data.fork.child_pid);
640         else if (!strcmp(name, "child_tgid"))
641             lua_pushinteger(L, e->event->raw->event_data.fork.child_tgid);
642         else
643             lua_pushnil(L);
644         return 1;
645     }
646
647     if (e->event->type == MRP_PROC_EVENT_UID) {
648         if (!strcmp(name, "ruid"))
649             lua_pushinteger(L, e->event->raw->event_data.id.r.ruid);
650         else if (!strcmp(name, "euid"))
651             lua_pushinteger(L, e->event->raw->event_data.id.e.euid);
652         else
653             lua_pushnil(L);
654         return 1;
655     }
656
657     if (e->event->type == MRP_PROC_EVENT_GID) {
658         if (!strcmp(name, "rgid"))
659             lua_pushinteger(L, e->event->raw->event_data.id.r.rgid);
660         else if (!strcmp(name, "egid"))
661             lua_pushinteger(L, e->event->raw->event_data.id.e.egid);
662         else
663             lua_pushnil(L);
664         return 1;
665     }
666
667     if (e->event->type == MRP_PROC_EVENT_PTRACE) {
668         if (!strcmp(name, "tracer_pid"))
669             lua_pushinteger(L, e->event->raw->event_data.ptrace.tracer_pid);
670         else if (!strcmp(name, "tracer_tgid"))
671             lua_pushinteger(L, e->event->raw->event_data.ptrace.tracer_tgid);
672         else
673             lua_pushnil(L);
674         return 1;
675     }
676
677     if (e->event->type == MRP_PROC_EVENT_COMM) {
678         if (!strcmp(name, "comm"))
679             lua_pushstring(L, e->event->raw->event_data.comm.comm);
680         else
681             lua_pushnil(L);
682         return 1;
683     }
684
685     if (e->event->type == MRP_PROC_EVENT_EXIT) {
686         if (!strcmp(name, "exit_code") || !strcmp(name, "code"))
687             lua_pushinteger(L, e->event->raw->event_data.exit.exit_code);
688         else if (!strcmp(name, "exit_signal") || !strcmp(name, "signal"))
689             lua_pushinteger(L, e->event->raw->event_data.exit.exit_signal);
690         else
691             lua_pushnil(L);
692         return 1;
693     }
694
695     lua_pushnil(L);
696     return 0;
697 }
698
699
700 static void event_destroy(void *data)
701 {
702     process_event_lua_t *e = (process_event_lua_t *)data;
703
704     mrp_free(e->event);
705     e->event = NULL;
706 }
707
708 static process_event_lua_t *event_check(lua_State *L, int idx)
709 {
710     return (process_event_lua_t *)
711         mrp_lua_check_object(L, PROCESS_EVENT_CLASS, idx);
712 }