mod_admin_telnet: Identify native bidi sessions
[prosody.git] / util / prosodyctl.lua
blob163658f30c0240ddd3d6ae4d6541d83e55964ea4
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 --
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";
18 local pcall = pcall;
19 local type = type;
21 local nodeprep, nameprep = stringprep.nodeprep, stringprep.nameprep;
23 local io, os = io, os;
24 local print = print;
25 local tonumber = tonumber;
27 local _G = _G;
28 local prosody = prosody;
30 -- UI helpers
31 local function show_message(msg, ...)
32 print(msg:format(...));
33 end
35 local function show_usage(usage, desc)
36 print("Usage: ".._G.arg[0].." "..usage);
37 if desc then
38 print(" "..desc);
39 end
40 end
42 local function show_module_configuration_help(mod_name)
43 print("Done.")
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.")
46 print("")
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")
50 end
52 local function getchar(n)
53 local stty_ret = os.execute("stty raw -echo 2>/dev/null");
54 local ok, char;
55 if stty_ret == true or stty_ret == 0 then
56 ok, char = pcall(io.read, n or 1);
57 os.execute("stty sane");
58 else
59 ok, char = pcall(io.read, "*l");
60 if ok then
61 char = char:sub(1, n or 1);
62 end
63 end
64 if ok then
65 return char;
66 end
67 end
69 local function getline()
70 local ok, line = pcall(io.read, "*l");
71 if ok then
72 return line;
73 end
74 end
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;
80 end
81 if stty_ret ~= 0 then
82 io.write("\027[08m"); -- ANSI 'hidden' text attribute
83 end
84 local ok, pass = pcall(io.read, "*l");
85 if stty_ret == 0 then
86 os.execute("stty sane");
87 else
88 io.write("\027[00m");
89 end
90 io.write("\n");
91 if ok then
92 return pass;
93 end
94 end
96 local function show_yesno(prompt)
97 io.write(prompt, " ");
98 local choice = getchar():lower();
99 io.write("\n");
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()
108 local password;
109 while true do
110 io.write("Enter new password: ");
111 password = getpass();
112 if not password then
113 show_message("No password - cancelled");
114 return;
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
119 return;
121 else
122 break;
125 return password;
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;
135 -- Server control
136 local function adduser(params)
137 local user, host, password = nodeprep(params.user), nameprep(params.host), params.password;
138 if not user then
139 return false, "invalid-username";
140 elseif not host then
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);
156 if not ok then
157 return false, errmsg or "creating-user-failed";
159 return true;
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");
193 if not pidfile then
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+");
209 if not file then
210 return false, "pidfile-read-failed", err;
213 local locked, err = lfs.lock(file, "w");
214 if locked then
215 file:close();
216 return false, "pidfile-not-locked";
219 local pid = tonumber(file:read("*a"));
220 file:close();
222 if not pid then
223 return false, "invalid-pid";
226 return true, pid;
229 local function isrunning()
230 local ok, pid, err = getpid();
231 if not ok then
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)
235 return true, false;
237 return ok, pid;
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();
245 if not ok then
246 return ok, ret;
248 if ret then
249 return false, "already-running";
251 if not source_dir then
252 os.execute(lua .. "./prosody");
253 else
254 os.execute(lua .. source_dir.."/../../bin/prosody");
256 return true;
259 local function stop()
260 local ok, ret = isrunning();
261 if not ok then
262 return ok, ret;
264 if not ret then
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);
272 return true;
275 local function reload()
276 local ok, ret = isrunning();
277 if not ok then
278 return ok, ret;
280 if not ret then
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);
288 return true;
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
295 return path;
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.."'")
308 else
309 os.execute("luarocks --tree='"..dir.."' --server='http://localhost/' "..operation.." "..mod);
311 if operation == "install" then
312 show_module_configuration_help(mod);
316 return {
317 show_message = show_message;
318 show_warning = show_message;
319 show_usage = show_usage;
320 show_module_configuration_help = show_module_configuration_help;
321 getchar = getchar;
322 getline = getline;
323 getpass = getpass;
324 show_yesno = show_yesno;
325 read_password = read_password;
326 show_prompt = show_prompt;
327 adduser = adduser;
328 user_exists = user_exists;
329 passwd = passwd;
330 deluser = deluser;
331 getpid = getpid;
332 isrunning = isrunning;
333 start = start;
334 stop = stop;
335 reload = reload;
336 get_path_custom_plugins = get_path_custom_plugins;
337 call_luarocks = call_luarocks;