| 1 | -- Prosody IM |
| 2 | -- Copyright (C) 2008-2010 Matthew Wild |
| 3 | -- Copyright (C) 2008-2010 Waqas Hussain |
| 4 | -- |
| 5 | -- This project is MIT/X11 licensed. Please see the |
| 6 | -- COPYING file in the source package for more information. |
| 7 | -- |
| 8 | |
| 9 | |
| 10 | local want_pposix_version = "0.3.5"; |
| 11 | |
| 12 | local pposix = assert(require "util.pposix"); |
| 13 | if pposix._VERSION ~= want_pposix_version then module:log("warn", "Unknown version (%s) of binary pposix module, expected %s", tostring(pposix._VERSION), want_pposix_version); end |
| 14 | |
| 15 | local signal = select(2, pcall(require, "util.signal")); |
| 16 | if type(signal) == "string" then |
| 17 | module:log("warn", "Couldn't load signal library, won't respond to SIGTERM"); |
| 18 | end |
| 19 | |
| 20 | local lfs = require "lfs"; |
| 21 | local stat = lfs.attributes; |
| 22 | |
| 23 | local prosody = _G.prosody; |
| 24 | |
| 25 | module.host = "*"; -- we're a global module |
| 26 | |
| 27 | local umask = module:get_option("umask") or "027"; |
| 28 | pposix.umask(umask); |
| 29 | |
| 30 | -- Allow switching away from root, some people like strange ports. |
| 31 | module:hook("server-started", function () |
| 32 | local uid = module:get_option("setuid"); |
| 33 | local gid = module:get_option("setgid"); |
| 34 | if gid then |
| 35 | local success, msg = pposix.setgid(gid); |
| 36 | if success then |
| 37 | module:log("debug", "Changed group to "..gid.." successfully."); |
| 38 | else |
| 39 | module:log("error", "Failed to change group to "..gid..". Error: "..msg); |
| 40 | prosody.shutdown("Failed to change group to "..gid); |
| 41 | end |
| 42 | end |
| 43 | if uid then |
| 44 | local success, msg = pposix.setuid(uid); |
| 45 | if success then |
| 46 | module:log("debug", "Changed user to "..uid.." successfully."); |
| 47 | else |
| 48 | module:log("error", "Failed to change user to "..uid..". Error: "..msg); |
| 49 | prosody.shutdown("Failed to change user to "..uid); |
| 50 | end |
| 51 | end |
| 52 | end); |
| 53 | |
| 54 | -- Don't even think about it! |
| 55 | if not prosody.start_time then -- server-starting |
| 56 | local suid = module:get_option("setuid"); |
| 57 | if not suid or suid == 0 or suid == "root" then |
| 58 | if pposix.getuid() == 0 and not module:get_option("run_as_root") then |
| 59 | module:log("error", "Danger, Will Robinson! Prosody doesn't need to be run as root, so don't do it!"); |
| 60 | module:log("error", "For more information on running Prosody as root, see http://prosody.im/doc/root"); |
| 61 | prosody.shutdown("Refusing to run as root"); |
| 62 | end |
| 63 | end |
| 64 | end |
| 65 | |
| 66 | local pidfile; |
| 67 | local pidfile_handle; |
| 68 | |
| 69 | local function remove_pidfile() |
| 70 | if pidfile_handle then |
| 71 | pidfile_handle:close(); |
| 72 | os.remove(pidfile); |
| 73 | pidfile, pidfile_handle = nil, nil; |
| 74 | end |
| 75 | end |
| 76 | |
| 77 | local function write_pidfile() |
| 78 | if pidfile_handle then |
| 79 | remove_pidfile(); |
| 80 | end |
| 81 | pidfile = module:get_option("pidfile"); |
| 82 | if pidfile then |
| 83 | local err; |
| 84 | local mode = stat(pidfile) and "r+" or "w+"; |
| 85 | pidfile_handle, err = io.open(pidfile, mode); |
| 86 | if not pidfile_handle then |
| 87 | module:log("error", "Couldn't write pidfile at %s; %s", pidfile, err); |
| 88 | prosody.shutdown("Couldn't write pidfile"); |
| 89 | else |
| 90 | if not lfs.lock(pidfile_handle, "w") then -- Exclusive lock |
| 91 | local other_pid = pidfile_handle:read("*a"); |
| 92 | module:log("error", "Another Prosody instance seems to be running with PID %s, quitting", other_pid); |
| 93 | pidfile_handle = nil; |
| 94 | prosody.shutdown("Prosody already running"); |
| 95 | else |
| 96 | pidfile_handle:close(); |
| 97 | pidfile_handle, err = io.open(pidfile, "w+"); |
| 98 | if not pidfile_handle then |
| 99 | module:log("error", "Couldn't write pidfile at %s; %s", pidfile, err); |
| 100 | prosody.shutdown("Couldn't write pidfile"); |
| 101 | else |
| 102 | if lfs.lock(pidfile_handle, "w") then |
| 103 | pidfile_handle:write(tostring(pposix.getpid())); |
| 104 | pidfile_handle:flush(); |
| 105 | end |
| 106 | end |
| 107 | end |
| 108 | end |
| 109 | end |
| 110 | end |
| 111 | |
| 112 | local syslog_opened; |
| 113 | function syslog_sink_maker(config) |
| 114 | if not syslog_opened then |
| 115 | pposix.syslog_open("prosody"); |
| 116 | syslog_opened = true; |
| 117 | end |
| 118 | local syslog, format = pposix.syslog_log, string.format; |
| 119 | return function (name, level, message, ...) |
| 120 | if ... then |
| 121 | syslog(level, format(message, ...)); |
| 122 | else |
| 123 | syslog(level, message); |
| 124 | end |
| 125 | end; |
| 126 | end |
| 127 | require "core.loggingmanager".register_sink_type("syslog", syslog_sink_maker); |
| 128 | |
| 129 | local daemonize = module:get_option("daemonize"); |
| 130 | if daemonize == nil then |
| 131 | local no_daemonize = module:get_option("no_daemonize"); --COMPAT w/ 0.5 |
| 132 | daemonize = not no_daemonize; |
| 133 | if no_daemonize ~= nil then |
| 134 | module:log("warn", "The 'no_daemonize' option is now replaced by 'daemonize'"); |
| 135 | module:log("warn", "Update your config from 'no_daemonize = %s' to 'daemonize = %s'", tostring(no_daemonize), tostring(daemonize)); |
| 136 | end |
| 137 | end |
| 138 | |
| 139 | if daemonize then |
| 140 | local function daemonize_server() |
| 141 | local ok, ret = pposix.daemonize(); |
| 142 | if not ok then |
| 143 | module:log("error", "Failed to daemonize: %s", ret); |
| 144 | elseif ret and ret > 0 then |
| 145 | os.exit(0); |
| 146 | else |
| 147 | module:log("info", "Successfully daemonized to PID %d", pposix.getpid()); |
| 148 | write_pidfile(); |
| 149 | end |
| 150 | end |
| 151 | if not prosody.start_time then -- server-starting |
| 152 | daemonize_server(); |
| 153 | end |
| 154 | else |
| 155 | -- Not going to daemonize, so write the pid of this process |
| 156 | write_pidfile(); |
| 157 | end |
| 158 | |
| 159 | module:hook("server-stopped", remove_pidfile); |
| 160 | |
| 161 | -- Set signal handlers |
| 162 | if signal.signal then |
| 163 | signal.signal("SIGTERM", function () |
| 164 | module:log("warn", "Received SIGTERM"); |
| 165 | prosody.unlock_globals(); |
| 166 | prosody.shutdown("Received SIGTERM"); |
| 167 | prosody.lock_globals(); |
| 168 | end); |
| 169 | |
| 170 | signal.signal("SIGHUP", function () |
| 171 | module:log("info", "Received SIGHUP"); |
| 172 | prosody.reload_config(); |
| 173 | prosody.reopen_logfiles(); |
| 174 | end); |
| 175 | |
| 176 | signal.signal("SIGINT", function () |
| 177 | module:log("info", "Received SIGINT"); |
| 178 | prosody.unlock_globals(); |
| 179 | prosody.shutdown("Received SIGINT"); |
| 180 | prosody.lock_globals(); |
| 181 | end); |
| 182 | end |