mirror of
https://github.com/bjc/prosody.git
synced 2025-03-31 11:47:40 +03:00
747 lines
21 KiB
Lua
Executable file
747 lines
21 KiB
Lua
Executable file
#!/usr/bin/env lua
|
|
-- Prosody IM
|
|
-- Copyright (C) 2008-2010 Matthew Wild
|
|
-- Copyright (C) 2008-2010 Waqas Hussain
|
|
--
|
|
-- This project is MIT/X11 licensed. Please see the
|
|
-- COPYING file in the source package for more information.
|
|
--
|
|
|
|
-- prosodyctl - command-line controller for Prosody XMPP server
|
|
|
|
-- Will be modified by configure script if run --
|
|
CFG_SOURCEDIR=CFG_SOURCEDIR or os.getenv("PROSODY_SRCDIR");
|
|
CFG_CONFIGDIR=CFG_CONFIGDIR or os.getenv("PROSODY_CFGDIR");
|
|
CFG_PLUGINDIR=CFG_PLUGINDIR or os.getenv("PROSODY_PLUGINDIR");
|
|
CFG_DATADIR=CFG_DATADIR or os.getenv("PROSODY_DATADIR");
|
|
|
|
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
|
|
|
local function is_relative(path)
|
|
local path_sep = package.config:sub(1,1);
|
|
return ((path_sep == "/" and path:sub(1,1) ~= "/")
|
|
or (path_sep == "\\" and (path:sub(1,1) ~= "/" and path:sub(2,3) ~= ":\\")))
|
|
end
|
|
|
|
-- Tell Lua where to find our libraries
|
|
if CFG_SOURCEDIR then
|
|
local function filter_relative_paths(path)
|
|
if is_relative(path) then return ""; end
|
|
end
|
|
local function sanitise_paths(paths)
|
|
return (paths:gsub("[^;]+;?", filter_relative_paths):gsub(";;+", ";"));
|
|
end
|
|
package.path = sanitise_paths(CFG_SOURCEDIR.."/?.lua;"..package.path);
|
|
package.cpath = sanitise_paths(CFG_SOURCEDIR.."/?.so;"..package.cpath);
|
|
end
|
|
|
|
-- Substitute ~ with path to home directory in data path
|
|
if CFG_DATADIR then
|
|
if os.getenv("HOME") then
|
|
CFG_DATADIR = CFG_DATADIR:gsub("^~", os.getenv("HOME"));
|
|
end
|
|
end
|
|
|
|
-----------
|
|
|
|
-- Check before first require, to preempt the probable failure
|
|
if _VERSION < "Lua 5.2" then
|
|
io.stderr:write("Prosody is no longer compatible with Lua 5.1\n")
|
|
io.stderr:write("See https://prosody.im/doc/depends#lua for more information\n")
|
|
return os.exit(1);
|
|
end
|
|
|
|
if not pcall(require, "prosody.loader") then
|
|
pcall(require, "loader");
|
|
end
|
|
|
|
local startup = require "prosody.util.startup";
|
|
startup.prosodyctl();
|
|
|
|
-----------
|
|
|
|
local configmanager = require "prosody.core.configmanager";
|
|
local modulemanager = require "prosody.core.modulemanager"
|
|
local prosodyctl = require "prosody.util.prosodyctl"
|
|
local socket = require "socket"
|
|
local dependencies = require "prosody.util.dependencies";
|
|
local lfs = dependencies.softreq "lfs";
|
|
|
|
-----------------------
|
|
|
|
local parse_args = require "prosody.util.argparse".parse;
|
|
local human_io = require "prosody.util.human.io";
|
|
|
|
local show_message, show_warning = prosodyctl.show_message, prosodyctl.show_warning;
|
|
local show_usage = prosodyctl.show_usage;
|
|
local read_password = human_io.read_password;
|
|
local call_luarocks = prosodyctl.call_luarocks;
|
|
local error_messages = prosodyctl.error_messages;
|
|
|
|
local prosodyctl_timeout = (configmanager.get("*", "prosodyctl_timeout") or 5) * 2;
|
|
-----------------------
|
|
local commands = {};
|
|
local command = table.remove(arg, 1);
|
|
|
|
local only_help = { short_params = { h = "help"; ["?"] = "help" } }
|
|
|
|
function commands.install(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help or not arg[1] then
|
|
show_usage([[install]], [[Installs a prosody/luarocks plugin]]);
|
|
return opts.help and 0 or 1;
|
|
end
|
|
-- TODO finalize config option name
|
|
local server = opts.server or configmanager.get("*", "plugin_server");
|
|
if not (arg[1]:match("^https://") or lfs.attributes(arg[1]) or server) then
|
|
show_warning("There is no 'plugin_server' option in the configuration file");
|
|
-- see https://prosody.im/doc/TODO documentation
|
|
-- #1602
|
|
return 1;
|
|
end
|
|
show_message("Installing %s in %s", arg[1], prosody.paths.installer);
|
|
local ret = call_luarocks("install", arg[1], server);
|
|
if ret == 0 and arg[1]:match("^mod_") then
|
|
prosodyctl.show_module_configuration_help(arg[1]);
|
|
end
|
|
return ret;
|
|
end
|
|
|
|
function commands.remove(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help or not arg[1] then
|
|
show_usage([[remove]], [[Removes a module installed in the working directory's plugins folder]]);
|
|
return opts.help and 0 or 1;
|
|
end
|
|
show_message("Removing %s from %s", arg[1], prosody.paths.installer);
|
|
local ret = call_luarocks("remove", arg[1]);
|
|
return ret;
|
|
end
|
|
|
|
function commands.list(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help then
|
|
show_usage([[list]], [[Shows installed rocks]]);
|
|
return 0;
|
|
end
|
|
local server = opts.server or configmanager.get("*", "plugin_server");
|
|
if opts.outdated then
|
|
-- put this back for luarocks
|
|
arg[1] = "--outdated";
|
|
|
|
if not server then
|
|
show_warning("There is no 'plugin_server' option in the configuration file, but this is needed for 'list --outdated' to work.");
|
|
return 1;
|
|
end
|
|
end
|
|
local ret = call_luarocks("list", arg[1], server);
|
|
return ret;
|
|
end
|
|
|
|
function commands.adduser(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help or not arg[1] then
|
|
show_usage([[adduser JID]], [[Create the specified user account in Prosody]]);
|
|
return opts.help and 0 or 1;
|
|
end
|
|
|
|
local shell = require "prosody.util.prosodyctl.shell";
|
|
return shell.shell({ ("user:create(%q, nil, %q)"):format(arg[1], "prosody:member") });
|
|
end
|
|
|
|
function commands.passwd(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help or not arg[1] then
|
|
show_usage([[passwd JID]], [[Set the password for the specified user account in Prosody]]);
|
|
return opts.help and 0 or 1;
|
|
end
|
|
|
|
local shell = require "prosody.util.prosodyctl.shell";
|
|
return shell.shell({ ("user:password(%q, nil)"):format(arg[1]) });
|
|
end
|
|
|
|
function commands.deluser(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help or not arg[1] then
|
|
show_usage([[deluser JID]], [[Permanently remove the specified user account from Prosody]]);
|
|
return opts.help and 0 or 1;
|
|
end
|
|
|
|
local shell = require "prosody.util.prosodyctl.shell";
|
|
return shell.shell({ ("user:delete(%q)"):format(arg[1]) });
|
|
end
|
|
|
|
local function has_init_system() --> which
|
|
lfs = lfs or require"lfs";
|
|
if lfs.attributes("/etc/systemd") then
|
|
return "systemd";
|
|
elseif lfs.attributes("/etc/init.d/prosody") then
|
|
return "rc.d";
|
|
end
|
|
end
|
|
|
|
local function service_command_warning(service_command)
|
|
if prosody.installed and configmanager.get("*", "prosodyctl_service_warnings") ~= false then
|
|
show_warning("ERROR: Use of 'prosodyctl %s' is disabled in this installation because", service_command);
|
|
|
|
local init = has_init_system()
|
|
if init then
|
|
show_warning(" we detected that this system uses %s for managing services.", init);
|
|
show_warning("");
|
|
show_warning(" To avoid problems, use that directly instead. For example:");
|
|
show_warning("");
|
|
if init == "systemd" then
|
|
show_warning(" systemctl %s prosody", service_command);
|
|
elseif init == "rc.d" then
|
|
show_warning(" /etc/init.d/prosody %s", service_command);
|
|
end
|
|
else
|
|
show_warning(" it may conflict with your system's service manager.");
|
|
show_warning("");
|
|
end
|
|
|
|
show_warning(" Proceeding to use prosodyctl may cause process management issues.");
|
|
show_warning(" You can pass --force to override this warning, or set");
|
|
show_warning(" prosodyctl_service_warnings = false in your global config.");
|
|
|
|
os.exit(1);
|
|
end
|
|
end
|
|
|
|
function commands.start(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help then
|
|
show_usage([[start]], [[Start Prosody]]);
|
|
return 0;
|
|
end
|
|
if not opts.force then
|
|
service_command_warning("start");
|
|
end
|
|
local ok, ret = prosodyctl.isrunning();
|
|
if not ok then
|
|
show_message(error_messages[ret]);
|
|
return 1;
|
|
end
|
|
|
|
if ret then
|
|
--luacheck: ignore 421/ret
|
|
local ok, ret = prosodyctl.getpid();
|
|
if not ok then
|
|
show_message("Couldn't get running Prosody's PID");
|
|
show_message(error_messages[ret]);
|
|
return 1;
|
|
end
|
|
show_message("Prosody is already running with PID %s", ret or "(unknown)");
|
|
return 1;
|
|
end
|
|
|
|
--luacheck: ignore 411/ret
|
|
local lua;
|
|
do
|
|
local i = 0;
|
|
repeat
|
|
i = i - 1;
|
|
until arg[i-1] == nil
|
|
lua = arg[i];
|
|
end
|
|
local ok, ret = prosodyctl.start(prosody.paths.source, lua);
|
|
if ok then
|
|
local daemonize = configmanager.get("*", "daemonize");
|
|
if daemonize == nil then
|
|
daemonize = prosody.installed;
|
|
end
|
|
if daemonize then
|
|
local i=1;
|
|
while true do
|
|
local ok, running = prosodyctl.isrunning();
|
|
if ok and running then
|
|
break;
|
|
elseif i == 5 then
|
|
show_message("Still waiting...");
|
|
elseif i >= prosodyctl_timeout then
|
|
show_message("Prosody is still not running. Please give it some time or check your log files for errors.");
|
|
return 2;
|
|
end
|
|
socket.sleep(0.5);
|
|
i = i + 1;
|
|
end
|
|
show_message("Started");
|
|
end
|
|
return 0;
|
|
end
|
|
|
|
show_message("Failed to start Prosody");
|
|
show_message(error_messages[ret])
|
|
return 1;
|
|
end
|
|
|
|
function commands.status(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help then
|
|
show_usage([[status]], [[Reports the running status of Prosody]]);
|
|
return 0;
|
|
end
|
|
|
|
local ok, ret = prosodyctl.isrunning();
|
|
if not ok then
|
|
show_message(error_messages[ret]);
|
|
return 1;
|
|
end
|
|
|
|
if ret then
|
|
--luacheck: ignore 421/ret
|
|
local ok, ret = prosodyctl.getpid();
|
|
if not ok then
|
|
show_message("Couldn't get running Prosody's PID");
|
|
show_message(error_messages[ret]);
|
|
return 1;
|
|
end
|
|
show_message("Prosody is running with PID %s", ret or "(unknown)");
|
|
return 0;
|
|
else
|
|
show_message("Prosody is not running");
|
|
if not prosody.switched_user and prosody.current_uid ~= 0 then
|
|
print("\nNote:")
|
|
print(" You will also see this if prosodyctl is not running under");
|
|
print(" the same user account as Prosody. Try running as root (e.g. ");
|
|
print(" with 'sudo' in front) to gain access to Prosody's real status.");
|
|
end
|
|
return 2
|
|
end
|
|
end
|
|
|
|
function commands.stop(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help then
|
|
show_usage([[stop]], [[Stop a running Prosody server]]);
|
|
return 0;
|
|
end
|
|
|
|
if not opts.force then
|
|
service_command_warning("stop");
|
|
end
|
|
|
|
local ok, running = prosodyctl.isrunning();
|
|
if not ok then
|
|
show_message(error_messages[running]);
|
|
return 1;
|
|
elseif not running then
|
|
show_message("Prosody is not running");
|
|
return 1;
|
|
end
|
|
|
|
local ok, ret = prosodyctl.stop();
|
|
if ok then
|
|
local i=1;
|
|
while true do
|
|
local ok, running = prosodyctl.isrunning(); --luacheck: ignore 421
|
|
if ok and not running then
|
|
break;
|
|
elseif i == 5 then
|
|
show_message("Still waiting...");
|
|
elseif i >= prosodyctl_timeout then
|
|
show_message("Prosody is still running. Please give it some time or check your log files for errors.");
|
|
return 2;
|
|
end
|
|
socket.sleep(0.5);
|
|
i = i + 1;
|
|
end
|
|
show_message("Stopped");
|
|
return 0;
|
|
end
|
|
|
|
show_message(error_messages[ret]);
|
|
return 1;
|
|
end
|
|
|
|
function commands.restart(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help then
|
|
show_usage([[restart]], [[Restart a running Prosody server]]);
|
|
return 1;
|
|
end
|
|
|
|
if not opts.force then
|
|
service_command_warning("restart");
|
|
end
|
|
|
|
commands.stop(arg);
|
|
return commands.start(arg);
|
|
end
|
|
|
|
function commands.about(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help then
|
|
show_usage([[about]], [[Show information about this Prosody installation]]);
|
|
return 0;
|
|
end
|
|
|
|
local pwd = ".";
|
|
local sorted_pairs = require "prosody.util.iterators".sorted_pairs;
|
|
local hg = require"prosody.util.mercurial";
|
|
local relpath = configmanager.resolve_relative_path;
|
|
|
|
print("Prosody "..(prosody.version or "(unknown version)"));
|
|
print("");
|
|
print("# Prosody directories");
|
|
print("Data directory: "..relpath(pwd, prosody.paths.data));
|
|
print("Config directory: "..relpath(pwd, prosody.paths.config or "."));
|
|
print("Source directory: "..relpath(pwd, prosody.paths.source or "."));
|
|
print("Plugin directories:")
|
|
print(" "..(prosody.paths.plugins:gsub("([^;]+);?", function(path)
|
|
path = configmanager.resolve_relative_path(pwd, path);
|
|
local hgid, hgrepo = hg.check_id(path);
|
|
if not hgid and hgrepo then
|
|
return path.." - "..hgrepo .."!\n ";
|
|
end
|
|
-- 010452cfaf53 is the first commit in the prosody-modules repository
|
|
hgrepo = hgrepo == "010452cfaf53" and "prosody-modules";
|
|
return path..(hgid and " - "..(hgrepo or "HG").." rev: "..hgid or "")
|
|
.."\n ";
|
|
end)));
|
|
print("");
|
|
local have_pposix, pposix = pcall(require, "prosody.util.pposix");
|
|
if have_pposix and pposix.uname then
|
|
print("# Operating system");
|
|
local uname, err = pposix.uname();
|
|
print(uname and uname.sysname .. " " .. uname.release or "Unknown POSIX", err or "");
|
|
print("");
|
|
end
|
|
print("# Lua environment");
|
|
print("Lua version: ", _G._VERSION);
|
|
print("");
|
|
print("Lua module search paths:");
|
|
for path in package.path:gmatch("[^;]+") do
|
|
print(" "..path);
|
|
end
|
|
print("");
|
|
print("Lua C module search paths:");
|
|
for path in package.cpath:gmatch("[^;]+") do
|
|
print(" "..path);
|
|
end
|
|
print("");
|
|
local luarocks_status = "Not installed"
|
|
if pcall(require, "luarocks.loader") then
|
|
luarocks_status = "Installed (2.x+)";
|
|
if package.loaded["luarocks.cfg"] then
|
|
luarocks_status = "Installed ("..(package.loaded["luarocks.cfg"].program_version or "2.x+")..")";
|
|
end
|
|
elseif pcall(require, "luarocks.require") then
|
|
luarocks_status = "Installed (1.x)";
|
|
end
|
|
print("LuaRocks: ", luarocks_status);
|
|
print("");
|
|
print("# Network");
|
|
print("");
|
|
print("Backend: "..require "prosody.net.server".get_backend());
|
|
print("");
|
|
print("# Lua module versions");
|
|
local module_versions, longest_name = {}, 8;
|
|
local library_versions = {};
|
|
dependencies.softreq"ssl";
|
|
dependencies.softreq"DBI";
|
|
dependencies.softreq"readline";
|
|
local friendly_names = {
|
|
DBI = "LuaDBI";
|
|
lfs = "LuaFileSystem";
|
|
lunbound = "luaunbound";
|
|
lxp = "LuaExpat";
|
|
socket = "LuaSocket";
|
|
ssl = "LuaSec";
|
|
};
|
|
local alternate_version_fields = {
|
|
-- These diverge from the module._VERSION convention
|
|
readline = "Version";
|
|
}
|
|
local lunbound = dependencies.softreq"lunbound";
|
|
local lxp = dependencies.softreq"lxp";
|
|
local hashes = dependencies.softreq"prosody.util.hashes";
|
|
for name, module in pairs(package.loaded) do
|
|
local version_field = alternate_version_fields[name] or "_VERSION";
|
|
if type(module) == "table" and rawget(module, version_field)
|
|
and name ~= "_G" and not name:match("%.") then
|
|
name = friendly_names[name] or name;
|
|
if #name > longest_name then
|
|
longest_name = #name;
|
|
end
|
|
local mod_version = module[version_field];
|
|
if tostring(mod_version):sub(1, #name+1) == name .. " " then
|
|
mod_version = mod_version:sub(#name+2);
|
|
end
|
|
module_versions[name] = mod_version;
|
|
end
|
|
end
|
|
if lunbound then
|
|
if not module_versions["luaunbound"] then
|
|
module_versions["luaunbound"] = "0.5 (?)";
|
|
end
|
|
library_versions["libunbound"] = lunbound._LIBVER;
|
|
end
|
|
if lxp then
|
|
library_versions["libexpat"] = lxp._EXPAT_VERSION;
|
|
end
|
|
if hashes then
|
|
library_versions["libcrypto"] = hashes._LIBCRYPTO_VERSION;
|
|
end
|
|
for name, version in sorted_pairs(module_versions) do
|
|
print(name..":"..string.rep(" ", longest_name-#name), version);
|
|
end
|
|
print("");
|
|
print("# library versions");
|
|
if require "prosody.net.server".event_base then
|
|
library_versions["libevent"] = require"luaevent".core.libevent_version();
|
|
end
|
|
for name, version in sorted_pairs(library_versions) do
|
|
print(name..":"..string.rep(" ", longest_name-#name), version);
|
|
end
|
|
print("");
|
|
end
|
|
|
|
function commands.version(arg)
|
|
local flags = { short_params = { h = "help"; ["?"] = "help", v = "verbose" } };
|
|
local opts = parse_args(arg, flags);
|
|
if opts.help then
|
|
show_usage("version [-v]", [[Show current Prosody version, or more]]);
|
|
return 0;
|
|
elseif opts.verbose then
|
|
return commands.about(arg);
|
|
end
|
|
|
|
print("Prosody "..(prosody.version or "(unknown version)"));
|
|
end
|
|
|
|
function commands.lua_paths()
|
|
local function shell_escape(s)
|
|
return "'" .. tostring(s):gsub("'",[['\'']]) .. "'";
|
|
end
|
|
|
|
print("LUA_PATH="..shell_escape(package.path));
|
|
print("LUA_CPATH="..shell_escape(package.cpath));
|
|
end
|
|
|
|
function commands.reload(arg)
|
|
local opts = parse_args(arg, only_help);
|
|
if opts.help then
|
|
show_usage([[reload]], [[Reload Prosody's configuration and re-open log files]]);
|
|
return 0;
|
|
end
|
|
|
|
local shell = require "prosody.util.prosodyctl.shell";
|
|
if shell.available() then
|
|
if arg[1] and arg[1]:match"^mod_" then
|
|
-- TODO reword the usage text, document
|
|
arg[1] = arg[1]:match("^mod_(.*)"); -- strip mod_ prefix
|
|
table.insert(arg, 1, "module");
|
|
table.insert(arg, 2, "reload");
|
|
return shell.shell(arg);
|
|
end
|
|
return shell.shell({ "config", "reload" });
|
|
elseif arg[1] then
|
|
show_message("Admin socket not found - is it enabled and is Prosody running?");
|
|
return 1;
|
|
end
|
|
|
|
local ok, running = prosodyctl.isrunning();
|
|
if not ok then
|
|
show_message(error_messages[running]);
|
|
return 1;
|
|
elseif not running then
|
|
show_message("Prosody is not running");
|
|
return 1;
|
|
end
|
|
|
|
if not opts.force then
|
|
service_command_warning("reload");
|
|
end
|
|
|
|
local ok, ret = prosodyctl.reload();
|
|
if ok then
|
|
|
|
show_message("Prosody log files re-opened and config file reloaded. You may need to reload modules for some changes to take effect.");
|
|
return 0;
|
|
end
|
|
|
|
show_message(error_messages[ret]);
|
|
return 1;
|
|
end
|
|
-- ejabberdctl compatibility
|
|
|
|
local unpack = table.unpack;
|
|
|
|
function commands.register(arg)
|
|
local user, host, password = unpack(arg);
|
|
if (not (user and host)) or arg[1] == "--help" then
|
|
if user ~= "--help" then
|
|
if not user then
|
|
show_message [[No username specified]]
|
|
elseif not host then
|
|
show_message [[Please specify which host you want to register the user on]];
|
|
end
|
|
end
|
|
show_usage("register USER HOST [PASSWORD]", "Register a user on the server, with the given password");
|
|
return 1;
|
|
end
|
|
if not password then
|
|
password = read_password();
|
|
if not password then
|
|
show_message [[Unable to register user with no password]];
|
|
return 1;
|
|
end
|
|
end
|
|
|
|
local ok, msg = prosodyctl.adduser { user = user, host = host, password = password };
|
|
|
|
if ok then return 0; end
|
|
|
|
show_message(error_messages[msg])
|
|
return 1;
|
|
end
|
|
|
|
function commands.unregister(arg)
|
|
local user, host = unpack(arg);
|
|
if (not (user and host)) or arg[1] == "--help" then
|
|
if user ~= "--help" then
|
|
if not user then
|
|
show_message [[No username specified]]
|
|
elseif not host then
|
|
show_message [[Please specify which host you want to unregister the user from]];
|
|
end
|
|
end
|
|
show_usage("unregister USER HOST [PASSWORD]", "Permanently remove a user account from the server");
|
|
return 1;
|
|
end
|
|
|
|
local ok, msg = prosodyctl.deluser { user = user, host = host };
|
|
|
|
if ok then return 0; end
|
|
|
|
show_message(error_messages[msg])
|
|
return 1;
|
|
end
|
|
|
|
---------------------
|
|
|
|
local async = require "prosody.util.async";
|
|
local server = require "prosody.net.server";
|
|
local watchers = {
|
|
error = function (_, err)
|
|
error(err);
|
|
end;
|
|
waiting = function ()
|
|
server.loop();
|
|
end;
|
|
};
|
|
local command_runner = async.runner(function ()
|
|
if command and command:match("^mod_") then -- Is a command in a module
|
|
local module_name = command:match("^mod_(.+)");
|
|
do
|
|
local ret, err = modulemanager.load("*", module_name);
|
|
if not ret then
|
|
show_message("Failed to load module '"..module_name.."': "..err);
|
|
os.exit(1);
|
|
end
|
|
end
|
|
|
|
local module = modulemanager.get_module("*", module_name);
|
|
if not module then
|
|
show_message("Failed to load module '"..module_name.."': Unknown error");
|
|
os.exit(1);
|
|
end
|
|
|
|
if not modulemanager.module_has_method(module, "command") then
|
|
show_message("Fail: mod_"..module_name.." does not support any commands");
|
|
os.exit(1);
|
|
end
|
|
|
|
local ok, ret = modulemanager.call_module_method(module, "command", arg);
|
|
if ok then
|
|
if type(ret) == "number" then
|
|
os.exit(ret, true);
|
|
elseif type(ret) == "string" then
|
|
show_message(ret);
|
|
end
|
|
os.exit(0, true); -- :)
|
|
else
|
|
show_message("Failed to execute command: %s", error_messages[ret]);
|
|
os.exit(1); -- :(
|
|
end
|
|
end
|
|
|
|
if command and not commands[command] then
|
|
local ok, command_module = pcall(require, "prosody.util.prosodyctl."..command);
|
|
if ok and command_module[command] then
|
|
commands[command] = command_module[command];
|
|
end
|
|
end
|
|
|
|
if not commands[command] then -- Show help for all commands
|
|
function show_usage(usage, desc)
|
|
print(string.format(" %-14s %s", usage, desc));
|
|
end
|
|
|
|
print("prosodyctl - Manage a Prosody server");
|
|
print("");
|
|
print("Usage: "..arg[0].." COMMAND [OPTIONS]");
|
|
print("");
|
|
print("Where COMMAND may be one of:");
|
|
|
|
local hidden_commands = require "prosody.util.set".new{ "register", "unregister", "lua_paths" };
|
|
local commands_order = {
|
|
"Process management:",
|
|
"start"; "stop"; "restart"; "reload"; "status";
|
|
"shell",
|
|
"User management:",
|
|
"adduser"; "passwd"; "deluser";
|
|
"Plugin management:",
|
|
"install"; "remove"; "list";
|
|
"Informative:",
|
|
"check",
|
|
"version",
|
|
"Other:",
|
|
"cert",
|
|
};
|
|
-- These live in util.prosodyctl.$command so we have their short help here.
|
|
local external_commands = {
|
|
cert = "Certificate management commands",
|
|
check = "Perform basic checks on your Prosody installation",
|
|
shell = "Interact with a running Prosody",
|
|
}
|
|
|
|
local done = {};
|
|
|
|
if prosody.installed and has_init_system() then
|
|
-- Hide start, stop, restart
|
|
done[table.remove(commands_order, 2)] = true;
|
|
done[table.remove(commands_order, 2)] = true;
|
|
done[table.remove(commands_order, 2)] = true;
|
|
end
|
|
|
|
for _, command_name in ipairs(commands_order) do
|
|
local command_func = commands[command_name];
|
|
if command_func then
|
|
command_func{ "--help" };
|
|
done[command_name] = true;
|
|
elseif external_commands[command_name] then
|
|
show_usage(command_name, external_commands[command_name]);
|
|
done[command_name] = true;
|
|
else
|
|
print""
|
|
print(command_name);
|
|
end
|
|
end
|
|
|
|
for command_name, command_func in pairs(commands) do
|
|
if not done[command_name] and not hidden_commands:contains(command_name) then
|
|
command_func{ "--help" };
|
|
done[command_name] = true;
|
|
end
|
|
end
|
|
|
|
|
|
os.exit(0, true);
|
|
end
|
|
|
|
os.exit(commands[command](arg), true);
|
|
end, watchers);
|
|
|
|
command_runner:run(true);
|