diff options
-rw-r--r-- | HACKERS | 8 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | TODO | 17 | ||||
-rw-r--r-- | core/componentmanager.lua | 17 | ||||
-rw-r--r-- | core/hostmanager.lua | 4 | ||||
-rw-r--r-- | core/s2smanager.lua | 35 | ||||
-rw-r--r-- | net/dns.lua | 17 | ||||
-rw-r--r-- | net/http.lua | 29 | ||||
-rw-r--r-- | net/httpclient_listener.lua | 2 | ||||
-rw-r--r-- | net/httpserver.lua | 2 | ||||
-rw-r--r-- | net/server.lua | 4 | ||||
-rw-r--r-- | net/xmppserver_listener.lua | 6 | ||||
-rw-r--r-- | plugins/mod_httpserver.lua | 24 | ||||
-rw-r--r-- | plugins/mod_posix.lua | 37 | ||||
-rw-r--r-- | plugins/mod_saslauth.lua | 3 | ||||
-rw-r--r-- | plugins/mod_tls.lua | 2 | ||||
-rwxr-xr-x | prosody | 13 | ||||
-rwxr-xr-x | prosodyctl | 30 | ||||
-rw-r--r-- | util-src/lsignal.c | 73 | ||||
-rw-r--r-- | util/prosodyctl.lua | 11 |
20 files changed, 237 insertions, 99 deletions
@@ -5,6 +5,8 @@ involved you can join us on our mailing list and discussion rooms. More information on these at http://prosody.im/discuss Patches are welcome, though before sending we would appreciate if you read -docs/coding_style.txt for guidelines on how to format your code, and are -comfortable with copyright of contributions being assigned to the core -developers. +docs/coding_style.txt for guidelines on how to format your code, and other tips. + +Documentation for developers can be found at http://prosody.im/doc/developers + +Have fun :) @@ -32,6 +32,6 @@ Mailing lists: ## Installation See the accompanying INSTALL file for help on building Prosody from source. Alternatively -see our guide at http://prosody.im/install +see our guide at http://prosody.im/doc/install @@ -1,5 +1,18 @@ -- Ad-hoc commands -- Clustering +== 0.7 == +DONE: http://blog.prosody.im/prosody-0-7-0rc1-available-for-testing/ +== 0.8 == +- Ad-hoc commands: + http://code.google.com/p/prosody-modules/wiki/mod_adhoc + http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_admin + http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_ping + http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_uptime + - Pubsub +- Data storage backend abstraction +== 0.9 == +- Clustering +== 1.0 == +- Web interface? +- World domination diff --git a/core/componentmanager.lua b/core/componentmanager.lua index a16c01d2..c701c4d7 100644 --- a/core/componentmanager.lua +++ b/core/componentmanager.lua @@ -14,9 +14,10 @@ local jid_split = require "util.jid".split; local fire_event = require "core.eventmanager".fire_event; local events_new = require "util.events".new; local st = require "util.stanza"; -local hosts = hosts; +local prosody, hosts = prosody, prosody.hosts; +local ssl = ssl; -local pairs, type, tostring = pairs, type, tostring; +local pairs, setmetatable, type, tostring = pairs, setmetatable, type, tostring; local components = {}; @@ -73,18 +74,24 @@ end function create_component(host, component, events) -- TODO check for host well-formedness - local ssl_ctx; - if host then + local ssl_ctx, ssl_ctx_in; + if host and ssl then -- We need to find SSL context to use... -- Discussion in prosody@ concluded that -- 1 level back is usually enough by default local base_host = host:gsub("^[^%.]+%.", ""); if hosts[base_host] then ssl_ctx = hosts[base_host].ssl_ctx; + ssl_ctx_in = hosts[base_host].ssl_ctx_in; + elseif prosody.global_ssl_ctx then + -- We have no cert, and no parent host to borrow a cert from + -- Use global/default cert if there is one + ssl_ctx = ssl.newcontext(prosody.global_ssl_ctx); + ssl_ctx_in = ssl.newcontext(setmetatable({ mode = "server" }, { __index = prosody.global_ssl_ctx })); end end return { type = "component", host = host, connected = true, s2sout = {}, - ssl_ctx = ssl_ctx, events = events or events_new() }; + ssl_ctx = ssl_ctx, ssl_ctx_in = ssl_ctx_in, events = events or events_new() }; end function register_component(host, component, session) diff --git a/core/hostmanager.lua b/core/hostmanager.lua index 8010b3de..125e71ba 100644 --- a/core/hostmanager.lua +++ b/core/hostmanager.lua @@ -20,8 +20,8 @@ end local incoming_s2s = _G.prosody.incoming_s2s; -- These are the defaults if not overridden in the config -local default_ssl_ctx = { mode = "client", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; }; -local default_ssl_ctx_in = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; }; +local default_ssl_ctx = { mode = "client", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none", options = "no_sslv2"; }; +local default_ssl_ctx_in = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none", options = "no_sslv2"; }; local log = require "util.logger".init("hostmanager"); diff --git a/core/s2smanager.lua b/core/s2smanager.lua index e8d8e723..92f07354 100644 --- a/core/s2smanager.lua +++ b/core/s2smanager.lua @@ -54,7 +54,7 @@ function compare_srv_priorities(a,b) return a.priority < b.priority or (a.priority == b.priority and a.weight > b.weight); end -local function bounce_sendq(session) +local function bounce_sendq(session, reason) local sendq = session.sendq; if sendq then session.log("info", "sending error replies for "..#sendq.." queued stanzas because of failed outgoing connection to "..tostring(session.to_host)); @@ -72,6 +72,9 @@ local function bounce_sendq(session) reply.attr.type = "error"; reply:tag("error", {type = "cancel"}) :tag("remote-server-not-found", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):up(); + if reason then + reply:tag("text", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):text("Connection failed: "..reason):up(); + end core_process_stanza(dummy, reply); end sendq[i] = nil; @@ -224,7 +227,7 @@ function attempt_connection(host_session, err) if not ok then if not attempt_connection(host_session, err) then -- No more attempts will be made - destroy_session(host_session); + destroy_session(host_session, err); end end end, "_xmpp-server._tcp."..connect_host..".", "SRV"); @@ -284,7 +287,7 @@ function try_connect(host_session, connect_host, connect_port) log("debug", "DNS lookup failed to get a response for %s", connect_host); if not attempt_connection(host_session, "name resolution failed") then -- Retry if we can log("debug", "No other records to try for %s - destroying", host_session.to_host); - destroy_session(host_session); -- End of the line, we can't + destroy_session(host_session, "DNS resolution failed"); -- End of the line, we can't end end end, connect_host, "A", "IN"); @@ -300,7 +303,7 @@ function try_connect(host_session, connect_host, connect_port) end function make_connect(host_session, connect_host, connect_port) - host_session.log("info", "Beginning new connection attempt to %s (%s:%d)", host_session.to_host, connect_host, connect_port); + (host_session.log or log)("info", "Beginning new connection attempt to %s (%s:%d)", host_session.to_host, connect_host, connect_port); -- Ok, we're going to try to connect local from_host, to_host = host_session.from_host, host_session.to_host; @@ -369,17 +372,17 @@ function streamopened(session, attr) session.streamid = uuid_gen(); (session.log or log)("debug", "incoming s2s received <stream:stream>"); - send("<?xml version='1.0'?>"); - send(stanza("stream:stream", { xmlns='jabber:server', ["xmlns:db"]='jabber:server:dialback', - ["xmlns:stream"]='http://etherx.jabber.org/streams', id=session.streamid, from=session.to_host, version=(session.version > 0 and "1.0" or nil) }):top_tag()); if session.to_host and not hosts[session.to_host] then -- Attempting to connect to a host we don't serve session:close({ condition = "host-unknown"; text = "This host does not serve "..session.to_host }); return; end + send("<?xml version='1.0'?>"); + send(stanza("stream:stream", { xmlns='jabber:server', ["xmlns:db"]='jabber:server:dialback', + ["xmlns:stream"]='http://etherx.jabber.org/streams', id=session.streamid, from=session.to_host, to=session.from_host, version=(session.version > 0 and "1.0" or nil) }):top_tag()); if session.version >= 1.0 then local features = st.stanza("stream:features"); - + if session.to_host then hosts[session.to_host].events.fire_event("s2s-stream-features", { session = session, features = features }); else @@ -402,7 +405,7 @@ function streamopened(session, attr) if send_buffer and #send_buffer > 0 then log("debug", "Sending s2s send_buffer now..."); for i, data in ipairs(send_buffer) do - session.sends2s(tostring(data)); + session.sends2s(data); send_buffer[i] = nil; end end @@ -446,6 +449,16 @@ function verify_dialback(id, to, from, key) end function make_authenticated(session, host) + if not session.secure then + local local_host = session.direction == "incoming" and session.to_host or session.from_host; + if config.get(local_host, "core", "s2s_require_encryption") then + session:close({ + condition = "policy-violation", + text = "Encrypted server-to-server communication is required but was not " + ..((session.direction == "outgoing" and "offered") or "used") + }); + end + end if session.type == "s2sout_unauthed" then session.type = "s2sout"; elseif session.type == "s2sin_unauthed" then @@ -493,12 +506,12 @@ end local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed s2s session: %s", data); end -function destroy_session(session) +function destroy_session(session, reason) (session.log or log)("info", "Destroying "..tostring(session.direction).." session "..tostring(session.from_host).."->"..tostring(session.to_host)); if session.direction == "outgoing" then hosts[session.from_host].s2sout[session.to_host] = nil; - bounce_sendq(session); + bounce_sendq(session, reason); elseif session.direction == "incoming" then incoming_s2s[session] = nil; end diff --git a/net/dns.lua b/net/dns.lua index 25941015..1b5321af 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -183,7 +183,7 @@ end function dns.random(...) -- - - - - - - - - - - - - - - - - - - dns.random - math.randomseed(10000*socket.gettime()); + math.randomseed(math.floor(10000*socket.gettime())); dns.random = math.random; return dns.random(...); end @@ -746,7 +746,7 @@ function resolver:receive(rset) -- - - - - - - - - - - - - - - - - receive if not next(self.active) then self:closeall(); end -- was the query on the wanted list? - local q = response.question; + local q = response.question[1]; local cos = get(self.wanted, q.class, q.type, q.name); if cos then for co in pairs(cos) do @@ -769,21 +769,18 @@ function resolver:feed(sock, packet) self.time = socket.gettime(); local response = self:decode(packet); - if response then + if response and self.active[response.header.id] + and self.active[response.header.id][response.question.raw] then --print('received response'); --self.print(response); - for i,section in pairs({ 'answer', 'authority', 'additional' }) do - for j,rr in pairs(response[section]) do - self:remember(rr, response.question[1].type); - end + for j,rr in pairs(response.answer) do + self:remember(rr, response.question[1].type); end -- retire the query local queries = self.active[response.header.id]; - if queries[response.question.raw] then - queries[response.question.raw] = nil; - end + queries[response.question.raw] = nil; if not next(queries) then self.active[response.header.id] = nil; end if not next(self.active) then self:closeall(); end diff --git a/net/http.lua b/net/http.lua index 9d2f9b96..09b04e61 100644 --- a/net/http.lua +++ b/net/http.lua @@ -30,7 +30,7 @@ function urldecode(s) return s and (s:gsub("%%(%x%x)", function (c) return char( local function expectbody(reqt, code) if reqt.method == "HEAD" then return nil end - if code == 204 or code == 304 then return nil end + if code == 204 or code == 304 or code == 301 then return nil end if code >= 100 and code < 200 then return nil end return 1 end @@ -43,6 +43,7 @@ local function request_reader(request, data, startpos) elseif request.state ~= "completed" then -- Error.. connection was closed prematurely request.callback("connection-closed", 0, request); + return; end destroy_request(request); request.body = nil; @@ -73,22 +74,31 @@ local function request_reader(request, data, startpos) elseif request.state == "headers" then print("Reading headers...") local pos = startpos; - local headers = request.responseheaders or {}; + local headers, headers_complete = request.responseheaders; + if not headers then + headers = {}; + request.responseheaders = headers; + end for line in data:sub(startpos, -1):gmatch("(.-)\r\n") do startpos = startpos + #line + 2; local k, v = line:match("(%S+): (.+)"); if k and v then headers[k:lower()] = v; - print("Header: "..k:lower().." = "..v); + --print("Header: "..k:lower().." = "..v); elseif #line == 0 then - request.responseheaders = headers; + headers_complete = true; break; else print("Unhandled header line: "..line); end end + if not headers_complete then return; end -- Reached the end of the headers - request.state = "body"; + if not expectbody(request, request.code) then + request.callback(nil, request.code, request); + return; + end + request.state = "body"; if #data > startpos then return request_reader(request, data, startpos); end @@ -97,12 +107,15 @@ local function request_reader(request, data, startpos) local http, code, text, linelen = data:match("^HTTP/(%S+) (%d+) (.-)\r\n()", startpos); code = tonumber(code); if not code then - return request.callback("invalid-status-line", 0, request); + log("warn", "Invalid HTTP status line, telling callback then closing"); + local ret = request.callback("invalid-status-line", 0, request); + destroy_request(request); + return ret; end request.code, request.responseversion = code, http; - if request.onlystatus or not expectbody(request, code) then + if request.onlystatus then if request.callback then request.callback(nil, code, request); end @@ -200,7 +213,7 @@ end function destroy_request(request) if request.conn then request.handler.close() - listener.disconnect(request.conn, "closed"); + listener.disconnect(request.handler, "closed"); end end diff --git a/net/httpclient_listener.lua b/net/httpclient_listener.lua index 69b7946b..a688a3e0 100644 --- a/net/httpclient_listener.lua +++ b/net/httpclient_listener.lua @@ -30,7 +30,7 @@ end function httpclient.disconnect(conn, err) local request = requests[conn]; - if request then + if request and err ~= "closed" then request:reader(nil); end requests[conn] = nil; diff --git a/net/httpserver.lua b/net/httpserver.lua index c4be59bf..6bd641f9 100644 --- a/net/httpserver.lua +++ b/net/httpserver.lua @@ -65,6 +65,7 @@ local function send_response(request, response) resp = { "HTTP/1.0 200 OK\r\n" }; t_insert(resp, "Connection: close\r\n"); + t_insert(resp, "Content-Type: text/html\r\n"); t_insert(resp, "Content-Length: "); t_insert(resp, #response); t_insert(resp, "\r\n\r\n"); @@ -286,6 +287,7 @@ function new_from_config(ports, handle_request, default_options) if ssl then ssl.mode = "server"; ssl.protocol = "sslv23"; + ssl.options = "no_sslv2"; end new{ port = port, interface = interface, diff --git a/net/server.lua b/net/server.lua index 6ab8ce91..ad46071b 100644 --- a/net/server.lua +++ b/net/server.lua @@ -434,7 +434,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport handler.bufferlen = function( readlen, sendlen )
maxsendlen = sendlen or maxsendlen
maxreadlen = readlen or maxreadlen
- return maxreadlen, maxsendlen
+ return bufferlen, maxreadlen, maxsendlen
end
handler.lock = function( switch )
if switch == true then
@@ -467,7 +467,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport end
local _readbuffer = function( ) -- this function reads data
local buffer, err, part = receive( socket, pattern ) -- receive buffer with "pattern"
- if not err or ( err == "timeout" or err == "wantread" ) then -- received something
+ if not err or (err == "wantread" or err == "timeout") or string_len(part) > 0 then -- received something
local buffer = buffer or part or ""
local len = string_len( buffer )
if len > maxreadlen then
diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua index 2ab51992..86a3d735 100644 --- a/net/xmppserver_listener.lua +++ b/net/xmppserver_listener.lua @@ -152,14 +152,14 @@ function xmppserver.disconnect(conn, err) local session = sessions[conn]; if session then if err and err ~= "closed" and session.srv_hosts then - (session.log or log)("debug", "s2s connection closed unexpectedly"); + (session.log or log)("debug", "s2s connection attempt failed: %s", err); if s2s_attempt_connect(session, err) then - (session.log or log)("debug", "...so we're going to try again"); + (session.log or log)("debug", "...so we're going to try another target"); return; -- Session lives for now end end (session.log or log)("info", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err)); - s2s_destroy_session(session); + s2s_destroy_session(session, err); sessions[conn] = nil; session = nil; end diff --git a/plugins/mod_httpserver.lua b/plugins/mod_httpserver.lua index 545d4faf..c12f1c05 100644 --- a/plugins/mod_httpserver.lua +++ b/plugins/mod_httpserver.lua @@ -15,8 +15,20 @@ local t_concat = table.concat; local http_base = config.get("*", "core", "http_path") or "www_files"; local response_400 = { status = "400 Bad Request", body = "<h1>Bad Request</h1>Sorry, we didn't understand your request :(" }; +local response_403 = { status = "403 Forbidden", body = "<h1>Forbidden</h1>You don't have permission to view the contents of this directory :(" }; local response_404 = { status = "404 Not Found", body = "<h1>Page Not Found</h1>Sorry, we couldn't find what you were looking for :(" }; +-- TODO: Should we read this from /etc/mime.types if it exists? (startup time...?) +local mime_map = { + html = "text/html"; + htm = "text/html"; + xml = "text/xml"; + xsl = "text/xml"; + txt = "text/plain; charset=utf-8"; + js = "text/javascript"; + css = "text/css"; +}; + local function preprocess_path(path) if path:sub(1,1) ~= "/" then path = "/"..path; @@ -36,11 +48,19 @@ local function preprocess_path(path) end function serve_file(path) - local f, err = open(http_base..path, "r"); + local f, err = open(http_base..path, "rb"); if not f then return response_404; end local data = f:read("*a"); f:close(); - return data; + if not data then + return response_403; + end + local ext = path:match("%.([^.]*)$"); + local mime = mime_map[ext]; -- Content-Type should be nil when not known + return { + headers = { ["Content-Type"] = mime; }; + body = data; + }; end local function handle_file_request(method, body, request) diff --git a/plugins/mod_posix.lua b/plugins/mod_posix.lua index b75b9610..ed0dbd87 100644 --- a/plugins/mod_posix.lua +++ b/plugins/mod_posix.lua @@ -19,6 +19,9 @@ end local logger_set = require "util.logger".setwriter; +local lfs = require "lfs"; +local stat = lfs.attributes; + local prosody = _G.prosody; module.host = "*"; -- we're a global module @@ -59,28 +62,38 @@ module:add_event_hook("server-starting", function () end end); -local pidfile_written; +local pidfile; +local pidfile_handle; local function remove_pidfile() - if pidfile_written then - os.remove(pidfile_written); - pidfile_written = nil; + if pidfile_handle then + pidfile_handle:close(); + os.remove(pidfile); + pidfile, pidfile_handle = nil, nil; end end local function write_pidfile() - if pidfile_written then + if pidfile_handle then remove_pidfile(); end - local pidfile = module:get_option("pidfile"); + pidfile = module:get_option("pidfile"); if pidfile then - local pf, err = io.open(pidfile, "w+"); - if not pf then - module:log("error", "Couldn't write pidfile; %s", 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"); else - pf:write(tostring(pposix.getpid())); - pf:close(); - pidfile_written = pidfile; + 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"); + else + pidfile_handle:write(tostring(pposix.getpid())); + pidfile_handle:flush(); + end end end end diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 9fd719c9..2aee2be0 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -115,6 +115,9 @@ local function sasl_handler(session, stanza) if not session.sasl_handler then return session.send(build_reply("failure", "invalid-mechanism")); end + if secure_auth_only and not session.secure then + return session.send(build_reply("failure", "encryption-required")); + end elseif not session.sasl_handler then return; -- FIXME ignoring out of order stanzas because ejabberd does end diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua index 54b48161..67555b15 100644 --- a/plugins/mod_tls.lua +++ b/plugins/mod_tls.lua @@ -94,6 +94,8 @@ module:hook_stanza(xmlns_starttls, "proceed", function (session, stanza) module:log("debug", "Proceeding with TLS on s2sout..."); local format, to_host, from_host = string.format, session.to_host, session.from_host; + local ssl_ctx = session.from_host and hosts[session.from_host].ssl_ctx or global_ssl_ctx; + session.conn.set_sslctx(ssl_ctx); session:reset_stream(); session.conn.starttls(true); session.secure = false; @@ -31,7 +31,9 @@ if CFG_DATADIR then end -- Required to be able to find packages installed with luarocks -pcall(require, "luarocks.require") +if not pcall(require, "luarocks.loader") then -- Try LuaRocks 2.x + pcall(require, "luarocks.require") -- Try LuaRocks 1.x +end -- Replace require with one that doesn't pollute _G do @@ -177,7 +179,7 @@ function init_global_state() -- Load SSL settings from config, and create a ctx table local global_ssl_ctx = rawget(_G, "ssl") and config.get("*", "core", "ssl"); if global_ssl_ctx then - local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; }; + local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none", options = "no_sslv2"; }; setmetatable(global_ssl_ctx, { __index = default_ssl_ctx }); end @@ -192,14 +194,15 @@ function init_global_state() log("error", "core."..option.." is not a table"); else for _, port in ipairs(ports) do + port = tonumber(port); if type(port) ~= "number" then log("error", "Non-numeric "..option.."_ports: "..tostring(port)); else local ok, err = cl.start(listener, { ssl = conntype ~= "tcp" and global_ssl_ctx, port = port, - interface = config.get("*", "core", option.."_interface") - or cl.get(listener).default_interface + interface = (option and config.get("*", "core", option.."_interface")) + or cl.get(listener).default_interface or config.get("*", "core", "interface"), type = conntype }); @@ -332,7 +335,7 @@ end function loop() -- Error handler for errors that make it this far local function catch_uncaught_error(err) - if type(err) == "string" and err:match("%d*: interrupted!$") then + if type(err) == "string" and err:match("interrupted!$") then return "quitting"; end @@ -30,7 +30,10 @@ if CFG_DATADIR then end -- Required to be able to find packages installed with luarocks -pcall(require, "luarocks.require") +if not pcall(require, "luarocks.loader") then -- Try LuaRocks 2.x + pcall(require, "luarocks.require") -- Try LuaRocks 1.x +end + config = require "core.configmanager" @@ -137,18 +140,33 @@ function show_usage(usage, desc) end local function getchar(n) - os.execute("stty raw -echo"); - local ok, char = pcall(io.read, n or 1); - os.execute("stty sane"); + local stty_ret = os.execute("stty raw -echo 2>/dev/null"); + local ok, char; + if stty_ret == 0 then + ok, char = pcall(io.read, n or 1); + os.execute("stty sane"); + else + ok, char = pcall(io.read, "*l"); + if ok then + char = char:sub(1, n or 1); + end + end if ok then return char; end end local function getpass() - os.execute("stty -echo"); + local stty_ret = os.execute("stty -echo 2>/dev/null"); + if stty_ret ~= 0 then + io.write("\027[08m"); -- ANSI 'hidden' text attribute + end local ok, pass = pcall(io.read, "*l"); - os.execute("stty sane"); + if stty_ret == 0 then + os.execute("stty sane"); + else + io.write("\027[00m"); + end io.write("\n"); if ok then return pass; diff --git a/util-src/lsignal.c b/util-src/lsignal.c index 80799e4a..fe35e8b7 100644 --- a/util-src/lsignal.c +++ b/util-src/lsignal.c @@ -1,9 +1,9 @@ /* * lsignal.h -- Signal Handler Library for Lua * - * Version: 1.000 + * Version: 1.000+changes * - * Copyright (C) 2007 Patrick J. Donnelly (batrick@unm.edu) + * Copyright (C) 2007 Patrick J. Donnelly (batrick@batbytes.com) * * This software is distributed under the same license as Lua 5.0: * @@ -27,6 +27,7 @@ */ #include <signal.h> +#include <stdlib.h> #include "lua.h" #include "lauxlib.h" @@ -149,43 +150,67 @@ static const struct lua_signal lua_signals[] = { {NULL, 0} }; -static int Nsig = 0; static lua_State *Lsig = NULL; static lua_Hook Hsig = NULL; static int Hmask = 0; static int Hcount = 0; +static struct signal_event +{ + int Nsig; + struct signal_event *next_event; +} *signal_queue = NULL; + +static struct signal_event *last_event = NULL; + static void sighook(lua_State *L, lua_Debug *ar) { + /* restore the old hook */ + lua_sethook(L, Hsig, Hmask, Hcount); + lua_pushstring(L, LUA_SIGNAL); lua_gettable(L, LUA_REGISTRYINDEX); - lua_pushnumber(L, Nsig); - lua_gettable(L, -2); - lua_call(L, 0, 0); + struct signal_event *event; + while((event = signal_queue)) + { + lua_pushnumber(L, event->Nsig); + lua_gettable(L, -2); + lua_call(L, 0, 0); + signal_queue = event->next_event; + free(event); + }; + + lua_pop(L, 1); /* pop lua_signal table */ - /* set the old hook */ - lua_sethook(L, Hsig, Hmask, Hcount); } static void handle(int sig) { - Hsig = lua_gethook(Lsig); - Hmask = lua_gethookmask(Lsig); - Hcount = lua_gethookcount(Lsig); - Nsig = sig; - - lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); - /* - switch (sig) + if(!signal_queue) + { + /* Store the existing debug hook (if any) and its parameters */ + Hsig = lua_gethook(Lsig); + Hmask = lua_gethookmask(Lsig); + Hcount = lua_gethookcount(Lsig); + + signal_queue = malloc(sizeof(struct signal_event)); + signal_queue->Nsig = sig; + signal_queue->next_event = NULL; + + last_event = signal_queue; + + /* Set our new debug hook */ + lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); + } + else { - case SIGABRT: ; - case SIGFPE: ; - case SIGILL: ; - case SIGINT: ; - case SIGSEGV: ; - case SIGTERM: ; - } */ + last_event->next_event = malloc(sizeof(struct signal_event)); + last_event->next_event->Nsig = sig; + last_event->next_event->next_event = NULL; + + last_event = last_event->next_event; + } } /* @@ -348,7 +373,7 @@ static int l_kill(lua_State *L) static const struct luaL_Reg lsignal_lib[] = { {"signal", l_signal}, {"raise", l_raise}, -#ifdef _POSIX_SOURCE +#if defined _POSIX_SOURCE || (defined(sun) || defined(__sun)) {"kill", l_kill}, #endif {NULL, NULL} diff --git a/util/prosodyctl.lua b/util/prosodyctl.lua index b24e194d..7ce6c513 100644 --- a/util/prosodyctl.lua +++ b/util/prosodyctl.lua @@ -12,6 +12,7 @@ local encodings = require "util.encodings"; local stringprep = encodings.stringprep; local usermanager = require "core.usermanager"; local signal = require "util.signal"; +local lfs = require "lfs"; local nodeprep, nameprep = stringprep.nodeprep, stringprep.nameprep; @@ -64,11 +65,17 @@ function getpid() return false, "no-pidfile"; end - local file, err = io.open(pidfile); + local file, err = io.open(pidfile, "r+"); if not file then return false, "pidfile-read-failed", err; end + local locked, err = lfs.lock(file, "w"); + if locked then + file:close(); + return false, "pidfile-not-locked"; + end + local pid = tonumber(file:read("*a")); file:close(); @@ -82,7 +89,7 @@ end function isrunning() local ok, pid, err = _M.getpid(); if not ok then - if pid == "pidfile-read-failed" then + if pid == "pidfile-read-failed" or pid == "pidfile-not-locked" then -- Report as not running, since we can't open the pidfile -- (it probably doesn't exist) return true, false; |