41 if os.getenv("HOME") then |
41 if os.getenv("HOME") then |
42 CFG_DATADIR = CFG_DATADIR:gsub("^~", os.getenv("HOME")); |
42 CFG_DATADIR = CFG_DATADIR:gsub("^~", os.getenv("HOME")); |
43 end |
43 end |
44 end |
44 end |
45 |
45 |
46 -- Global 'prosody' object |
46 ----------- |
47 local prosody = { |
47 |
48 hosts = {}; |
48 require "util.startup".prosodyctl(); |
49 events = require "util.events".new(); |
49 |
50 platform = "posix"; |
50 ----------- |
51 lock_globals = function () end; |
|
52 unlock_globals = function () end; |
|
53 installed = CFG_SOURCEDIR ~= nil; |
|
54 core_post_stanza = function () end; -- TODO: mod_router! |
|
55 }; |
|
56 _G.prosody = prosody; |
|
57 |
|
58 local dependencies = require "util.dependencies"; |
|
59 if not dependencies.check_dependencies() then |
|
60 os.exit(1); |
|
61 end |
|
62 |
|
63 config = require "core.configmanager" |
|
64 |
|
65 local ENV_CONFIG; |
|
66 do |
|
67 local filenames = {}; |
|
68 |
|
69 local filename; |
|
70 if arg[1] == "--config" and arg[2] then |
|
71 table.insert(filenames, arg[2]); |
|
72 if CFG_CONFIGDIR then |
|
73 table.insert(filenames, CFG_CONFIGDIR.."/"..arg[2]); |
|
74 end |
|
75 table.remove(arg, 1); table.remove(arg, 1); |
|
76 else |
|
77 table.insert(filenames, (CFG_CONFIGDIR or ".").."/prosody.cfg.lua"); |
|
78 end |
|
79 for _,_filename in ipairs(filenames) do |
|
80 filename = _filename; |
|
81 local file = io.open(filename); |
|
82 if file then |
|
83 file:close(); |
|
84 ENV_CONFIG = filename; |
|
85 CFG_CONFIGDIR = filename:match("^(.*)[\\/][^\\/]*$"); |
|
86 break; |
|
87 end |
|
88 end |
|
89 local ok, level, err = config.load(filename); |
|
90 if not ok then |
|
91 print("\n"); |
|
92 print("**************************"); |
|
93 if level == "parser" then |
|
94 print("A problem occured while reading the config file "..filename); |
|
95 local err_line, err_message = tostring(err):match("%[string .-%]:(%d*): (.*)"); |
|
96 print("Error"..(err_line and (" on line "..err_line) or "")..": "..(err_message or tostring(err))); |
|
97 print(""); |
|
98 elseif level == "file" then |
|
99 print("Prosody was unable to find the configuration file."); |
|
100 print("We looked for: "..filename); |
|
101 print("A sample config file is included in the Prosody download called prosody.cfg.lua.dist"); |
|
102 print("Copy or rename it to prosody.cfg.lua and edit as necessary."); |
|
103 end |
|
104 print("More help on configuring Prosody can be found at https://prosody.im/doc/configure"); |
|
105 print("Good luck!"); |
|
106 print("**************************"); |
|
107 print(""); |
|
108 os.exit(1); |
|
109 end |
|
110 end |
|
111 local original_logging_config = config.get("*", "log"); |
|
112 config.set("*", "log", { { levels = { min="info" }, to = "console" } }); |
|
113 |
|
114 local data_path = config.get("*", "data_path") or CFG_DATADIR or "data"; |
|
115 local custom_plugin_paths = config.get("*", "plugin_paths"); |
|
116 if custom_plugin_paths then |
|
117 local path_sep = package.config:sub(3,3); |
|
118 -- path1;path2;path3;defaultpath... |
|
119 CFG_PLUGINDIR = table.concat(custom_plugin_paths, path_sep)..path_sep..(CFG_PLUGINDIR or "plugins"); |
|
120 end |
|
121 prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR, |
|
122 plugins = CFG_PLUGINDIR or "plugins", data = data_path }; |
|
123 |
|
124 if prosody.installed then |
|
125 -- Change working directory to data path. |
|
126 require "lfs".chdir(data_path); |
|
127 end |
|
128 |
|
129 require "core.loggingmanager" |
|
130 |
|
131 dependencies.log_warnings(); |
|
132 |
|
133 -- Switch away from root and into the prosody user -- |
|
134 local switched_user, current_uid; |
|
135 |
|
136 local want_pposix_version = "0.4.0"; |
|
137 local have_pposix, pposix = pcall(require, "util.pposix"); |
|
138 |
|
139 if have_pposix and pposix then |
|
140 if pposix._VERSION ~= want_pposix_version then |
|
141 print(string.format("Unknown version (%s) of binary pposix module, expected %s", |
|
142 tostring(pposix._VERSION), want_pposix_version)); return; |
|
143 end |
|
144 current_uid = pposix.getuid(); |
|
145 local arg_root = arg[1] == "--root"; |
|
146 if arg_root then table.remove(arg, 1); end |
|
147 if current_uid == 0 and config.get("*", "run_as_root") ~= true and not arg_root then |
|
148 -- We haz root! |
|
149 local desired_user = config.get("*", "prosody_user") or "prosody"; |
|
150 local desired_group = config.get("*", "prosody_group") or desired_user; |
|
151 local ok, err = pposix.setgid(desired_group); |
|
152 if ok then |
|
153 ok, err = pposix.initgroups(desired_user); |
|
154 end |
|
155 if ok then |
|
156 ok, err = pposix.setuid(desired_user); |
|
157 if ok then |
|
158 -- Yay! |
|
159 switched_user = true; |
|
160 end |
|
161 end |
|
162 if not switched_user then |
|
163 -- Boo! |
|
164 print("Warning: Couldn't switch to Prosody user/group '"..tostring(desired_user).."'/'"..tostring(desired_group).."': "..tostring(err)); |
|
165 else |
|
166 -- Make sure the Prosody user can read the config |
|
167 local conf, err, errno = io.open(ENV_CONFIG); |
|
168 if conf then |
|
169 conf:close(); |
|
170 else |
|
171 print("The config file is not readable by the '"..desired_user.."' user."); |
|
172 print("Prosody will not be able to read it."); |
|
173 print("Error was "..err); |
|
174 os.exit(1); |
|
175 end |
|
176 end |
|
177 end |
|
178 |
|
179 -- Set our umask to protect data files |
|
180 pposix.umask(config.get("*", "umask") or "027"); |
|
181 pposix.setenv("HOME", data_path); |
|
182 pposix.setenv("PROSODY_CONFIG", ENV_CONFIG); |
|
183 else |
|
184 print("Error: Unable to load pposix module. Check that Prosody is installed correctly.") |
|
185 print("For more help send the below error to us through https://prosody.im/discuss"); |
|
186 print(tostring(pposix)) |
|
187 os.exit(1); |
|
188 end |
|
189 |
|
190 local function test_writeable(filename) |
|
191 local f, err = io.open(filename, "a"); |
|
192 if not f then |
|
193 return false, err; |
|
194 end |
|
195 f:close(); |
|
196 return true; |
|
197 end |
|
198 |
|
199 local unwriteable_files = {}; |
|
200 if type(original_logging_config) == "string" and original_logging_config:sub(1,1) ~= "*" then |
|
201 local ok, err = test_writeable(original_logging_config); |
|
202 if not ok then |
|
203 table.insert(unwriteable_files, err); |
|
204 end |
|
205 elseif type(original_logging_config) == "table" then |
|
206 for _, rule in ipairs(original_logging_config) do |
|
207 if rule.filename then |
|
208 local ok, err = test_writeable(rule.filename); |
|
209 if not ok then |
|
210 table.insert(unwriteable_files, err); |
|
211 end |
|
212 end |
|
213 end |
|
214 end |
|
215 |
|
216 if #unwriteable_files > 0 then |
|
217 print("One of more of the Prosody log files are not"); |
|
218 print("writeable, please correct the errors and try"); |
|
219 print("starting prosodyctl again."); |
|
220 print(""); |
|
221 for _, err in ipairs(unwriteable_files) do |
|
222 print(err); |
|
223 end |
|
224 print(""); |
|
225 os.exit(1); |
|
226 end |
|
227 |
|
228 |
51 |
229 local error_messages = setmetatable({ |
52 local error_messages = setmetatable({ |
230 ["invalid-username"] = "The given username is invalid in a Jabber ID"; |
53 ["invalid-username"] = "The given username is invalid in a Jabber ID"; |
231 ["invalid-hostname"] = "The given hostname is invalid"; |
54 ["invalid-hostname"] = "The given hostname is invalid"; |
232 ["no-password"] = "No password was supplied"; |
55 ["no-password"] = "No password was supplied"; |
238 ["no-posix"] = "The mod_posix module is not enabled in the Prosody config file, see https://prosody.im/doc/prosodyctl for more info"; |
61 ["no-posix"] = "The mod_posix module is not enabled in the Prosody config file, see https://prosody.im/doc/prosodyctl for more info"; |
239 ["no-such-method"] = "This module has no commands"; |
62 ["no-such-method"] = "This module has no commands"; |
240 ["not-running"] = "Prosody is not running"; |
63 ["not-running"] = "Prosody is not running"; |
241 }, { __index = function (t,k) return "Error: "..(tostring(k):gsub("%-", " "):gsub("^.", string.upper)); end }); |
64 }, { __index = function (t,k) return "Error: "..(tostring(k):gsub("%-", " "):gsub("^.", string.upper)); end }); |
242 |
65 |
243 hosts = prosody.hosts; |
66 local config = require "core.configmanager"; |
244 |
|
245 local function make_host(hostname) |
|
246 return { |
|
247 type = "local", |
|
248 events = prosody.events, |
|
249 modules = {}, |
|
250 sessions = {}, |
|
251 users = require "core.usermanager".new_null_provider(hostname) |
|
252 }; |
|
253 end |
|
254 |
|
255 for hostname, config in pairs(config.getconfig()) do |
|
256 hosts[hostname] = make_host(hostname); |
|
257 end |
|
258 |
|
259 local modulemanager = require "core.modulemanager" |
67 local modulemanager = require "core.modulemanager" |
260 |
|
261 local prosodyctl = require "util.prosodyctl" |
68 local prosodyctl = require "util.prosodyctl" |
262 local socket = require "socket" |
69 local socket = require "socket" |
263 |
70 local dependencies = require "util.dependencies"; |
264 local http = require "net.http" |
|
265 local config_ssl = config.get("*", "ssl") or {} |
|
266 local https_client = config.get("*", "client_https_ssl") |
|
267 http.default.options.sslctx = require "core.certmanager".create_context("client_https port 0", "client", |
|
268 { capath = config_ssl.capath, cafile = config_ssl.cafile, verify = "peer", }, https_client); |
|
269 |
71 |
270 ----------------------- |
72 ----------------------- |
271 |
|
272 -- FIXME: Duplicate code waiting for util.startup |
|
273 function read_version() |
|
274 -- Try to determine version |
|
275 local version_file = io.open((CFG_SOURCEDIR or ".").."/prosody.version"); |
|
276 prosody.version = "unknown"; |
|
277 if version_file then |
|
278 prosody.version = version_file:read("*a"):gsub("%s*$", ""); |
|
279 version_file:close(); |
|
280 if #prosody.version == 12 and prosody.version:match("^[a-f0-9]+$") then |
|
281 prosody.version = "hg:"..prosody.version; |
|
282 end |
|
283 else |
|
284 local hg = require"util.mercurial"; |
|
285 local hgid = hg.check_id(CFG_SOURCEDIR or "."); |
|
286 if hgid then prosody.version = "hg:" .. hgid; end |
|
287 end |
|
288 end |
|
289 |
73 |
290 local show_message, show_warning = prosodyctl.show_message, prosodyctl.show_warning; |
74 local show_message, show_warning = prosodyctl.show_message, prosodyctl.show_warning; |
291 local show_usage = prosodyctl.show_usage; |
75 local show_usage = prosodyctl.show_usage; |
292 local show_yesno = prosodyctl.show_yesno; |
76 local show_yesno = prosodyctl.show_yesno; |
293 local show_prompt = prosodyctl.show_prompt; |
77 local show_prompt = prosodyctl.show_prompt; |
560 local relpath = config.resolve_relative_path; |
343 local relpath = config.resolve_relative_path; |
561 |
344 |
562 print("Prosody "..(prosody.version or "(unknown version)")); |
345 print("Prosody "..(prosody.version or "(unknown version)")); |
563 print(""); |
346 print(""); |
564 print("# Prosody directories"); |
347 print("# Prosody directories"); |
565 print("Data directory: "..relpath(pwd, data_path)); |
348 print("Data directory: "..relpath(pwd, prosody.paths.data)); |
566 print("Config directory: "..relpath(pwd, CFG_CONFIGDIR or ".")); |
349 print("Config directory: "..relpath(pwd, prosody.paths.config or ".")); |
567 print("Source directory: "..relpath(pwd, CFG_SOURCEDIR or ".")); |
350 print("Source directory: "..relpath(pwd, prosody.paths.source or ".")); |
568 print("Plugin directories:") |
351 print("Plugin directories:") |
569 print(" "..(prosody.paths.plugins:gsub("([^;]+);?", function(path) |
352 print(" "..(prosody.paths.plugins:gsub("([^;]+);?", function(path) |
570 path = config.resolve_relative_path(pwd, path); |
353 path = config.resolve_relative_path(pwd, path); |
571 local hgid, hgrepo = hg.check_id(path); |
354 local hgid, hgrepo = hg.check_id(path); |
572 if not hgid and hgrepo then |
355 if not hgid and hgrepo then |