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);
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,
334 ktype == LUA_TNUMBER ? type : 0);
338 event = lua_tolstring(L, -1, &len);
342 if (!strcmp(event, "uid"))
343 mask |= MRP_PROC_EVENT_UID;
344 else if (!strcmp(event, "gid"))
345 mask |= MRP_PROC_EVENT_GID;
346 else if (!strcmp(event, "sid"))
347 mask |= MRP_PROC_EVENT_SID;
353 if (!strcmp(event, "none"))
354 mask |= MRP_PROC_EVENT_NONE;
355 else if (!strcmp(event, "fork"))
356 mask |= MRP_PROC_EVENT_FORK;
357 else if (!strcmp(event, "exec"))
358 mask |= MRP_PROC_EVENT_EXEC;
359 else if (!strcmp(event, "exit"))
360 mask |= MRP_PROC_EVENT_EXIT;
361 else if (!strcmp(event, "user"))
362 mask |= MRP_PROC_EVENT_UID;
363 else if (!strcmp(event, "comm"))
364 mask |= MRP_PROC_EVENT_COMM;
365 else if (!strcmp(event, "core"))
366 mask |= MRP_PROC_EVENT_COREDUMP;
372 if (!strcmp(event, "trace"))
373 mask |= MRP_PROC_EVENT_PTRACE;
374 else if (!strcmp(event, "group"))
375 mask |= MRP_PROC_EVENT_GID;
381 if (!strcmp(event, "ptrace"))
382 mask |= MRP_PROC_EVENT_PTRACE;
388 if (!strcmp(event, "session"))
389 mask |= MRP_PROC_EVENT_SID;
390 else if (!strcmp(event, "recurse"))
391 mask |= MRP_PROC_RECURSE;
397 if (!strcmp(event, "coredump"))
398 mask |= MRP_PROC_EVENT_COREDUMP;
404 if (!strcmp(event, "nothreads"))
405 mask |= MRP_PROC_IGNORE_THREADS;
411 if (!strcmp(event, "ignorethreads"))
412 mask |= MRP_PROC_IGNORE_THREADS;
419 mrp_log_warning("ignoring unknown process event '%s'", event);
424 lua_pushinteger(L, mask);
429 static int setup_filter(process_watch_lua_t *w, lua_State *L, int filterref)
431 int top = lua_gettop(L);
433 const char *kname, *usr, *grp;
436 if (!mrp_lua_object_deref_value(w, L, filterref, false)) {
437 mrp_log_error("Failed to dereference process watch filter table.");
441 MRP_LUA_FOREACH_ALL(L, i, top + 1, ktype, kname, klen) {
442 if (ktype != LUA_TSTRING) {
443 mrp_log_error("Invalid process watch filter (non-string key).");
447 kname = lua_tolstring(L, -2, &len);
449 if (!strcmp(kname, "pid") || !strcmp(kname, "process")) {
450 if (lua_type(L, -1) != LUA_TNUMBER) {
451 mrp_log_error("Invalid process watch filter pid.");
455 w->filter.pid = lua_tointeger(L, -1);
459 if (!strcmp(kname, "path")) {
460 if (lua_type(L, -1) != LUA_TSTRING) {
461 mrp_log_error("Invalid process watch filter path.");
465 w->filter.path = mrp_strdup(lua_tostring(L, -1));
469 if (!strcmp(kname, "comm") || !strcmp(kname, "name")) {
470 if (lua_type(L, -1) != LUA_TSTRING) {
471 mrp_log_error("Invalid process watch filter comm.");
475 w->filter.comm = mrp_strdup(lua_tostring(L, -1));
479 if (!strcmp(kname, "uid") || !strcmp(kname, "user")) {
480 if (lua_type(L, -1) == LUA_TNUMBER) {
481 w->filter.uid = lua_tointeger(L, -1);
485 if (lua_type(L, -1) == LUA_TSTRING) {
486 struct passwd *pw = getpwnam(usr = lua_tolstring(L, -1, &len));
489 mrp_log_error("Unknown process watch filter user '%s'.",
494 w->filter.uid = pw->pw_uid;
498 mrp_log_error("Invalid process watch filter user.");
502 if (!strcmp(kname, "gid") || !strcmp(kname, "group")) {
503 if (lua_type(L, -1) == LUA_TNUMBER) {
504 w->filter.gid = lua_tointeger(L, -1);
508 if (lua_type(L, -1) == LUA_TSTRING) {
509 struct group *gr = getgrnam(grp = lua_tolstring(L, -1, &len));
512 mrp_log_error("Unknown process watch filter group '%s'.",
517 w->filter.gid = gr->gr_gid;
521 mrp_log_error("Invalid process watch filter group.");
525 mrp_log_error("Invalid process watch filter field '%s'.", kname);
529 w->filterref = mrp_lua_object_ref_value(w, L, top + 1);
540 static bool register_event_class(lua_State *L)
542 mrp_lua_create_object_class(L, PROCESS_EVENT_CLASS);
548 static int event_no_constructor(lua_State *L)
550 return luaL_error(L, "trying to create a process event via constructor.");
554 static void *event_create(lua_State *L, mrp_proc_event_t *event)
556 static bool eclass = false;
557 process_event_lua_t *e;
560 if (!(eclass = register_event_class(L)))
563 e = (process_event_lua_t *)mrp_lua_create_object(L, PROCESS_EVENT_CLASS,
566 if (e == NULL || (e->event = mrp_allocz(sizeof(*e->event))) == NULL) {
567 mrp_log_error("Failed to allocate process event.");
571 memcpy(e->event, event, sizeof(*e->event));
577 static int event_setfield(lua_State *L)
580 return luaL_error(L, "trying to set field on read-only process event");
584 static int event_getfield(lua_State *L)
586 process_event_lua_t *e = event_check(L, -2);
587 const char *name, *type;;
589 if (lua_type(L, -1) != LUA_TSTRING)
590 return luaL_error(L, "process event has only string fields");
592 if (e->event == NULL) {
597 name = lua_tostring(L, -1);
599 if (!strcmp(name, "type")) {
600 switch (e->event->type) {
601 case MRP_PROC_EVENT_NONE: type = "<none>" ; break;
602 case MRP_PROC_EVENT_FORK: type = "fork" ; break;
603 case MRP_PROC_EVENT_EXEC: type = "exec" ; break;
604 case MRP_PROC_EVENT_EXIT: type = "exit" ; break;
605 case MRP_PROC_EVENT_UID: type = "uid" ; break;
606 case MRP_PROC_EVENT_GID: type = "gid" ; break;
607 case MRP_PROC_EVENT_SID: type = "sid" ; break;
608 case MRP_PROC_EVENT_PTRACE: type = "ptrace" ; break;
609 case MRP_PROC_EVENT_COMM: type = "comm" ; break;
610 case MRP_PROC_EVENT_COREDUMP: type = "coredump" ; break;
611 default: type = "<unknown>"; break;
614 lua_pushstring(L, type);
618 if (!strcmp(name, "pid") || !strcmp(name, "process_pid")) {
619 if (e->event->type != MRP_PROC_EVENT_FORK)
620 lua_pushinteger(L, e->event->raw->event_data.exec.process_pid);
626 if (!strcmp(name, "tgid") || !strcmp(name, "process_tgid")) {
627 if (e->event->type != MRP_PROC_EVENT_FORK)
628 lua_pushinteger(L, e->event->raw->event_data.exec.process_tgid);
634 if (e->event->type == MRP_PROC_EVENT_FORK) {
635 if (!strcmp(name, "parent_pid"))
636 lua_pushinteger(L, e->event->raw->event_data.fork.parent_pid);
637 else if (!strcmp(name, "parent_tgid"))
638 lua_pushinteger(L, e->event->raw->event_data.fork.parent_tgid);
639 else if (!strcmp(name, "child_pid"))
640 lua_pushinteger(L, e->event->raw->event_data.fork.child_pid);
641 else if (!strcmp(name, "child_tgid"))
642 lua_pushinteger(L, e->event->raw->event_data.fork.child_tgid);
648 if (e->event->type == MRP_PROC_EVENT_UID) {
649 if (!strcmp(name, "ruid"))
650 lua_pushinteger(L, e->event->raw->event_data.id.r.ruid);
651 else if (!strcmp(name, "euid"))
652 lua_pushinteger(L, e->event->raw->event_data.id.e.euid);
658 if (e->event->type == MRP_PROC_EVENT_GID) {
659 if (!strcmp(name, "rgid"))
660 lua_pushinteger(L, e->event->raw->event_data.id.r.rgid);
661 else if (!strcmp(name, "egid"))
662 lua_pushinteger(L, e->event->raw->event_data.id.e.egid);
668 if (e->event->type == MRP_PROC_EVENT_PTRACE) {
669 if (!strcmp(name, "tracer_pid"))
670 lua_pushinteger(L, e->event->raw->event_data.ptrace.tracer_pid);
671 else if (!strcmp(name, "tracer_tgid"))
672 lua_pushinteger(L, e->event->raw->event_data.ptrace.tracer_tgid);
678 if (e->event->type == MRP_PROC_EVENT_COMM) {
679 if (!strcmp(name, "comm"))
680 lua_pushstring(L, e->event->raw->event_data.comm.comm);
686 if (e->event->type == MRP_PROC_EVENT_EXIT) {
687 if (!strcmp(name, "exit_code") || !strcmp(name, "code"))
688 lua_pushinteger(L, e->event->raw->event_data.exit.exit_code);
689 else if (!strcmp(name, "exit_signal") || !strcmp(name, "signal"))
690 lua_pushinteger(L, e->event->raw->event_data.exit.exit_signal);
701 static void event_destroy(void *data)
703 process_event_lua_t *e = (process_event_lua_t *)data;
709 static process_event_lua_t *event_check(lua_State *L, int idx)
711 return (process_event_lua_t *)
712 mrp_lua_check_object(L, PROCESS_EVENT_CLASS, idx);