Comparison

plugins/mod_posix.lua @ 13461:c673ff1075bd

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.
author Kim Alvefur <zash@zash.se>
date Sat, 23 Mar 2024 20:48:19 +0100
parent 13452:69faf3552d52
comparison
equal deleted inserted replaced
13460:a688947fab1e 13461:c673ff1075bd
4 -- 4 --
5 -- This project is MIT/X11 licensed. Please see the 5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information. 6 -- COPYING file in the source package for more information.
7 -- 7 --
8 8
9
10 local want_pposix_version = "0.4.0";
11
12 local pposix = assert(require "prosody.util.pposix");
13 if pposix._VERSION ~= want_pposix_version then
14 module:log("warn", "Unknown version (%s) of binary pposix module, expected %s."
15 .. "Perhaps you need to recompile?", tostring(pposix._VERSION), want_pposix_version);
16 end
17
18
19 local lfs = require "lfs";
20 local stat = lfs.attributes;
21
22 local prosody = _G.prosody;
23
24 module:set_global(); -- we're a global module 9 module:set_global(); -- we're a global module
25 10
26 local umask = module:get_option_string("umask", "027"); 11 -- TODO delete this whole concept
27 pposix.umask(umask);
28
29 -- Don't even think about it!
30 if not prosody.start_time then -- server-starting
31 if pposix.getuid() == 0 and not module:get_option_boolean("run_as_root") then
32 module:log("error", "Danger, Will Robinson! Prosody doesn't need to be run as root, so don't do it!");
33 module:log("error", "For more information on running Prosody as root, see https://prosody.im/doc/root");
34 prosody.shutdown("Refusing to run as root", 1);
35 end
36 end
37
38 local pidfile;
39 local pidfile_handle;
40
41 local function remove_pidfile()
42 if pidfile_handle then
43 pidfile_handle:close();
44 os.remove(pidfile);
45 pidfile, pidfile_handle = nil, nil;
46 end
47 end
48
49 local function write_pidfile()
50 if pidfile_handle then
51 remove_pidfile();
52 end
53 pidfile = module:get_option_path("pidfile", nil, "data");
54 if pidfile then
55 local err;
56 local mode = stat(pidfile) and "r+" or "w+";
57 pidfile_handle, err = io.open(pidfile, mode);
58 if not pidfile_handle then
59 module:log("error", "Couldn't write pidfile at %s; %s", pidfile, err);
60 prosody.shutdown("Couldn't write pidfile", 1);
61 else
62 if not lfs.lock(pidfile_handle, "w") then -- Exclusive lock
63 local other_pid = pidfile_handle:read("*a");
64 module:log("error", "Another Prosody instance seems to be running with PID %s, quitting", other_pid);
65 pidfile_handle = nil;
66 prosody.shutdown("Prosody already running", 1);
67 else
68 pidfile_handle:close();
69 pidfile_handle, err = io.open(pidfile, "w+");
70 if not pidfile_handle then
71 module:log("error", "Couldn't write pidfile at %s; %s", pidfile, err);
72 prosody.shutdown("Couldn't write pidfile", 1);
73 else
74 if lfs.lock(pidfile_handle, "w") then
75 pidfile_handle:write(tostring(pposix.getpid()));
76 pidfile_handle:flush();
77 end
78 end
79 end
80 end
81 end
82 end
83
84 local daemonize = prosody.opts.daemonize;
85
86 if daemonize == nil then
87 -- Fall back to config file if not specified on command-line
88 daemonize = module:get_option_boolean("daemonize", nil);
89 if daemonize ~= nil then
90 module:log("warn", "The 'daemonize' option has been deprecated, specify -D or -F on the command line instead.");
91 -- TODO: Write some docs and include a link in the warning.
92 end
93 end
94
95 local function remove_log_sinks()
96 local lm = require "prosody.core.loggingmanager";
97 lm.register_sink_type("console", nil);
98 lm.register_sink_type("stdout", nil);
99 lm.reload_logging();
100 end
101
102 if daemonize then
103 local function daemonize_server()
104 module:log("info", "Prosody is about to detach from the console, disabling further console output");
105 remove_log_sinks();
106 local ok, ret = pposix.daemonize();
107 if not ok then
108 module:log("error", "Failed to daemonize: %s", ret);
109 elseif ret and ret > 0 then
110 os.exit(0);
111 else
112 module:log("info", "Successfully daemonized to PID %d", pposix.getpid());
113 write_pidfile();
114 end
115 end
116 module:hook("server-started", daemonize_server)
117 else
118 -- Not going to daemonize, so write the pid of this process
119 write_pidfile();
120 end
121
122 module:hook("server-stopped", remove_pidfile);