aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKim Alvefur <zash@zash.se>2024-03-23 20:48:19 +0100
committerKim Alvefur <zash@zash.se>2024-03-23 20:48:19 +0100
commitc2c82a10d3839afe8f74a29588723096c08ac1f8 (patch)
treea68523ab3395c2ec230a096c49366283700476c8
parent2bc341d8b10b37a949e5108f45286857891e77e9 (diff)
downloadprosody-c2c82a10d3839afe8f74a29588723096c08ac1f8.tar.gz
prosody-c2c82a10d3839afe8f74a29588723096c08ac1f8.zip
mod_posix: Move everything to util.startup
This allows greater control over the order of events. Notably, the internal ordering between daemonization, initialization of libunbound and setup of signal handling is sensitive. libunbound starts a separate thread for processing DNS requests. If this thread is started before signal handling has been set up, it will not inherit the signal handlers and instead behave as it would have before signal handlers were set up, i.e. cause the whole process to immediately exit. libunbound is usually initialized on the first DNS request, usually triggered by an outgoing s2s connection attempt. If daemonization happens before signals have been set up, signals may not be processed at all.
-rw-r--r--plugins/mod_posix.lua113
-rw-r--r--util/startup.lua117
2 files changed, 109 insertions, 121 deletions
diff --git a/plugins/mod_posix.lua b/plugins/mod_posix.lua
index 383769a2..101e6e62 100644
--- a/plugins/mod_posix.lua
+++ b/plugins/mod_posix.lua
@@ -6,117 +6,6 @@
-- COPYING file in the source package for more information.
--
-
-local want_pposix_version = "0.4.0";
-
-local pposix = assert(require "prosody.util.pposix");
-if pposix._VERSION ~= want_pposix_version then
- module:log("warn", "Unknown version (%s) of binary pposix module, expected %s."
- .. "Perhaps you need to recompile?", tostring(pposix._VERSION), want_pposix_version);
-end
-
-
-local lfs = require "lfs";
-local stat = lfs.attributes;
-
-local prosody = _G.prosody;
-
module:set_global(); -- we're a global module
-local umask = module:get_option_string("umask", "027");
-pposix.umask(umask);
-
--- Don't even think about it!
-if not prosody.start_time then -- server-starting
- if pposix.getuid() == 0 and not module:get_option_boolean("run_as_root") then
- module:log("error", "Danger, Will Robinson! Prosody doesn't need to be run as root, so don't do it!");
- module:log("error", "For more information on running Prosody as root, see https://prosody.im/doc/root");
- prosody.shutdown("Refusing to run as root", 1);
- end
-end
-
-local pidfile;
-local pidfile_handle;
-
-local function remove_pidfile()
- if pidfile_handle then
- pidfile_handle:close();
- os.remove(pidfile);
- pidfile, pidfile_handle = nil, nil;
- end
-end
-
-local function write_pidfile()
- if pidfile_handle then
- remove_pidfile();
- end
- pidfile = module:get_option_path("pidfile", nil, "data");
- if pidfile then
- local err;
- local mode = stat(pidfile) and "r+" or "w+";
- pidfile_handle, err = io.open(pidfile, mode);
- if not pidfile_handle then
- module:log("error", "Couldn't write pidfile at %s; %s", pidfile, err);
- prosody.shutdown("Couldn't write pidfile", 1);
- else
- if not lfs.lock(pidfile_handle, "w") then -- Exclusive lock
- local other_pid = pidfile_handle:read("*a");
- module:log("error", "Another Prosody instance seems to be running with PID %s, quitting", other_pid);
- pidfile_handle = nil;
- prosody.shutdown("Prosody already running", 1);
- else
- pidfile_handle:close();
- pidfile_handle, err = io.open(pidfile, "w+");
- if not pidfile_handle then
- module:log("error", "Couldn't write pidfile at %s; %s", pidfile, err);
- prosody.shutdown("Couldn't write pidfile", 1);
- else
- if lfs.lock(pidfile_handle, "w") then
- pidfile_handle:write(tostring(pposix.getpid()));
- pidfile_handle:flush();
- end
- end
- end
- end
- end
-end
-
-local daemonize = prosody.opts.daemonize;
-
-if daemonize == nil then
- -- Fall back to config file if not specified on command-line
- daemonize = module:get_option_boolean("daemonize", nil);
- if daemonize ~= nil then
- module:log("warn", "The 'daemonize' option has been deprecated, specify -D or -F on the command line instead.");
- -- TODO: Write some docs and include a link in the warning.
- end
-end
-
-local function remove_log_sinks()
- local lm = require "prosody.core.loggingmanager";
- lm.register_sink_type("console", nil);
- lm.register_sink_type("stdout", nil);
- lm.reload_logging();
-end
-
-if daemonize then
- local function daemonize_server()
- module:log("info", "Prosody is about to detach from the console, disabling further console output");
- remove_log_sinks();
- local ok, ret = pposix.daemonize();
- if not ok then
- module:log("error", "Failed to daemonize: %s", ret);
- elseif ret and ret > 0 then
- os.exit(0);
- else
- module:log("info", "Successfully daemonized to PID %d", pposix.getpid());
- write_pidfile();
- end
- end
- module:hook("server-started", daemonize_server)
-else
- -- Not going to daemonize, so write the pid of this process
- write_pidfile();
-end
-
-module:hook("server-stopped", remove_pidfile);
+-- TODO delete this whole concept
diff --git a/util/startup.lua b/util/startup.lua
index 92bf2987..3ec3f375 100644
--- a/util/startup.lua
+++ b/util/startup.lua
@@ -531,21 +531,30 @@ function startup.force_console_logging()
config.set("*", "log", { { levels = { min = log_level or "info" }, to = "console" } });
end
+local function check_posix()
+ if prosody.platform ~= "posix" then return end
+
+ local want_pposix_version = "0.4.0";
+ local have_pposix, pposix = pcall(require, "prosody.util.pposix");
+
+ if pposix._VERSION ~= want_pposix_version then
+ print(string.format("Unknown version (%s) of binary pposix module, expected %s",
+ tostring(pposix._VERSION), want_pposix_version));
+ os.exit(1);
+ end
+ if have_pposix and pposix then
+ return pposix;
+ end
+end
+
function startup.switch_user()
-- Switch away from root and into the prosody user --
-- NOTE: This function is only used by prosodyctl.
-- The prosody process is built with the assumption that
-- it is already started as the appropriate user.
- local want_pposix_version = "0.4.0";
- local have_pposix, pposix = pcall(require, "prosody.util.pposix");
-
- if have_pposix and pposix then
- if pposix._VERSION ~= want_pposix_version then
- print(string.format("Unknown version (%s) of binary pposix module, expected %s",
- tostring(pposix._VERSION), want_pposix_version));
- os.exit(1);
- end
+ local pposix = check_posix()
+ if pposix then
prosody.current_uid = pposix.getuid();
local arg_root = prosody.opts.root;
if prosody.current_uid == 0 and config.get("*", "run_as_root") ~= true and not arg_root then
@@ -671,6 +680,93 @@ function startup.make_dummy_hosts()
end
end
+function startup.posix_umask()
+ if prosody.platform ~= "posix" then return end
+ local pposix = require "prosody.util.pposix";
+ local umask = config.get("*", "umask") or "027";
+ pposix.umask(umask);
+end
+
+function startup.check_user()
+ local pposix = check_posix();
+ if not pposix then return end
+ -- Don't even think about it!
+ if pposix.getuid() == 0 and not config.get("*", "run_as_root") then
+ log("error", "Danger, Will Robinson! Prosody doesn't need to be run as root, so don't do it!");
+ log("error", "For more information on running Prosody as root, see https://prosody.im/doc/root");
+ prosody.shutdown("Refusing to run as root", 1);
+ end
+end
+
+local function remove_pidfile()
+ local pidfile = prosody.pidfile;
+ if prosody.pidfile_handle then
+ prosody.pidfile_handle:close();
+ os.remove(pidfile);
+ prosody.pidfile, prosody.pidfile_handle = nil, nil;
+ end
+end
+
+function startup.write_pidfile()
+ local pposix = check_posix();
+ if not pposix then return end
+ local lfs = require "lfs";
+ local stat = lfs.attributes;
+ local pidfile = config.get("*", "pidfile") or nil;
+ if not pidfile then return end
+ pidfile = config.resolve_relative_path(prosody.paths.data, pidfile);
+ local mode = stat(pidfile) and "r+" or "w+";
+ local pidfile_handle, err = io.open(pidfile, mode);
+ if not pidfile_handle then
+ log("error", "Couldn't write pidfile at %s; %s", pidfile, err);
+ prosody.shutdown("Couldn't write pidfile", 1);
+ else
+ prosody.pidfile = pidfile;
+ if not lfs.lock(pidfile_handle, "w") then -- Exclusive lock
+ local other_pid = pidfile_handle:read("*a");
+ log("error", "Another Prosody instance seems to be running with PID %s, quitting", other_pid);
+ prosody.pidfile_handle = nil;
+ prosody.shutdown("Prosody already running", 1);
+ else
+ pidfile_handle:close();
+ pidfile_handle, err = io.open(pidfile, "w+");
+ if not pidfile_handle then
+ log("error", "Couldn't write pidfile at %s; %s", pidfile, err);
+ prosody.shutdown("Couldn't write pidfile", 1);
+ else
+ if lfs.lock(pidfile_handle, "w") then
+ pidfile_handle:write(tostring(pposix.getpid()));
+ pidfile_handle:flush();
+ prosody.pidfile_handle = pidfile_handle;
+ end
+ end
+ end
+ end
+ prosody.events.add_handler("server-stopped", remove_pidfile);
+end
+
+local function remove_log_sinks()
+ local lm = require "prosody.core.loggingmanager";
+ lm.register_sink_type("console", nil);
+ lm.register_sink_type("stdout", nil);
+ lm.reload_logging();
+end
+
+function startup.posix_daemonize()
+ if not prosody.opts.daemonize then return end
+ local pposix = check_posix();
+ log("info", "Prosody is about to detach from the console, disabling further console output");
+ remove_log_sinks();
+ local ok, ret = pposix.daemonize();
+ if not ok then
+ log("error", "Failed to daemonize: %s", ret);
+ elseif ret and ret > 0 then
+ os.exit(0);
+ else
+ log("info", "Successfully daemonized to PID %d", pposix.getpid());
+ end
+end
+
function startup.hook_posix_signals()
if prosody.platform ~= "posix" then return end
local have_signal, signal = pcall(require, "prosody.util.signal");
@@ -765,6 +861,7 @@ function startup.prosody()
-- These actions are in a strict order, as many depend on
-- previous steps to have already been performed
prosody.process_type = "prosody";
+ startup.check_user();
startup.parse_args();
startup.init_global_state();
startup.read_config();
@@ -790,6 +887,8 @@ function startup.prosody()
startup.init_http_client();
startup.init_data_store();
startup.init_global_protection();
+ startup.posix_daemonize();
+ startup.write_pidfile();
startup.hook_posix_signals();
startup.prepare_to_start();
startup.notify_started();