From fded373d990ee9fbb6f1d03a8052437ae701336f Mon Sep 17 00:00:00 2001 From: Egor Date: Thu, 12 Feb 2026 02:42:47 +0200 Subject: [PATCH] admin: move command/hook dispatch to lua --- lua/init.lua | 23 +++++++++++++++++++++ src/admin.cpp | 57 ++++++++------------------------------------------- src/main.cpp | 10 +++++++++ 3 files changed, 42 insertions(+), 48 deletions(-) diff --git a/lua/init.lua b/lua/init.lua index 66da1ca..252be05 100644 --- a/lua/init.lua +++ b/lua/init.lua @@ -1,11 +1,34 @@ -- Copyright (c) 2023-2026 Egor -- SPDX-License-Identifier: GPL-2.0-or-later +if not commands then + commands = {} +end +function dispatch_command(client, source, command, ...) + if client.regstate ~= 2 then -- REG_REGISTERED + -- TODO: err_notregistered(), sendbuf(client) + return + end + if client.umode & 2 == 0 then -- UMODE_OPER + -- TODO: err_noprivileges(), sendbuf(client) + return + end + commands[command](client, source, command, table.pack(...)) +end +function commands.eval(client, source, command, args) + assert(load(args[1], args[1], "t"))() +end function commands.reload(client, source, command, args) client_notice(client, "reloading...") dofile(getluafile "init.lua") client_notice(client, "done") end setmetatable(_G, getmetatable(ircd)) +if not hooks then + hooks = {} +end +function dispatch_hook(hook, cl1, cl2, chan, txt) + return hooks[hook](hook, cl1, cl2, chan, txt) +end if not managed_hooks then managed_hooks = {} end diff --git a/src/admin.cpp b/src/admin.cpp index 1a9acb2..bf47c3d 100644 --- a/src/admin.cpp +++ b/src/admin.cpp @@ -274,15 +274,6 @@ static int globals_index(lua_State *L) return push(L, dyingclients), 1; return 0; } -static int command_eval(lua_State *L) -{ - luaL_checktype(L, 4, LUA_TTABLE); - lua_geti(L, 4, 1); - if (LUA_OK != luaL_dostring(L, lua_tostring(L, -1))) { - fprintf(stderr, "%s\n", lua_tostring(L, -1)); - } - return 0; -} static int fn_client_privmsg(lua_State *L) { Client *cl = ClientRef::check(L, 1); @@ -473,12 +464,6 @@ void admin_init(void) lua_newuserdatauv(L, 0, 0); luaL_setmetatable(L, "globals"); lua_setglobal(L, "ircd"); - lua_newtable(L); - lua_pushcfunction(L, command_eval); - lua_setfield(L, -2, "eval"); - lua_setglobal(L, "commands"); - lua_newtable(L); - lua_setglobal(L, "hooks"); { luaL_Reg funcs[] = { {"client_privmsg", fn_client_privmsg}, @@ -519,35 +504,20 @@ void admin_dostring(const char *command) } bool admin_command(Client *client, char *source, char *command, int argc, char *args[]) { - if (!is_registered(client)) - return err_notregistered(), sendbuf(client), false; - if (!(client->umode & UMODE_OPER)) - return err_noprivileges(client), sendbuf(client), false; lua_State *L = GL; - if (lua_getglobal(L, "commands") != LUA_TTABLE) { - fprintf(stderr, "no command table\n"); - lua_pop(L, 1); - return false; - } - lua_getfield(L, -1, command); - lua_remove(L, -2); - if (!lua_isfunction(L, -1)) { - fprintf(stderr, "command not found: %s\n", command); - lua_pop(L, 1); - return false; - } + lua_getglobal(L, "dispatch_command"); push(L, client); lua_pushstring(L, source); lua_pushstring(L, command); - lua_createtable(L, argc, 1); - for (int i = 0; i < argc; i++) { - lua_pushstring(L, args[i]); - lua_seti(L, -2, i+1); + if (!lua_checkstack(L, argc)) { + fprintf(stderr, "no lua stack space\n"); + lua_settop(L, 0); + return false; } - lua_pushinteger(L, argc); - lua_setfield(L, -2, "n"); - if (LUA_OK != lua_pcall(L, 4, 0, 0)) { + for (int i = 0; i < argc; i++) + lua_pushstring(L, args[i]); + if (LUA_OK != lua_pcall(L, 3+argc, 0, 0)) { fprintf(stderr, "%s\n", lua_tostring(L, -1)); lua_pop(L, 1); } @@ -556,16 +526,7 @@ bool admin_command(Client *client, char *source, char *command, int argc, char * int admin_hook(const char *hook, Client *cl1, Client *cl2, Channel *chan, char *txt) { lua_State *L = GL; - if (lua_getglobal(L, "hooks") != LUA_TTABLE) { - lua_pop(L, 1); - return 0; - } - lua_getfield(L, -1, hook); - lua_remove(L, -2); - if (!lua_isfunction(L, -1)) { - lua_pop(L, 1); - return 0; - } + lua_getglobal(L, "dispatch_hook"); lua_pushstring(L, hook); cl1 ? push(L, cl1) : lua_pushnil(L); cl2 ? push(L, cl2) : lua_pushnil(L); diff --git a/src/main.cpp b/src/main.cpp index 05a3e58..b15288e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -292,6 +292,16 @@ int main(int argc, char *argv[]) netpoll::reg(listener.fd, UV_READABLE); } + // make eval work even if the rest of the runtime is missing + admin_dostring(R"( + function dispatch_command(client, source, command, ...) + -- UMODE_OPER + if client.umode & 2 ~= 0 and command == "eval" then + local s = table.pack(...)[1] + assert(load(s, s, "t"))() + end + end + )"); admin_dostring("dofile(getluafile'init.lua')"); fchanlog = fopen(getdatafile("chanlog.txt"), "abe"); -- 2.56.0