2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
10 local config
= require
"core.configmanager";
11 local encodings
= require
"util.encodings";
12 local stringprep
= encodings
.stringprep
;
13 local storagemanager
= require
"core.storagemanager";
14 local usermanager
= require
"core.usermanager";
15 local signal
= require
"util.signal";
16 local set
= require
"util.set";
17 local lfs
= require
"lfs";
21 local nodeprep
, nameprep
= stringprep
.nodeprep
, stringprep
.nameprep
;
23 local io
, os
= io
, os
;
25 local tonumber = tonumber;
28 local prosody
= prosody
;
31 local function show_message(msg
, ...)
32 print(msg
:format(...));
35 local function show_usage(usage
, desc
)
36 print("Usage: ".._G
.arg
[0].." "..usage
);
42 local function show_module_configuration_help(mod_name
)
44 print("If you installed a prosody plugin, don't forget to add its name under the 'modules_enabled' section inside your configuration file.")
45 print("Depending on the module, there might be further configuration steps required.")
47 print("More info about: ")
48 print(" modules_enabled: https://prosody.im/doc/modules_enabled")
49 print(" "..mod_name
..": https://modules.prosody.im/"..mod_name
..".html")
52 local function getchar(n
)
53 local stty_ret
= os
.execute("stty raw -echo 2>/dev/null");
55 if stty_ret
== true or stty_ret
== 0 then
56 ok
, char
= pcall(io
.read, n
or 1);
57 os
.execute("stty sane");
59 ok
, char
= pcall(io
.read, "*l");
61 char
= char
:sub(1, n
or 1);
69 local function getline()
70 local ok
, line
= pcall(io
.read, "*l");
76 local function getpass()
77 local stty_ret
, _
, status_code
= os
.execute("stty -echo 2>/dev/null");
78 if status_code
then -- COMPAT w/ Lua 5.1
79 stty_ret
= status_code
;
82 io
.write("\027[08m"); -- ANSI 'hidden' text attribute
84 local ok
, pass
= pcall(io
.read, "*l");
86 os
.execute("stty sane");
96 local function show_yesno(prompt
)
97 io
.write(prompt
, " ");
98 local choice
= getchar():lower();
100 if not choice
:match("%a") then
101 choice
= prompt
:match("%[.-(%U).-%]$");
102 if not choice
then return nil; end
104 return (choice
== "y");
107 local function read_password()
110 io
.write("Enter new password: ");
111 password
= getpass();
113 show_message("No password - cancelled");
116 io
.write("Retype new password: ");
117 if getpass() ~= password
then
118 if not show_yesno
[=[Passwords did not match, try again? [Y/n]]=] then
128 local function show_prompt(prompt)
129 io.write(prompt, " ");
130 local line = getline();
131 line = line and line:gsub("\n$","");
132 return (line and #line > 0) and line or nil;
136 local function adduser(params)
137 local user, host, password = nodeprep(params.user), nameprep(params.host), params.password;
139 return false, "invalid-username";
141 return false, "invalid-hostname";
144 local host_session = prosody.hosts[host];
145 if not host_session then
146 return false, "no-such-host";
149 storagemanager.initialize_host(host);
150 local provider = host_session.users;
151 if not(provider) or provider.name == "null" then
152 usermanager.initialize_host(host);
155 local ok, errmsg = usermanager.create_user(user, password, host);
157 return false, errmsg or "creating-user-failed";
162 local function user_exists(params)
163 local user, host = nodeprep(params.user), nameprep(params.host);
165 storagemanager.initialize_host(host);
166 local provider = prosody.hosts[host].users;
167 if not(provider) or provider.name == "null" then
168 usermanager.initialize_host(host);
171 return usermanager.user_exists(user, host);
174 local function passwd(params)
175 if not user_exists(params) then
176 return false, "no-such-user";
179 return adduser(params);
182 local function deluser(params)
183 if not user_exists(params) then
184 return false, "no-such-user";
186 local user, host = nodeprep(params.user), nameprep(params.host);
188 return usermanager.delete_user(user, host);
191 local function getpid()
192 local pidfile = config.get("*", "pidfile");
194 return false, "no-pidfile";
197 if type(pidfile) ~= "string" then
198 return false, "invalid-pidfile";
201 pidfile = config.resolve_relative_path(prosody.paths.data, pidfile);
203 local modules_disabled = set.new(config.get("*", "modules_disabled"));
204 if prosody.platform ~= "posix" or modules_disabled:contains("posix") then
205 return false, "no-posix";
208 local file, err = io.open(pidfile, "r+");
210 return false, "pidfile-read-failed", err;
213 local locked, err = lfs.lock(file, "w");
216 return false, "pidfile-not-locked";
219 local pid = tonumber(file:read("*a"));
223 return false, "invalid-pid";
229 local function isrunning()
230 local ok, pid, err = getpid();
232 if pid == "pidfile-read-failed" or pid == "pidfile-not-locked" then
233 -- Report as not running, since we can't open the pidfile
234 -- (it probably doesn't exist)
239 return true, signal.kill(pid, 0) == 0;
242 local function start(source_dir, lua)
243 lua = lua and lua .. " " or "";
244 local ok, ret = isrunning();
249 return false, "already-running";
251 if not source_dir then
252 os.execute(lua .. "./prosody");
254 os.execute(lua .. source_dir.."/../../bin/prosody");
259 local function stop()
260 local ok, ret = isrunning();
265 return false, "not-running";
268 local ok, pid = getpid()
269 if not ok then return false, pid; end
271 signal.kill(pid, signal.SIGTERM);
275 local function reload()
276 local ok, ret = isrunning();
281 return false, "not-running";
284 local ok, pid = getpid()
285 if not ok then return false, pid; end
287 signal.kill(pid, signal.SIGHUP);
291 local function get_path_custom_plugins(plugin_paths)
292 -- I'm considering that the custom plugins' path is the first one at prosody.paths.plugins
293 -- luacheck: ignore 512
294 for path in plugin_paths:gmatch("[^;]+") do
299 local function call_luarocks(mod, operation)
300 local dir = get_path_custom_plugins(prosody.paths.plugins);
301 if operation == "install" then
302 show_message("Installing %s at %s", mod, dir);
303 elseif operation == "remove" then
304 show_message("Removing %s from %s", mod, dir);
306 if operation == "list" then
307 os.execute("luarocks list --tree='"..dir.."'")
309 os.execute("luarocks --tree='"..dir.."' --server='http://localhost/' "..operation.." "..mod);
311 if operation == "install" then
312 show_module_configuration_help(mod);
317 show_message = show_message;
318 show_warning = show_message;
319 show_usage = show_usage;
320 show_module_configuration_help = show_module_configuration_help;
324 show_yesno = show_yesno;
325 read_password = read_password;
326 show_prompt = show_prompt;
328 user_exists = user_exists;
332 isrunning = isrunning;
336 get_path_custom_plugins = get_path_custom_plugins;
337 call_luarocks = call_luarocks;