]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2011 New Dream Network | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
f67539c2 | 15 | #include <filesystem> |
f67539c2 | 16 | #include "common/async/context_pool.h" |
7c673cae FG |
17 | #include "common/ceph_argparse.h" |
18 | #include "common/code_environment.h" | |
19 | #include "common/config.h" | |
20 | #include "common/debug.h" | |
21 | #include "common/errno.h" | |
22 | #include "common/signal.h" | |
23 | #include "common/version.h" | |
24 | #include "erasure-code/ErasureCodePlugin.h" | |
25 | #include "global/global_context.h" | |
26 | #include "global/global_init.h" | |
27 | #include "global/pidfile.h" | |
28 | #include "global/signal_handler.h" | |
29 | #include "include/compat.h" | |
30 | #include "include/str_list.h" | |
11fdf7f2 | 31 | #include "mon/MonClient.h" |
7c673cae | 32 | |
f67539c2 | 33 | #ifndef _WIN32 |
7c673cae FG |
34 | #include <pwd.h> |
35 | #include <grp.h> | |
f67539c2 | 36 | #endif |
7c673cae FG |
37 | #include <errno.h> |
38 | ||
39 | #ifdef HAVE_SYS_PRCTL_H | |
40 | #include <sys/prctl.h> | |
41 | #endif | |
42 | ||
43 | #define dout_context g_ceph_context | |
44 | #define dout_subsys ceph_subsys_ | |
f67539c2 | 45 | |
20effc67 TL |
46 | namespace fs = std::filesystem; |
47 | ||
f67539c2 TL |
48 | using std::cerr; |
49 | using std::string; | |
50 | ||
7c673cae FG |
51 | static void global_init_set_globals(CephContext *cct) |
52 | { | |
53 | g_ceph_context = cct; | |
11fdf7f2 | 54 | get_process_name(g_process_name, sizeof(g_process_name)); |
7c673cae FG |
55 | } |
56 | ||
57 | static void output_ceph_version() | |
58 | { | |
59 | char buf[1024]; | |
60 | snprintf(buf, sizeof(buf), "%s, process %s, pid %d", | |
61 | pretty_version_to_str().c_str(), | |
62 | get_process_name_cpp().c_str(), getpid()); | |
63 | generic_dout(0) << buf << dendl; | |
64 | } | |
65 | ||
66 | static const char* c_str_or_null(const std::string &str) | |
67 | { | |
68 | if (str.empty()) | |
69 | return NULL; | |
70 | return str.c_str(); | |
71 | } | |
72 | ||
73 | static int chown_path(const std::string &pathname, const uid_t owner, const gid_t group, | |
74 | const std::string &uid_str, const std::string &gid_str) | |
75 | { | |
f67539c2 TL |
76 | #ifdef _WIN32 |
77 | return 0; | |
78 | #else | |
79 | ||
7c673cae FG |
80 | const char *pathname_cstr = c_str_or_null(pathname); |
81 | ||
82 | if (!pathname_cstr) { | |
83 | return 0; | |
84 | } | |
85 | ||
86 | int r = ::chown(pathname_cstr, owner, group); | |
87 | ||
88 | if (r < 0) { | |
89 | r = -errno; | |
90 | cerr << "warning: unable to chown() " << pathname << " as " | |
91 | << uid_str << ":" << gid_str << ": " << cpp_strerror(r) << std::endl; | |
92 | } | |
93 | ||
94 | return r; | |
f67539c2 | 95 | #endif |
7c673cae FG |
96 | } |
97 | ||
11fdf7f2 TL |
98 | void global_pre_init( |
99 | const std::map<std::string,std::string> *defaults, | |
100 | std::vector < const char* >& args, | |
101 | uint32_t module_type, code_environment_t code_env, | |
102 | int flags) | |
7c673cae FG |
103 | { |
104 | std::string conf_file_list; | |
105 | std::string cluster = ""; | |
11fdf7f2 | 106 | |
9f95a23c TL |
107 | // ensure environment arguments are included in early processing |
108 | env_to_vec(args); | |
109 | ||
11fdf7f2 TL |
110 | CephInitParameters iparams = ceph_argparse_early_args( |
111 | args, module_type, | |
112 | &cluster, &conf_file_list); | |
113 | ||
b32b8144 | 114 | CephContext *cct = common_preinit(iparams, code_env, flags); |
7c673cae FG |
115 | cct->_conf->cluster = cluster; |
116 | global_init_set_globals(cct); | |
11fdf7f2 | 117 | auto& conf = cct->_conf; |
7c673cae | 118 | |
11fdf7f2 TL |
119 | if (flags & (CINIT_FLAG_NO_DEFAULT_CONFIG_FILE| |
120 | CINIT_FLAG_NO_MON_CONFIG)) { | |
121 | conf->no_mon_config = true; | |
122 | } | |
123 | ||
124 | // alternate defaults | |
125 | if (defaults) { | |
126 | for (auto& i : *defaults) { | |
127 | conf.set_val_default(i.first, i.second); | |
128 | } | |
129 | } | |
7c673cae | 130 | |
9f95a23c TL |
131 | if (conf.get_val<bool>("no_config_file")) { |
132 | flags |= CINIT_FLAG_NO_DEFAULT_CONFIG_FILE; | |
133 | } | |
134 | ||
11fdf7f2 TL |
135 | int ret = conf.parse_config_files(c_str_or_null(conf_file_list), |
136 | &cerr, flags); | |
7c673cae | 137 | if (ret == -EDOM) { |
11fdf7f2 TL |
138 | cct->_log->flush(); |
139 | cerr << "global_init: error parsing config file." << std::endl; | |
7c673cae FG |
140 | _exit(1); |
141 | } | |
142 | else if (ret == -ENOENT) { | |
143 | if (!(flags & CINIT_FLAG_NO_DEFAULT_CONFIG_FILE)) { | |
144 | if (conf_file_list.length()) { | |
11fdf7f2 TL |
145 | cct->_log->flush(); |
146 | cerr << "global_init: unable to open config file from search list " | |
147 | << conf_file_list << std::endl; | |
7c673cae FG |
148 | _exit(1); |
149 | } else { | |
9f95a23c TL |
150 | cerr << "did not load config file, using default settings." |
151 | << std::endl; | |
7c673cae FG |
152 | } |
153 | } | |
154 | } | |
155 | else if (ret) { | |
11fdf7f2 | 156 | cct->_log->flush(); |
f67539c2 TL |
157 | cerr << "global_init: error reading config file. " |
158 | << conf.get_parse_error() << std::endl; | |
7c673cae FG |
159 | _exit(1); |
160 | } | |
161 | ||
11fdf7f2 TL |
162 | // environment variables override (CEPH_ARGS, CEPH_KEYRING) |
163 | conf.parse_env(cct->get_module_type()); | |
164 | ||
165 | // command line (as passed by caller) | |
166 | conf.parse_argv(args); | |
7c673cae | 167 | |
11fdf7f2 TL |
168 | if (!cct->_log->is_started()) { |
169 | cct->_log->start(); | |
170 | } | |
171 | ||
172 | // do the --show-config[-val], if present in argv | |
173 | conf.do_argv_commands(); | |
7c673cae FG |
174 | |
175 | // Now we're ready to complain about config file parse errors | |
9f95a23c | 176 | g_conf().complain_about_parse_error(g_ceph_context); |
7c673cae FG |
177 | } |
178 | ||
179 | boost::intrusive_ptr<CephContext> | |
11fdf7f2 | 180 | global_init(const std::map<std::string,std::string> *defaults, |
7c673cae FG |
181 | std::vector < const char* >& args, |
182 | uint32_t module_type, code_environment_t code_env, | |
f67539c2 | 183 | int flags, bool run_pre_init) |
7c673cae FG |
184 | { |
185 | // Ensure we're not calling the global init functions multiple times. | |
186 | static bool first_run = true; | |
187 | if (run_pre_init) { | |
188 | // We will run pre_init from here (default). | |
11fdf7f2 TL |
189 | ceph_assert(!g_ceph_context && first_run); |
190 | global_pre_init(defaults, args, module_type, code_env, flags); | |
7c673cae FG |
191 | } else { |
192 | // Caller should have invoked pre_init manually. | |
11fdf7f2 | 193 | ceph_assert(g_ceph_context && first_run); |
7c673cae FG |
194 | } |
195 | first_run = false; | |
196 | ||
197 | // Verify flags have not changed if global_pre_init() has been called | |
198 | // manually. If they have, update them. | |
199 | if (g_ceph_context->get_init_flags() != flags) { | |
200 | g_ceph_context->set_init_flags(flags); | |
201 | } | |
202 | ||
f67539c2 | 203 | #ifndef _WIN32 |
7c673cae FG |
204 | // signal stuff |
205 | int siglist[] = { SIGPIPE, 0 }; | |
206 | block_signals(siglist, NULL); | |
f67539c2 | 207 | #endif |
7c673cae | 208 | |
11fdf7f2 | 209 | if (g_conf()->fatal_signal_handlers) { |
7c673cae | 210 | install_standard_sighandlers(); |
11fdf7f2 | 211 | } |
f67539c2 | 212 | ceph::register_assert_context(g_ceph_context); |
7c673cae | 213 | |
11fdf7f2 | 214 | if (g_conf()->log_flush_on_exit) |
7c673cae FG |
215 | g_ceph_context->_log->set_flush_on_exit(); |
216 | ||
217 | // drop privileges? | |
20effc67 | 218 | std::ostringstream priv_ss; |
f67539c2 TL |
219 | |
220 | #ifndef _WIN32 | |
7c673cae FG |
221 | // consider --setuser root a no-op, even if we're not root |
222 | if (getuid() != 0) { | |
11fdf7f2 TL |
223 | if (g_conf()->setuser.length()) { |
224 | cerr << "ignoring --setuser " << g_conf()->setuser << " since I am not root" | |
7c673cae FG |
225 | << std::endl; |
226 | } | |
11fdf7f2 TL |
227 | if (g_conf()->setgroup.length()) { |
228 | cerr << "ignoring --setgroup " << g_conf()->setgroup | |
7c673cae FG |
229 | << " since I am not root" << std::endl; |
230 | } | |
11fdf7f2 TL |
231 | } else if (g_conf()->setgroup.length() || |
232 | g_conf()->setuser.length()) { | |
7c673cae FG |
233 | uid_t uid = 0; // zero means no change; we can only drop privs here. |
234 | gid_t gid = 0; | |
235 | std::string uid_string; | |
236 | std::string gid_string; | |
eafe8130 | 237 | std::string home_directory; |
11fdf7f2 | 238 | if (g_conf()->setuser.length()) { |
eafe8130 TL |
239 | char buf[4096]; |
240 | struct passwd pa; | |
241 | struct passwd *p = 0; | |
242 | ||
11fdf7f2 | 243 | uid = atoi(g_conf()->setuser.c_str()); |
eafe8130 TL |
244 | if (uid) { |
245 | getpwuid_r(uid, &pa, buf, sizeof(buf), &p); | |
246 | } else { | |
11fdf7f2 | 247 | getpwnam_r(g_conf()->setuser.c_str(), &pa, buf, sizeof(buf), &p); |
eafe8130 | 248 | if (!p) { |
11fdf7f2 | 249 | cerr << "unable to look up user '" << g_conf()->setuser << "'" |
7c673cae FG |
250 | << std::endl; |
251 | exit(1); | |
eafe8130 TL |
252 | } |
253 | ||
254 | uid = p->pw_uid; | |
255 | gid = p->pw_gid; | |
256 | uid_string = g_conf()->setuser; | |
257 | } | |
258 | ||
259 | if (p && p->pw_dir != nullptr) { | |
260 | home_directory = std::string(p->pw_dir); | |
7c673cae FG |
261 | } |
262 | } | |
11fdf7f2 TL |
263 | if (g_conf()->setgroup.length() > 0) { |
264 | gid = atoi(g_conf()->setgroup.c_str()); | |
7c673cae FG |
265 | if (!gid) { |
266 | char buf[4096]; | |
267 | struct group gr; | |
268 | struct group *g = 0; | |
11fdf7f2 | 269 | getgrnam_r(g_conf()->setgroup.c_str(), &gr, buf, sizeof(buf), &g); |
7c673cae | 270 | if (!g) { |
11fdf7f2 | 271 | cerr << "unable to look up group '" << g_conf()->setgroup << "'" |
7c673cae FG |
272 | << ": " << cpp_strerror(errno) << std::endl; |
273 | exit(1); | |
274 | } | |
275 | gid = g->gr_gid; | |
11fdf7f2 | 276 | gid_string = g_conf()->setgroup; |
7c673cae FG |
277 | } |
278 | } | |
279 | if ((uid || gid) && | |
11fdf7f2 | 280 | g_conf()->setuser_match_path.length()) { |
7c673cae | 281 | // induce early expansion of setuser_match_path config option |
11fdf7f2 TL |
282 | string match_path = g_conf()->setuser_match_path; |
283 | g_conf().early_expand_meta(match_path, &cerr); | |
7c673cae FG |
284 | struct stat st; |
285 | int r = ::stat(match_path.c_str(), &st); | |
286 | if (r < 0) { | |
287 | cerr << "unable to stat setuser_match_path " | |
11fdf7f2 | 288 | << g_conf()->setuser_match_path |
7c673cae FG |
289 | << ": " << cpp_strerror(errno) << std::endl; |
290 | exit(1); | |
291 | } | |
292 | if ((uid && uid != st.st_uid) || | |
293 | (gid && gid != st.st_gid)) { | |
294 | cerr << "WARNING: will not setuid/gid: " << match_path | |
295 | << " owned by " << st.st_uid << ":" << st.st_gid | |
296 | << " and not requested " << uid << ":" << gid | |
297 | << std::endl; | |
298 | uid = 0; | |
299 | gid = 0; | |
300 | uid_string.erase(); | |
301 | gid_string.erase(); | |
302 | } else { | |
303 | priv_ss << "setuser_match_path " | |
304 | << match_path << " owned by " | |
305 | << st.st_uid << ":" << st.st_gid << ". "; | |
306 | } | |
307 | } | |
308 | g_ceph_context->set_uid_gid(uid, gid); | |
309 | g_ceph_context->set_uid_gid_strings(uid_string, gid_string); | |
310 | if ((flags & CINIT_FLAG_DEFER_DROP_PRIVILEGES) == 0) { | |
311 | if (setgid(gid) != 0) { | |
312 | cerr << "unable to setgid " << gid << ": " << cpp_strerror(errno) | |
313 | << std::endl; | |
314 | exit(1); | |
315 | } | |
316 | if (setuid(uid) != 0) { | |
317 | cerr << "unable to setuid " << uid << ": " << cpp_strerror(errno) | |
318 | << std::endl; | |
319 | exit(1); | |
320 | } | |
eafe8130 TL |
321 | if (setenv("HOME", home_directory.c_str(), 1) != 0) { |
322 | cerr << "warning: unable to set HOME to " << home_directory << ": " | |
323 | << cpp_strerror(errno) << std::endl; | |
324 | } | |
7c673cae FG |
325 | priv_ss << "set uid:gid to " << uid << ":" << gid << " (" << uid_string << ":" << gid_string << ")"; |
326 | } else { | |
327 | priv_ss << "deferred set uid:gid to " << uid << ":" << gid << " (" << uid_string << ":" << gid_string << ")"; | |
328 | } | |
329 | } | |
f67539c2 | 330 | #endif /* _WIN32 */ |
7c673cae FG |
331 | |
332 | #if defined(HAVE_SYS_PRCTL_H) | |
333 | if (prctl(PR_SET_DUMPABLE, 1) == -1) { | |
334 | cerr << "warning: unable to set dumpable flag: " << cpp_strerror(errno) << std::endl; | |
335 | } | |
92f5a8d4 TL |
336 | # if defined(PR_SET_THP_DISABLE) |
337 | if (!g_conf().get_val<bool>("thp") && prctl(PR_SET_THP_DISABLE, 1, 0, 0, 0) == -1) { | |
338 | cerr << "warning: unable to disable THP: " << cpp_strerror(errno) << std::endl; | |
339 | } | |
340 | # endif | |
7c673cae FG |
341 | #endif |
342 | ||
9f95a23c TL |
343 | // |
344 | // Utterly important to run first network connection after setuid(). | |
345 | // In case of rdma transport uverbs kernel module starts returning | |
346 | // -EACCESS on each operation if credentials has been changed, see | |
347 | // callers of ib_safe_file_access() for details. | |
348 | // | |
349 | // fork() syscall also matters, so daemonization won't work in case | |
350 | // of rdma. | |
351 | // | |
352 | if (!g_conf()->no_mon_config) { | |
353 | // make sure our mini-session gets legacy values | |
354 | g_conf().apply_changes(nullptr); | |
355 | ||
f67539c2 TL |
356 | ceph::async::io_context_pool cp(1); |
357 | MonClient mc_bootstrap(g_ceph_context, cp); | |
9f95a23c | 358 | if (mc_bootstrap.get_monmap_and_config() < 0) { |
f67539c2 | 359 | cp.stop(); |
9f95a23c TL |
360 | g_ceph_context->_log->flush(); |
361 | cerr << "failed to fetch mon config (--no-mon-config to skip)" | |
362 | << std::endl; | |
363 | _exit(1); | |
364 | } | |
f67539c2 | 365 | cp.stop(); |
9f95a23c TL |
366 | } |
367 | ||
7c673cae | 368 | // Expand metavariables. Invoke configuration observers. Open log file. |
11fdf7f2 | 369 | g_conf().apply_changes(nullptr); |
7c673cae | 370 | |
11fdf7f2 | 371 | if (g_conf()->run_dir.length() && |
7c673cae FG |
372 | code_env == CODE_ENVIRONMENT_DAEMON && |
373 | !(flags & CINIT_FLAG_NO_DAEMON_ACTIONS)) { | |
f67539c2 TL |
374 | |
375 | if (!fs::exists(g_conf()->run_dir.c_str())) { | |
376 | std::error_code ec; | |
377 | if (!fs::create_directory(g_conf()->run_dir, ec)) { | |
378 | cerr << "warning: unable to create " << g_conf()->run_dir | |
379 | << ec.message() << std::endl; | |
380 | } | |
381 | fs::permissions( | |
382 | g_conf()->run_dir.c_str(), | |
383 | fs::perms::owner_all | | |
384 | fs::perms::group_read | fs::perms::group_exec | | |
385 | fs::perms::others_read | fs::perms::others_exec); | |
7c673cae FG |
386 | } |
387 | } | |
388 | ||
7c673cae FG |
389 | // call all observers now. this has the side-effect of configuring |
390 | // and opening the log file immediately. | |
11fdf7f2 | 391 | g_conf().call_all_observers(); |
7c673cae FG |
392 | |
393 | if (priv_ss.str().length()) { | |
394 | dout(0) << priv_ss.str() << dendl; | |
395 | } | |
396 | ||
397 | if ((flags & CINIT_FLAG_DEFER_DROP_PRIVILEGES) && | |
398 | (g_ceph_context->get_set_uid() || g_ceph_context->get_set_gid())) { | |
399 | // Fix ownership on log files and run directories if needed. | |
400 | // Admin socket files are chown()'d during the common init path _after_ | |
401 | // the service thread has been started. This is sadly a bit of a hack :( | |
11fdf7f2 | 402 | chown_path(g_conf()->run_dir, |
7c673cae FG |
403 | g_ceph_context->get_set_uid(), |
404 | g_ceph_context->get_set_gid(), | |
405 | g_ceph_context->get_set_uid_string(), | |
406 | g_ceph_context->get_set_gid_string()); | |
407 | g_ceph_context->_log->chown_log_file( | |
408 | g_ceph_context->get_set_uid(), | |
409 | g_ceph_context->get_set_gid()); | |
410 | } | |
411 | ||
412 | // Now we're ready to complain about config file parse errors | |
9f95a23c | 413 | g_conf().complain_about_parse_error(g_ceph_context); |
7c673cae FG |
414 | |
415 | // test leak checking | |
11fdf7f2 | 416 | if (g_conf()->debug_deliberately_leak_memory) { |
7c673cae FG |
417 | derr << "deliberately leaking some memory" << dendl; |
418 | char *s = new char[1234567]; | |
419 | (void)s; | |
420 | // cppcheck-suppress memleak | |
421 | } | |
422 | ||
423 | if (code_env == CODE_ENVIRONMENT_DAEMON && !(flags & CINIT_FLAG_NO_DAEMON_ACTIONS)) | |
424 | output_ceph_version(); | |
425 | ||
426 | if (g_ceph_context->crush_location.init_on_startup()) { | |
427 | cerr << " failed to init_on_startup : " << cpp_strerror(errno) << std::endl; | |
428 | exit(1); | |
429 | } | |
430 | ||
431 | return boost::intrusive_ptr<CephContext>{g_ceph_context, false}; | |
432 | } | |
7c673cae | 433 | |
7c673cae FG |
434 | void global_print_banner(void) |
435 | { | |
436 | output_ceph_version(); | |
437 | } | |
438 | ||
439 | int global_init_prefork(CephContext *cct) | |
440 | { | |
441 | if (g_code_env != CODE_ENVIRONMENT_DAEMON) | |
442 | return -1; | |
443 | ||
11fdf7f2 | 444 | const auto& conf = cct->_conf; |
7c673cae FG |
445 | if (!conf->daemonize) { |
446 | ||
9f95a23c | 447 | if (pidfile_write(conf->pid_file) < 0) |
7c673cae FG |
448 | exit(1); |
449 | ||
450 | if ((cct->get_init_flags() & CINIT_FLAG_DEFER_DROP_PRIVILEGES) && | |
451 | (cct->get_set_uid() || cct->get_set_gid())) { | |
452 | chown_path(conf->pid_file, cct->get_set_uid(), cct->get_set_gid(), | |
453 | cct->get_set_uid_string(), cct->get_set_gid_string()); | |
454 | } | |
455 | ||
456 | return -1; | |
457 | } | |
458 | ||
459 | cct->notify_pre_fork(); | |
460 | // stop log thread | |
461 | cct->_log->flush(); | |
462 | cct->_log->stop(); | |
463 | return 0; | |
464 | } | |
465 | ||
466 | void global_init_daemonize(CephContext *cct) | |
467 | { | |
468 | if (global_init_prefork(cct) < 0) | |
469 | return; | |
470 | ||
f67539c2 | 471 | #if !defined(_AIX) && !defined(_WIN32) |
7c673cae FG |
472 | int ret = daemon(1, 1); |
473 | if (ret) { | |
474 | ret = errno; | |
475 | derr << "global_init_daemonize: BUG: daemon error: " | |
476 | << cpp_strerror(ret) << dendl; | |
477 | exit(1); | |
478 | } | |
479 | ||
480 | global_init_postfork_start(cct); | |
481 | global_init_postfork_finish(cct); | |
482 | #else | |
483 | # warning daemon not supported on aix | |
484 | #endif | |
485 | } | |
486 | ||
1adf2230 AA |
487 | int reopen_as_null(CephContext *cct, int fd) |
488 | { | |
f67539c2 | 489 | int newfd = open(DEV_NULL, O_RDONLY | O_CLOEXEC); |
1adf2230 AA |
490 | if (newfd < 0) { |
491 | int err = errno; | |
492 | lderr(cct) << __func__ << " failed to open /dev/null: " << cpp_strerror(err) | |
493 | << dendl; | |
494 | return -1; | |
495 | } | |
496 | // atomically dup newfd to target fd. target fd is implicitly closed if | |
497 | // open and atomically replaced; see man dup2 | |
498 | int r = dup2(newfd, fd); | |
499 | if (r < 0) { | |
500 | int err = errno; | |
501 | lderr(cct) << __func__ << " failed to dup2 " << fd << ": " | |
502 | << cpp_strerror(err) << dendl; | |
503 | return -1; | |
504 | } | |
505 | // close newfd (we cloned it to target fd) | |
506 | VOID_TEMP_FAILURE_RETRY(close(newfd)); | |
91327a77 | 507 | // N.B. FD_CLOEXEC is cleared on fd (see dup2(2)) |
1adf2230 AA |
508 | return 0; |
509 | } | |
510 | ||
7c673cae FG |
511 | void global_init_postfork_start(CephContext *cct) |
512 | { | |
adb31ebb TL |
513 | // reexpand the meta in child process |
514 | cct->_conf.finalize_reexpand_meta(); | |
515 | ||
7c673cae FG |
516 | // restart log thread |
517 | cct->_log->start(); | |
518 | cct->notify_post_fork(); | |
519 | ||
520 | /* This is the old trick where we make file descriptors 0, 1, and possibly 2 | |
521 | * point to /dev/null. | |
522 | * | |
523 | * We have to do this because otherwise some arbitrary call to open() later | |
524 | * in the program might get back one of these file descriptors. It's hard to | |
525 | * guarantee that nobody ever writes to stdout, even though they're not | |
526 | * supposed to. | |
527 | */ | |
1adf2230 | 528 | reopen_as_null(cct, STDIN_FILENO); |
7c673cae | 529 | |
11fdf7f2 | 530 | const auto& conf = cct->_conf; |
9f95a23c | 531 | if (pidfile_write(conf->pid_file) < 0) |
7c673cae FG |
532 | exit(1); |
533 | ||
534 | if ((cct->get_init_flags() & CINIT_FLAG_DEFER_DROP_PRIVILEGES) && | |
535 | (cct->get_set_uid() || cct->get_set_gid())) { | |
536 | chown_path(conf->pid_file, cct->get_set_uid(), cct->get_set_gid(), | |
537 | cct->get_set_uid_string(), cct->get_set_gid_string()); | |
538 | } | |
539 | } | |
540 | ||
541 | void global_init_postfork_finish(CephContext *cct) | |
542 | { | |
28e407b8 AA |
543 | /* We only close stdout+stderr once the caller decides the daemonization |
544 | * process is finished. This way we can allow error or other messages to be | |
7c673cae FG |
545 | * propagated in a manner that the user is able to see. |
546 | */ | |
547 | if (!(cct->get_init_flags() & CINIT_FLAG_NO_CLOSE_STDERR)) { | |
548 | int ret = global_init_shutdown_stderr(cct); | |
549 | if (ret) { | |
550 | derr << "global_init_daemonize: global_init_shutdown_stderr failed with " | |
551 | << "error code " << ret << dendl; | |
552 | exit(1); | |
553 | } | |
554 | } | |
28e407b8 | 555 | |
1adf2230 | 556 | reopen_as_null(cct, STDOUT_FILENO); |
28e407b8 | 557 | |
7c673cae FG |
558 | ldout(cct, 1) << "finished global_init_daemonize" << dendl; |
559 | } | |
560 | ||
561 | ||
562 | void global_init_chdir(const CephContext *cct) | |
563 | { | |
11fdf7f2 | 564 | const auto& conf = cct->_conf; |
7c673cae FG |
565 | if (conf->chdir.empty()) |
566 | return; | |
567 | if (::chdir(conf->chdir.c_str())) { | |
568 | int err = errno; | |
569 | derr << "global_init_chdir: failed to chdir to directory: '" | |
570 | << conf->chdir << "': " << cpp_strerror(err) << dendl; | |
571 | } | |
572 | } | |
573 | ||
574 | /* Map stderr to /dev/null. This isn't really re-entrant; we rely on the old unix | |
575 | * behavior that the file descriptor that gets assigned is the lowest | |
576 | * available one. | |
577 | */ | |
578 | int global_init_shutdown_stderr(CephContext *cct) | |
579 | { | |
1adf2230 | 580 | reopen_as_null(cct, STDERR_FILENO); |
11fdf7f2 TL |
581 | int l = cct->_conf->err_to_stderr ? -1 : -2; |
582 | cct->_log->set_stderr_level(l, l); | |
7c673cae FG |
583 | return 0; |
584 | } | |
585 | ||
586 | int global_init_preload_erasure_code(const CephContext *cct) | |
587 | { | |
11fdf7f2 | 588 | const auto& conf = cct->_conf; |
7c673cae FG |
589 | string plugins = conf->osd_erasure_code_plugins; |
590 | ||
591 | // validate that this is a not a legacy plugin | |
f67539c2 | 592 | std::list<string> plugins_list; |
7c673cae | 593 | get_str_list(plugins, plugins_list); |
f67539c2 | 594 | for (auto i = plugins_list.begin(); i != plugins_list.end(); ++i) { |
7c673cae FG |
595 | string plugin_name = *i; |
596 | string replacement = ""; | |
597 | ||
598 | if (plugin_name == "jerasure_generic" || | |
599 | plugin_name == "jerasure_sse3" || | |
600 | plugin_name == "jerasure_sse4" || | |
601 | plugin_name == "jerasure_neon") { | |
602 | replacement = "jerasure"; | |
603 | } | |
604 | else if (plugin_name == "shec_generic" || | |
605 | plugin_name == "shec_sse3" || | |
606 | plugin_name == "shec_sse4" || | |
607 | plugin_name == "shec_neon") { | |
608 | replacement = "shec"; | |
609 | } | |
610 | ||
611 | if (replacement != "") { | |
612 | dout(0) << "WARNING: osd_erasure_code_plugins contains plugin " | |
613 | << plugin_name << " that is now deprecated. Please modify the value " | |
614 | << "for osd_erasure_code_plugins to use " << replacement << " instead." << dendl; | |
615 | } | |
616 | } | |
617 | ||
f67539c2 TL |
618 | std::stringstream ss; |
619 | int r = ceph::ErasureCodePluginRegistry::instance().preload( | |
7c673cae | 620 | plugins, |
11fdf7f2 | 621 | conf.get_val<std::string>("erasure_code_dir"), |
7c673cae FG |
622 | &ss); |
623 | if (r) | |
624 | derr << ss.str() << dendl; | |
625 | else | |
626 | dout(0) << ss.str() << dendl; | |
627 | return r; | |
628 | } |