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