Software /
code /
prosody
Comparison
util/prosodyctl.lua @ 11200:bf8f2da84007
Merge 0.11->trunk
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Thu, 05 Nov 2020 22:31:25 +0100 |
parent | 11136:d0d3e25b7300 |
child | 11290:7919ecdc4a72 |
comparison
equal
deleted
inserted
replaced
11199:6c7c50a4de32 | 11200:bf8f2da84007 |
---|---|
10 local config = require "core.configmanager"; | 10 local config = require "core.configmanager"; |
11 local encodings = require "util.encodings"; | 11 local encodings = require "util.encodings"; |
12 local stringprep = encodings.stringprep; | 12 local stringprep = encodings.stringprep; |
13 local storagemanager = require "core.storagemanager"; | 13 local storagemanager = require "core.storagemanager"; |
14 local usermanager = require "core.usermanager"; | 14 local usermanager = require "core.usermanager"; |
15 local interpolation = require "util.interpolation"; | |
15 local signal = require "util.signal"; | 16 local signal = require "util.signal"; |
16 local set = require "util.set"; | 17 local set = require "util.set"; |
17 local lfs = require "lfs"; | 18 local lfs = require "lfs"; |
18 local pcall = pcall; | |
19 local type = type; | 19 local type = type; |
20 | 20 |
21 local nodeprep, nameprep = stringprep.nodeprep, stringprep.nameprep; | 21 local nodeprep, nameprep = stringprep.nodeprep, stringprep.nameprep; |
22 | 22 |
23 local io, os = io, os; | 23 local io, os = io, os; |
25 local tonumber = tonumber; | 25 local tonumber = tonumber; |
26 | 26 |
27 local _G = _G; | 27 local _G = _G; |
28 local prosody = prosody; | 28 local prosody = prosody; |
29 | 29 |
30 local error_messages = setmetatable({ | |
31 ["invalid-username"] = "The given username is invalid in a Jabber ID"; | |
32 ["invalid-hostname"] = "The given hostname is invalid"; | |
33 ["no-password"] = "No password was supplied"; | |
34 ["no-such-user"] = "The given user does not exist on the server"; | |
35 ["no-such-host"] = "The given hostname does not exist in the config"; | |
36 ["unable-to-save-data"] = "Unable to store, perhaps you don't have permission?"; | |
37 ["no-pidfile"] = "There is no 'pidfile' option in the configuration file, see https://prosody.im/doc/prosodyctl#pidfile for help"; | |
38 ["invalid-pidfile"] = "The 'pidfile' option in the configuration file is not a string, see https://prosody.im/doc/prosodyctl#pidfile for help"; | |
39 ["no-posix"] = "The mod_posix module is not enabled in the Prosody config file, see https://prosody.im/doc/prosodyctl for more info"; | |
40 ["no-such-method"] = "This module has no commands"; | |
41 ["not-running"] = "Prosody is not running"; | |
42 }, { __index = function (_,k) return "Error: "..(tostring(k):gsub("%-", " "):gsub("^.", string.upper)); end }); | |
43 | |
30 -- UI helpers | 44 -- UI helpers |
31 local function show_message(msg, ...) | 45 local show_message = require "util.human.io".printf; |
32 print(msg:format(...)); | |
33 end | |
34 | 46 |
35 local function show_usage(usage, desc) | 47 local function show_usage(usage, desc) |
36 print("Usage: ".._G.arg[0].." "..usage); | 48 print("Usage: ".._G.arg[0].." "..usage); |
37 if desc then | 49 if desc then |
38 print(" "..desc); | 50 print(" "..desc); |
39 end | 51 end |
40 end | 52 end |
41 | 53 |
42 local function getchar(n) | 54 local function show_module_configuration_help(mod_name) |
43 local stty_ret = os.execute("stty raw -echo 2>/dev/null"); | 55 print("Done.") |
44 local ok, char; | 56 print("If you installed a prosody plugin, don't forget to add its name under the 'modules_enabled' section inside your configuration file.") |
45 if stty_ret == true or stty_ret == 0 then | 57 print("Depending on the module, there might be further configuration steps required.") |
46 ok, char = pcall(io.read, n or 1); | 58 print("") |
47 os.execute("stty sane"); | 59 print("More info about: ") |
48 else | 60 print(" modules_enabled: https://prosody.im/doc/modules_enabled") |
49 ok, char = pcall(io.read, "*l"); | 61 print(" "..mod_name..": https://modules.prosody.im/"..mod_name..".html") |
50 if ok then | |
51 char = char:sub(1, n or 1); | |
52 end | |
53 end | |
54 if ok then | |
55 return char; | |
56 end | |
57 end | |
58 | |
59 local function getline() | |
60 local ok, line = pcall(io.read, "*l"); | |
61 if ok then | |
62 return line; | |
63 end | |
64 end | |
65 | |
66 local function getpass() | |
67 local stty_ret, _, status_code = os.execute("stty -echo 2>/dev/null"); | |
68 if status_code then -- COMPAT w/ Lua 5.1 | |
69 stty_ret = status_code; | |
70 end | |
71 if stty_ret ~= 0 then | |
72 io.write("\027[08m"); -- ANSI 'hidden' text attribute | |
73 end | |
74 local ok, pass = pcall(io.read, "*l"); | |
75 if stty_ret == 0 then | |
76 os.execute("stty sane"); | |
77 else | |
78 io.write("\027[00m"); | |
79 end | |
80 io.write("\n"); | |
81 if ok then | |
82 return pass; | |
83 end | |
84 end | |
85 | |
86 local function show_yesno(prompt) | |
87 io.write(prompt, " "); | |
88 local choice = getchar():lower(); | |
89 io.write("\n"); | |
90 if not choice:match("%a") then | |
91 choice = prompt:match("%[.-(%U).-%]$"); | |
92 if not choice then return nil; end | |
93 end | |
94 return (choice == "y"); | |
95 end | |
96 | |
97 local function read_password() | |
98 local password; | |
99 while true do | |
100 io.write("Enter new password: "); | |
101 password = getpass(); | |
102 if not password then | |
103 show_message("No password - cancelled"); | |
104 return; | |
105 end | |
106 io.write("Retype new password: "); | |
107 if getpass() ~= password then | |
108 if not show_yesno [=[Passwords did not match, try again? [Y/n]]=] then | |
109 return; | |
110 end | |
111 else | |
112 break; | |
113 end | |
114 end | |
115 return password; | |
116 end | |
117 | |
118 local function show_prompt(prompt) | |
119 io.write(prompt, " "); | |
120 local line = getline(); | |
121 line = line and line:gsub("\n$",""); | |
122 return (line and #line > 0) and line or nil; | |
123 end | 62 end |
124 | 63 |
125 -- Server control | 64 -- Server control |
126 local function adduser(params) | 65 local function adduser(params) |
127 local user, host, password = nodeprep(params.user), nameprep(params.host), params.password; | 66 local user, host, password = nodeprep(params.user, true), nameprep(params.host), params.password; |
128 if not user then | 67 if not user then |
129 return false, "invalid-username"; | 68 return false, "invalid-username"; |
130 elseif not host then | 69 elseif not host then |
131 return false, "invalid-hostname"; | 70 return false, "invalid-hostname"; |
132 end | 71 end |
198 local file, err = io.open(pidfile, "r+"); | 137 local file, err = io.open(pidfile, "r+"); |
199 if not file then | 138 if not file then |
200 return false, "pidfile-read-failed", err; | 139 return false, "pidfile-read-failed", err; |
201 end | 140 end |
202 | 141 |
203 local locked, err = lfs.lock(file, "w"); | 142 local locked, err = lfs.lock(file, "w"); -- luacheck: ignore 211/err |
204 if locked then | 143 if locked then |
205 file:close(); | 144 file:close(); |
206 return false, "pidfile-not-locked"; | 145 return false, "pidfile-not-locked"; |
207 end | 146 end |
208 | 147 |
215 | 154 |
216 return true, pid; | 155 return true, pid; |
217 end | 156 end |
218 | 157 |
219 local function isrunning() | 158 local function isrunning() |
220 local ok, pid, err = getpid(); | 159 local ok, pid, err = getpid(); -- luacheck: ignore 211/err |
221 if not ok then | 160 if not ok then |
222 if pid == "pidfile-read-failed" or pid == "pidfile-not-locked" then | 161 if pid == "pidfile-read-failed" or pid == "pidfile-not-locked" then |
223 -- Report as not running, since we can't open the pidfile | 162 -- Report as not running, since we can't open the pidfile |
224 -- (it probably doesn't exist) | 163 -- (it probably doesn't exist) |
225 return true, false; | 164 return true, false; |
227 return ok, pid; | 166 return ok, pid; |
228 end | 167 end |
229 return true, signal.kill(pid, 0) == 0; | 168 return true, signal.kill(pid, 0) == 0; |
230 end | 169 end |
231 | 170 |
232 local function start(source_dir) | 171 local function start(source_dir, lua) |
172 lua = lua and lua .. " " or ""; | |
233 local ok, ret = isrunning(); | 173 local ok, ret = isrunning(); |
234 if not ok then | 174 if not ok then |
235 return ok, ret; | 175 return ok, ret; |
236 end | 176 end |
237 if ret then | 177 if ret then |
238 return false, "already-running"; | 178 return false, "already-running"; |
239 end | 179 end |
240 if not source_dir then | 180 if not source_dir then |
241 os.execute("./prosody -D"); | 181 os.execute(lua .. "./prosody -D"); |
242 else | 182 else |
243 os.execute(source_dir.."/../../bin/prosody -D"); | 183 os.execute(lua .. source_dir.."/../../bin/prosody -D"); |
244 end | 184 end |
245 return true; | 185 return true; |
246 end | 186 end |
247 | 187 |
248 local function stop() | 188 local function stop() |
273 local ok, pid = getpid() | 213 local ok, pid = getpid() |
274 if not ok then return false, pid; end | 214 if not ok then return false, pid; end |
275 | 215 |
276 signal.kill(pid, signal.SIGHUP); | 216 signal.kill(pid, signal.SIGHUP); |
277 return true; | 217 return true; |
218 end | |
219 | |
220 local function get_path_custom_plugins(plugin_paths) | |
221 -- I'm considering that the custom plugins' path is the first one at prosody.paths.plugins | |
222 -- luacheck: ignore 512 | |
223 for path in plugin_paths:gmatch("[^;]+") do | |
224 return path; | |
225 end | |
226 end | |
227 | |
228 local render_cli = interpolation.new("%b{}", function (s) return "'"..s:gsub("'","'\\''").."'" end) | |
229 | |
230 local function call_luarocks(operation, mod, server) | |
231 local dir = get_path_custom_plugins(prosody.paths.plugins); | |
232 if operation == "install" then | |
233 show_message("Installing %s at %s", mod, dir); | |
234 elseif operation == "remove" then | |
235 show_message("Removing %s from %s", mod, dir); | |
236 end | |
237 os.execute(render_cli("luarocks {op} --tree={dir} {server&--server={server}} {mod?}", { | |
238 dir = dir; op = operation; mod = mod; server = server; | |
239 })); | |
240 if operation == "install" then | |
241 show_module_configuration_help(mod); | |
242 end | |
278 end | 243 end |
279 | 244 |
280 return { | 245 return { |
281 show_message = show_message; | 246 show_message = show_message; |
282 show_warning = show_message; | 247 show_warning = show_message; |
283 show_usage = show_usage; | 248 show_usage = show_usage; |
284 getchar = getchar; | 249 show_module_configuration_help = show_module_configuration_help; |
285 getline = getline; | |
286 getpass = getpass; | |
287 show_yesno = show_yesno; | |
288 read_password = read_password; | |
289 show_prompt = show_prompt; | |
290 adduser = adduser; | 250 adduser = adduser; |
291 user_exists = user_exists; | 251 user_exists = user_exists; |
292 passwd = passwd; | 252 passwd = passwd; |
293 deluser = deluser; | 253 deluser = deluser; |
294 getpid = getpid; | 254 getpid = getpid; |
295 isrunning = isrunning; | 255 isrunning = isrunning; |
296 start = start; | 256 start = start; |
297 stop = stop; | 257 stop = stop; |
298 reload = reload; | 258 reload = reload; |
259 get_path_custom_plugins = get_path_custom_plugins; | |
260 call_luarocks = call_luarocks; | |
261 error_messages = error_messages; | |
299 }; | 262 }; |