2 * Copyright (c) 2014, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
34 #include <sys/types.h>
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>
44 #include "process-watch.h"
47 * process watch object
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
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,
64 static int process_watch_getmember(void *data, lua_State *L, int member,
66 static int process_watch_delete(lua_State *L);
68 static int setup_filter(process_watch_lua_t *w, lua_State *L, int filterref);
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));
75 MRP_LUA_METHOD_LIST_TABLE(process_watch_overrides,
76 MRP_LUA_OVERRIDE_CALL(process_watch_no_constructor));
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));
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 | MRP_LUA_CLASS_PRIVREFS);
89 MRP_LUA_CLASS_CHECKER(process_watch_lua_t, process_watch_lua,
90 PROCESS_WATCH_LUA_CLASS);
93 PROCESS_WATCH_MEMBER_EVENTS,
94 PROCESS_WATCH_MEMBER_FILTER,
95 PROCESS_WATCH_MEMBER_NOTIFY
96 } process_watch_member_t;
100 * process event object
103 #define PROCESS_EVENT_CLASS MRP_LUA_CLASS_SIMPLE(ProcessEvent)
106 mrp_proc_event_t *event;
109 typedef ProcessEvent_t process_event_lua_t;
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);
119 MRP_LUA_CLASS_DEF_SIMPLE(
124 MRP_LUA_METHOD_CONSTRUCTOR(event_no_constructor)),
126 MRP_LUA_OVERRIDE_CALL(event_no_constructor)
127 MRP_LUA_OVERRIDE_GETFIELD(event_getfield)
128 MRP_LUA_OVERRIDE_SETFIELD(event_setfield)));
130 static int process_watch_no_constructor(lua_State *L)
132 return luaL_error(L, "trying to create a process watch via constructor.");
136 static void process_watch_notify(process_watch_lua_t *w, lua_State *L,
139 mrp_funcbridge_value_t args[3], rv;
142 if (L == NULL || w->notify == NULL)
145 mrp_debug("notifying process watch %p", w);
148 args[1].pointer = event_create(L, e);
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);
157 static void event_cb(mrp_proc_watch_t *pw, mrp_proc_event_t *e, void *user_data)
159 process_watch_lua_t *w = (process_watch_lua_t *)user_data;
163 mrp_debug("got notification (0x%x) for process watch %p", e->type, w);
165 process_watch_notify(w, mrp_lua_get_lua_state(), e);
169 process_watch_lua_t *process_watch_create(sysmon_lua_t *sm, lua_State *L)
171 process_watch_lua_t *w;
173 mrp_proc_filter_t *f;
176 luaL_checktype(L, 2, LUA_TTABLE);
178 w = (process_watch_lua_t *)mrp_lua_create_object(L, PROCESS_WATCH_LUA_CLASS,
181 mrp_list_init(&w->hook);
183 w->watchref = LUA_NOREF;
184 w->filterref = LUA_NOREF;
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>");
194 if (w->notify == NULL) {
195 luaL_error(L, "process watch notification callback not set");
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)
205 ctx = mrp_lua_get_murphy_context();
206 w->w = mrp_add_proc_watch(ctx->ml, w->mask, f, event_cb, w);
211 luaL_error(L, "failed to create process watch");
217 static void process_watch_destroy(void *data)
219 mrp_debug("process watch %p destroyed", data);
223 static int process_watch_delete(lua_State *L)
225 process_watch_lua_t *w = process_watch_lua_check(L, 1);
227 mrp_lua_object_unref_value(w, L, w->filterref);
228 w->filterref = LUA_NOREF;
230 mrp_del_proc_watch(w->w);
231 sysmon_del_process_watch(w->sysmon, w);
237 static void process_watch_changed(void *data, lua_State *L, int member)
245 static int process_watch_setmember(void *data, lua_State *L, int member,
248 process_watch_lua_t *w = (process_watch_lua_t *)data;
251 case PROCESS_WATCH_MEMBER_EVENTS:
255 case PROCESS_WATCH_MEMBER_FILTER:
256 if (v->any != LUA_NOREF)
257 return setup_filter(w, L, v->any);
261 case PROCESS_WATCH_MEMBER_NOTIFY:
262 if (!mrp_lua_object_deref_value(w, L, v->any, false))
264 switch (lua_type(L, -1)) {
266 w->notify = mrp_funcbridge_create_luafunc(L, -1);
273 mrp_lua_object_unref_value(w, L, v->any);
275 return (w->notify != NULL ? 1 : 0);
278 mrp_log_error("Can't set read-only process watch member #%d.", member);
284 static int process_watch_getmember(void *data, lua_State *L, int member,
287 process_watch_lua_t *w = (process_watch_lua_t *)data;
293 case PROCESS_WATCH_MEMBER_EVENTS:
297 case PROCESS_WATCH_MEMBER_FILTER:
298 v->any = w->filterref;
308 static ssize_t process_watch_tostring(mrp_lua_tostr_mode_t mode, char *buf,
309 size_t size, lua_State *L, void *data)
311 process_watch_lua_t *w = (process_watch_lua_t *)data;
315 switch (mode & MRP_LUA_TOSTR_MODEMASK) {
316 case MRP_LUA_TOSTR_LUA:
318 return snprintf(buf, size, "{process watch %p}", w);
323 int process_event_mask(lua_State *L, int idx)
325 mrp_proc_event_type_t mask;
326 const char *event, *name;
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);
337 event = lua_tolstring(L, -1, &len);
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;
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;
371 if (!strcmp(event, "trace"))
372 mask |= MRP_PROC_EVENT_PTRACE;
373 else if (!strcmp(event, "group"))
374 mask |= MRP_PROC_EVENT_GID;
380 if (!strcmp(event, "ptrace"))
381 mask |= MRP_PROC_EVENT_PTRACE;
387 if (!strcmp(event, "session"))
388 mask |= MRP_PROC_EVENT_SID;
389 else if (!strcmp(event, "recurse"))
390 mask |= MRP_PROC_RECURSE;
396 if (!strcmp(event, "coredump"))
397 mask |= MRP_PROC_EVENT_COREDUMP;
403 if (!strcmp(event, "nothreads"))
404 mask |= MRP_PROC_IGNORE_THREADS;
410 if (!strcmp(event, "ignorethreads"))
411 mask |= MRP_PROC_IGNORE_THREADS;
418 mrp_log_warning("ignoring unknown process event '%s'", event);
423 lua_pushinteger(L, mask);
428 static int setup_filter(process_watch_lua_t *w, lua_State *L, int filterref)
430 int top = lua_gettop(L);
432 const char *kname, *usr, *grp;
435 if (!mrp_lua_object_deref_value(w, L, filterref, false)) {
436 mrp_log_error("Failed to dereference process watch filter table.");
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).");
446 kname = lua_tolstring(L, -2, &len);
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.");
454 w->filter.pid = lua_tointeger(L, -1);
458 if (!strcmp(kname, "path")) {
459 if (lua_type(L, -1) != LUA_TSTRING) {
460 mrp_log_error("Invalid process watch filter path.");
464 w->filter.path = mrp_strdup(lua_tostring(L, -1));
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.");
474 w->filter.comm = mrp_strdup(lua_tostring(L, -1));
478 if (!strcmp(kname, "uid") || !strcmp(kname, "user")) {
479 if (lua_type(L, -1) == LUA_TNUMBER) {
480 w->filter.uid = lua_tointeger(L, -1);
484 if (lua_type(L, -1) == LUA_TSTRING) {
485 struct passwd *pw = getpwnam(usr = lua_tolstring(L, -1, &len));
488 mrp_log_error("Unknown process watch filter user '%s'.",
493 w->filter.uid = pw->pw_uid;
497 mrp_log_error("Invalid process watch filter user.");
501 if (!strcmp(kname, "gid") || !strcmp(kname, "group")) {
502 if (lua_type(L, -1) == LUA_TNUMBER) {
503 w->filter.gid = lua_tointeger(L, -1);
507 if (lua_type(L, -1) == LUA_TSTRING) {
508 struct group *gr = getgrnam(grp = lua_tolstring(L, -1, &len));
511 mrp_log_error("Unknown process watch filter group '%s'.",
516 w->filter.gid = gr->gr_gid;
520 mrp_log_error("Invalid process watch filter group.");
524 mrp_log_error("Invalid process watch filter field '%s'.", kname);
528 w->filterref = mrp_lua_object_ref_value(w, L, top + 1);
539 static bool register_event_class(lua_State *L)
541 mrp_lua_create_object_class(L, PROCESS_EVENT_CLASS);
547 static int event_no_constructor(lua_State *L)
549 return luaL_error(L, "trying to create a process event via constructor.");
553 static void *event_create(lua_State *L, mrp_proc_event_t *event)
555 static bool eclass = false;
556 process_event_lua_t *e;
559 if (!(eclass = register_event_class(L)))
562 e = (process_event_lua_t *)mrp_lua_create_object(L, PROCESS_EVENT_CLASS,
565 if (e == NULL || (e->event = mrp_allocz(sizeof(*e->event))) == NULL) {
566 mrp_log_error("Failed to allocate process event.");
570 memcpy(e->event, event, sizeof(*e->event));
576 static int event_setfield(lua_State *L)
579 return luaL_error(L, "trying to set field on read-only process event");
583 static int event_getfield(lua_State *L)
585 process_event_lua_t *e = event_check(L, -2);
586 const char *name, *type;;
588 if (lua_type(L, -1) != LUA_TSTRING)
589 return luaL_error(L, "process event has only string fields");
591 if (e->event == NULL) {
596 name = lua_tostring(L, -1);
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;
613 lua_pushstring(L, type);
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);
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);
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);
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);
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);
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);
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);
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);
700 static void event_destroy(void *data)
702 process_event_lua_t *e = (process_event_lua_t *)data;
708 static process_event_lua_t *event_check(lua_State *L, int idx)
710 return (process_event_lua_t *)
711 mrp_lua_check_object(L, PROCESS_EVENT_CLASS, idx);