diff options
Diffstat (limited to 'src/lua/lua_util.c')
-rw-r--r-- | src/lua/lua_util.c | 275 |
1 files changed, 250 insertions, 25 deletions
diff --git a/src/lua/lua_util.c b/src/lua/lua_util.c index ce4d9f67c..f2e9b8fa9 100644 --- a/src/lua/lua_util.c +++ b/src/lua/lua_util.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 Vsevolod Stakhov + * Copyright 2025 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,12 +23,21 @@ #include "lua_parsers.h" -#ifdef WITH_LUA_REPL -#include "replxx.h" -#endif +#include "replxx.h" #include <math.h> #include <glob.h> +#include <sys/types.h> +#include <sys/time.h> +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +#include <sys/sysctl.h> +#ifdef __FreeBSD__ +#include <sys/user.h> +#endif +#endif +#ifdef __APPLE__ +#include <mach/mach.h> +#endif #include "unicode/uspoof.h" #include "unicode/uscript.h" @@ -629,6 +638,27 @@ LUA_FUNCTION_DEF(util, caseless_hash_fast); LUA_FUNCTION_DEF(util, get_hostname); /*** + * @function util.get_uptime() + * Returns system uptime in seconds + * @return {number} uptime in seconds + */ +LUA_FUNCTION_DEF(util, get_uptime); + +/*** + * @function util.get_pid() + * Returns current process PID + * @return {number} process ID + */ +LUA_FUNCTION_DEF(util, get_pid); + +/*** + * @function util.get_memory_usage() + * Returns memory usage information for current process + * @return {table} memory usage info with 'rss' and 'vsize' fields in bytes + */ +LUA_FUNCTION_DEF(util, get_memory_usage); + +/*** * @function util.parse_content_type(ct_string, mempool) * Parses content-type string to a table: * - `type` @@ -730,6 +760,9 @@ static const struct luaL_reg utillib_f[] = { LUA_INTERFACE_DEF(util, umask), LUA_INTERFACE_DEF(util, isatty), LUA_INTERFACE_DEF(util, get_hostname), + LUA_INTERFACE_DEF(util, get_uptime), + LUA_INTERFACE_DEF(util, get_pid), + LUA_INTERFACE_DEF(util, get_memory_usage), LUA_INTERFACE_DEF(util, parse_content_type), LUA_INTERFACE_DEF(util, mime_header_encode), LUA_INTERFACE_DEF(util, pack), @@ -755,9 +788,17 @@ static const struct luaL_reg int64lib_m[] = { {NULL, NULL}}; LUA_FUNCTION_DEF(ev_base, loop); +LUA_FUNCTION_DEF(ev_base, update_time); +LUA_FUNCTION_DEF(ev_base, timestamp); +LUA_FUNCTION_DEF(ev_base, pending_events); +LUA_FUNCTION_DEF(ev_base, add_timer); static const struct luaL_reg ev_baselib_m[] = { LUA_INTERFACE_DEF(ev_base, loop), + LUA_INTERFACE_DEF(ev_base, update_time), + LUA_INTERFACE_DEF(ev_base, timestamp), + LUA_INTERFACE_DEF(ev_base, pending_events), + LUA_INTERFACE_DEF(ev_base, add_timer), {"__tostring", rspamd_lua_class_tostring}, {NULL, NULL}}; @@ -2408,6 +2449,107 @@ lua_util_get_hostname(lua_State *L) } static int +lua_util_get_uptime(lua_State *L) +{ + LUA_TRACE_POINT; + double uptime = 0.0; + +#ifdef __linux__ + FILE *f = fopen("/proc/uptime", "r"); + if (f) { + if (fscanf(f, "%lf", &uptime) != 1) { + uptime = 0.0; + } + fclose(f); + } +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct timeval boottime; + size_t len = sizeof(boottime); + int mib[2] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(mib, 2, &boottime, &len, NULL, 0) == 0) { + struct timeval now; + gettimeofday(&now, NULL); + uptime = (now.tv_sec - boottime.tv_sec) + + (now.tv_usec - boottime.tv_usec) / 1000000.0; + } +#endif + + lua_pushnumber(L, uptime); + return 1; +} + +static int +lua_util_get_pid(lua_State *L) +{ + LUA_TRACE_POINT; + lua_pushinteger(L, getpid()); + return 1; +} + +static int +lua_util_get_memory_usage(lua_State *L) +{ + LUA_TRACE_POINT; + lua_createtable(L, 0, 2); + +#ifdef __linux__ + FILE *f = fopen("/proc/self/status", "r"); + if (f) { + char line[256]; + long rss = 0, vsize = 0; + + while (fgets(line, sizeof(line), f)) { + if (sscanf(line, "VmRSS: %ld kB", &rss) == 1) { + rss *= 1024; /* Convert to bytes */ + } + else if (sscanf(line, "VmSize: %ld kB", &vsize) == 1) { + vsize *= 1024; /* Convert to bytes */ + } + } + fclose(f); + + lua_pushstring(L, "rss"); + lua_pushinteger(L, rss); + lua_settable(L, -3); + + lua_pushstring(L, "vsize"); + lua_pushinteger(L, vsize); + lua_settable(L, -3); + } +#elif defined(__APPLE__) + struct task_basic_info info; + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; + + if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t) &info, &count) == KERN_SUCCESS) { + lua_pushstring(L, "rss"); + lua_pushinteger(L, info.resident_size); + lua_settable(L, -3); + + lua_pushstring(L, "vsize"); + lua_pushinteger(L, info.virtual_size); + lua_settable(L, -3); + } +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct kinfo_proc kp; + size_t len = sizeof(kp); + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()}; + + if (sysctl(mib, 4, &kp, &len, NULL, 0) == 0) { + lua_pushstring(L, "rss"); + lua_pushinteger(L, kp.ki_rssize * getpagesize()); + lua_settable(L, -3); + + lua_pushstring(L, "vsize"); + lua_pushinteger(L, kp.ki_size); + lua_settable(L, -3); + } +#endif + + return 1; +} + +static int lua_util_parse_content_type(lua_State *L) { return lua_parsers_parse_content_type(L); @@ -2502,7 +2644,7 @@ lua_util_readline(lua_State *L) if (lua_type(L, 1) == LUA_TSTRING) { prompt = lua_tostring(L, 1); } -#ifdef WITH_LUA_REPL + static Replxx *rx_instance = NULL; if (rx_instance == NULL) { @@ -2519,26 +2661,6 @@ lua_util_readline(lua_State *L) else { lua_pushnil(L); } -#else - size_t linecap = 0; - ssize_t linelen; - - fprintf(stdout, "%s ", prompt); - - linelen = getline(&input, &linecap, stdin); - - if (linelen > 0) { - if (input[linelen - 1] == '\n') { - linelen--; - } - - lua_pushlstring(L, input, linelen); - free(input); - } - else { - lua_pushnil(L); - } -#endif return 1; } @@ -3611,3 +3733,106 @@ lua_ev_base_loop(lua_State *L) return 1; } + +static int +lua_ev_base_update_time(lua_State *L) +{ + struct ev_loop *ev_base; + + ev_base = lua_check_ev_base(L, 1); + ev_now_update_if_cheap(ev_base); + + lua_pushnumber(L, ev_time()); + + return 1; +} + +static int +lua_ev_base_timestamp(lua_State *L) +{ + struct ev_loop *ev_base; + + ev_base = lua_check_ev_base(L, 1); + lua_pushnumber(L, ev_now(ev_base)); + + return 1; +} + +static int +lua_ev_base_pending_events(lua_State *L) +{ + struct ev_loop *ev_base; + + ev_base = lua_check_ev_base(L, 1); + lua_pushnumber(L, ev_pending_count(ev_base)); + + return 1; +} + +struct rspamd_ev_base_cbdata { + lua_State *L; + int cbref; + ev_timer ev; +}; + +static void +lua_ev_base_cb(struct ev_loop *loop, struct ev_timer *t, int events) +{ + struct rspamd_ev_base_cbdata *cbdata = (struct rspamd_ev_base_cbdata *) t->data; + lua_State *L; + bool schedule_more = false; + + L = cbdata->L; + + lua_pushcfunction(L, &rspamd_lua_traceback); + int err_idx = lua_gettop(L); + lua_rawgeti(L, LUA_REGISTRYINDEX, cbdata->cbref); + + if (lua_pcall(L, 0, 1, err_idx) != 0) { + msg_err("call to periodic " + "script failed: %s", + lua_tostring(L, -1)); + } + else { + if (lua_isnumber(L, -1)) { + schedule_more = true; + ev_timer_set(&cbdata->ev, lua_tonumber(L, -1), 0.0); + } + } + + if (schedule_more) { + ev_timer_again(loop, t); + } + else { + /* Cleanup */ + ev_timer_stop(loop, t); + luaL_unref(L, LUA_REGISTRYINDEX, cbdata->cbref); + g_free(cbdata); + } +} + +static int +lua_ev_base_add_timer(lua_State *L) +{ + struct ev_loop *ev_base; + + ev_base = lua_check_ev_base(L, 1); + if (!lua_isfunction(L, 3)) { + return luaL_error(L, "invalid arguments: callback expected"); + } + + if (!lua_isnumber(L, 2)) { + return luaL_error(L, "invalid arguments: timeout expected"); + } + + struct rspamd_ev_base_cbdata *cbdata = g_malloc(sizeof(*cbdata)); + cbdata->L = L; + lua_pushvalue(L, 3); + cbdata->ev.data = cbdata; + cbdata->cbref = luaL_ref(L, LUA_REGISTRYINDEX); + + ev_timer_init(&cbdata->ev, lua_ev_base_cb, lua_tonumber(L, 2), 0.0); + ev_timer_start(ev_base, &cbdata->ev); + + return 0; +} |