xref: /php-src/sapi/fpm/fpm/fpm_unix.c (revision 08b57772)
1 	/* (c) 2007,2008 Andrei Nigmatulin */
2 
3 #include "fpm_config.h"
4 
5 #include <string.h>
6 #include <sys/time.h>
7 #include <sys/resource.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <sys/un.h>
12 #include <pwd.h>
13 #include <grp.h>
14 
15 #ifdef HAVE_PRCTL
16 #include <sys/prctl.h>
17 #endif
18 
19 #ifdef HAVE_PROCCTL
20 #include <sys/procctl.h>
21 #endif
22 
23 #ifdef HAVE_SETPFLAGS
24 #include <priv.h>
25 #endif
26 
27 #ifdef HAVE_APPARMOR
28 #include <sys/apparmor.h>
29 #endif
30 
31 #ifdef HAVE_SYS_ACL_H
32 #include <sys/acl.h>
33 #endif
34 
35 #ifdef HAVE_SELINUX
36 #include <selinux/selinux.h>
37 #endif
38 
39 #include "fpm.h"
40 #include "fpm_conf.h"
41 #include "fpm_cleanup.h"
42 #include "fpm_clock.h"
43 #include "fpm_stdio.h"
44 #include "fpm_unix.h"
45 #include "fpm_signals.h"
46 #include "zlog.h"
47 
48 size_t fpm_pagesize;
49 
50 
fpm_unix_is_id(const char * name)51 static inline bool fpm_unix_is_id(const char* name)
52 {
53 	return strlen(name) == strspn(name, "0123456789");
54 }
55 
fpm_unix_get_passwd(struct fpm_worker_pool_s * wp,const char * name,int flags)56 static struct passwd *fpm_unix_get_passwd(struct fpm_worker_pool_s *wp, const char *name, int flags)
57 {
58 	struct passwd *pwd = getpwnam(name);
59 	if (!pwd) {
60 		zlog(flags, "[pool %s] cannot get uid for user '%s'", wp->config->name, name);
61 		return NULL;
62 	}
63 
64 	return pwd;
65 }
66 
fpm_unix_check_listen_address(struct fpm_worker_pool_s * wp,const char * address,int flags)67 static inline bool fpm_unix_check_listen_address(struct fpm_worker_pool_s *wp, const char *address, int flags)
68 {
69 	if (wp->listen_address_domain != FPM_AF_UNIX) {
70 		return true;
71 	}
72 
73 	struct sockaddr_un test_socket;
74 	size_t address_length = strlen(address);
75 	size_t socket_length = sizeof(test_socket.sun_path);
76 
77 	if (address_length < socket_length) {
78 		return true;
79 	}
80 
81 	zlog(
82 		flags,
83 		"[pool %s] cannot bind to UNIX socket '%s' as path is too long (found length: %zu, "
84 			"maximal length: %zu)",
85 		wp->config->name,
86 		address,
87 		address_length,
88 		socket_length
89 	);
90 
91 	return false;
92 }
93 
fpm_unix_check_passwd(struct fpm_worker_pool_s * wp,const char * name,int flags)94 static inline bool fpm_unix_check_passwd(struct fpm_worker_pool_s *wp, const char *name, int flags)
95 {
96 	return !name || fpm_unix_is_id(name) || fpm_unix_get_passwd(wp, name, flags);
97 }
98 
fpm_unix_get_group(struct fpm_worker_pool_s * wp,const char * name,int flags)99 static struct group *fpm_unix_get_group(struct fpm_worker_pool_s *wp, const char *name, int flags)
100 {
101 	struct group *group = getgrnam(name);
102 	if (!group) {
103 		zlog(flags, "[pool %s] cannot get gid for group '%s'", wp->config->name, name);
104 		return NULL;
105 	}
106 
107 	return group;
108 }
109 
fpm_unix_check_group(struct fpm_worker_pool_s * wp,const char * name,int flags)110 static inline bool fpm_unix_check_group(struct fpm_worker_pool_s *wp, const char *name, int flags)
111 {
112 	return !name || fpm_unix_is_id(name) || fpm_unix_get_group(wp, name, flags);
113 }
114 
fpm_unix_test_config(struct fpm_worker_pool_s * wp)115 bool fpm_unix_test_config(struct fpm_worker_pool_s *wp)
116 {
117 	struct fpm_worker_pool_config_s *config = wp->config;
118 	return (
119 		fpm_unix_check_passwd(wp, config->user, ZLOG_ERROR) &&
120 		fpm_unix_check_group(wp, config->group, ZLOG_ERROR) &&
121 		fpm_unix_check_listen_address(wp, config->listen_address, ZLOG_SYSERROR) &&
122 		fpm_unix_check_passwd(wp, config->listen_owner, ZLOG_SYSERROR) &&
123 		fpm_unix_check_group(wp, config->listen_group, ZLOG_SYSERROR)
124 	);
125 }
126 
fpm_unix_resolve_socket_permissions(struct fpm_worker_pool_s * wp)127 int fpm_unix_resolve_socket_permissions(struct fpm_worker_pool_s *wp) /* {{{ */
128 {
129 	struct fpm_worker_pool_config_s *c = wp->config;
130 #ifdef HAVE_FPM_ACL
131 	int n;
132 
133 	/* uninitialized */
134 	wp->socket_acl  = NULL;
135 #endif
136 	wp->socket_uid = -1;
137 	wp->socket_gid = -1;
138 	wp->socket_mode = 0660;
139 
140 	if (!c) {
141 		return 0;
142 	}
143 
144 	if (c->listen_mode && *c->listen_mode) {
145 		wp->socket_mode = strtoul(c->listen_mode, 0, 8);
146 	}
147 
148 #ifdef HAVE_FPM_ACL
149 	/* count the users and groups configured */
150 	n = 0;
151 	if (c->listen_acl_users && *c->listen_acl_users) {
152 		char *p;
153 		n++;
154 		for (p=strchr(c->listen_acl_users, ',') ; p ; p=strchr(p+1, ',')) {
155 			n++;
156 		}
157 	}
158 	if (c->listen_acl_groups && *c->listen_acl_groups) {
159 		char *p;
160 		n++;
161 		for (p=strchr(c->listen_acl_groups, ',') ; p ; p=strchr(p+1, ',')) {
162 			n++;
163 		}
164 	}
165 	/* if ACL configured */
166 	if (n) {
167 		acl_t acl;
168 		acl_entry_t entry;
169 		acl_permset_t perm;
170 		char *tmp, *p, *end;
171 
172 		acl = acl_init(n);
173 		if (!acl) {
174 			zlog(ZLOG_SYSERROR, "[pool %s] cannot allocate ACL", wp->config->name);
175 			return -1;
176 		}
177 		/* Create USER ACL */
178 		if (c->listen_acl_users && *c->listen_acl_users) {
179 			struct passwd *pwd;
180 
181 			tmp = estrdup(c->listen_acl_users);
182 			for (p=tmp ; p ; p=end) {
183 				if ((end = strchr(p, ','))) {
184 					*end++ = 0;
185 				}
186 				pwd = fpm_unix_get_passwd(wp, p, ZLOG_SYSERROR);
187 				if (pwd) {
188 					zlog(ZLOG_DEBUG, "[pool %s] user '%s' have uid=%d", wp->config->name, p, pwd->pw_uid);
189 				} else {
190 					acl_free(acl);
191 					efree(tmp);
192 					return -1;
193 				}
194 				if (0 > acl_create_entry(&acl, &entry) ||
195 					0 > acl_set_tag_type(entry, ACL_USER) ||
196 					0 > acl_set_qualifier(entry, &pwd->pw_uid) ||
197 					0 > acl_get_permset(entry, &perm) ||
198 					0 > acl_clear_perms (perm) ||
199 					0 > acl_add_perm (perm, ACL_READ) ||
200 					0 > acl_add_perm (perm, ACL_WRITE)) {
201 					zlog(ZLOG_SYSERROR, "[pool %s] cannot create ACL for user '%s'", wp->config->name, p);
202 					acl_free(acl);
203 					efree(tmp);
204 					return -1;
205 				}
206 			}
207 			efree(tmp);
208 		}
209 		/* Create GROUP ACL */
210 		if (c->listen_acl_groups && *c->listen_acl_groups) {
211 			struct group *grp;
212 
213 			tmp = estrdup(c->listen_acl_groups);
214 			for (p=tmp ; p ; p=end) {
215 				if ((end = strchr(p, ','))) {
216 					*end++ = 0;
217 				}
218 				grp = fpm_unix_get_group(wp, p, ZLOG_SYSERROR);
219 				if (grp) {
220 					zlog(ZLOG_DEBUG, "[pool %s] group '%s' have gid=%d", wp->config->name, p, grp->gr_gid);
221 				} else {
222 					acl_free(acl);
223 					efree(tmp);
224 					return -1;
225 				}
226 				if (0 > acl_create_entry(&acl, &entry) ||
227 					0 > acl_set_tag_type(entry, ACL_GROUP) ||
228 					0 > acl_set_qualifier(entry, &grp->gr_gid) ||
229 					0 > acl_get_permset(entry, &perm) ||
230 					0 > acl_clear_perms (perm) ||
231 					0 > acl_add_perm (perm, ACL_READ) ||
232 					0 > acl_add_perm (perm, ACL_WRITE)) {
233 					zlog(ZLOG_SYSERROR, "[pool %s] cannot create ACL for group '%s'", wp->config->name, p);
234 					acl_free(acl);
235 					efree(tmp);
236 					return -1;
237 				}
238 			}
239 			efree(tmp);
240 		}
241 		if (c->listen_owner && *c->listen_owner) {
242 			zlog(ZLOG_WARNING, "[pool %s] ACL set, listen.owner = '%s' is ignored", wp->config->name, c->listen_owner);
243 		}
244 		if (c->listen_group && *c->listen_group) {
245 			zlog(ZLOG_WARNING, "[pool %s] ACL set, listen.group = '%s' is ignored", wp->config->name, c->listen_group);
246 		}
247 		wp->socket_acl  = acl;
248 		return 0;
249 	}
250 	/* When listen.users and listen.groups not configured, continue with standard right */
251 #endif
252 
253 	if (c->listen_owner && *c->listen_owner) {
254 		if (fpm_unix_is_id(c->listen_owner)) {
255 			wp->socket_uid = strtoul(c->listen_owner, 0, 10);
256 		} else {
257 			struct passwd *pwd;
258 
259 			pwd = fpm_unix_get_passwd(wp, c->listen_owner, ZLOG_SYSERROR);
260 			if (!pwd) {
261 				return -1;
262 			}
263 
264 			wp->socket_uid = pwd->pw_uid;
265 			wp->socket_gid = pwd->pw_gid;
266 		}
267 	}
268 
269 	if (c->listen_group && *c->listen_group) {
270 		if (fpm_unix_is_id(c->listen_group)) {
271 			wp->socket_gid = strtoul(c->listen_group, 0, 10);
272 		} else {
273 			struct group *grp;
274 
275 			grp = fpm_unix_get_group(wp, c->listen_group, ZLOG_SYSERROR);
276 			if (!grp) {
277 				return -1;
278 			}
279 			wp->socket_gid = grp->gr_gid;
280 		}
281 	}
282 
283 	return 0;
284 }
285 /* }}} */
286 
fpm_unix_set_socket_permissions(struct fpm_worker_pool_s * wp,const char * path)287 int fpm_unix_set_socket_permissions(struct fpm_worker_pool_s *wp, const char *path) /* {{{ */
288 {
289 #ifdef HAVE_FPM_ACL
290 	if (wp->socket_acl) {
291 		acl_t aclfile, aclconf;
292 		acl_entry_t entryfile, entryconf;
293 		int i;
294 
295 		/* Read the socket ACL */
296 		aclconf = wp->socket_acl;
297 		aclfile = acl_get_file (path, ACL_TYPE_ACCESS);
298 		if (!aclfile) {
299 			zlog(ZLOG_SYSERROR, "[pool %s] failed to read the ACL of the socket '%s'", wp->config->name, path);
300 			return -1;
301 		}
302 		/* Copy the new ACL entry from config */
303 		for (i=ACL_FIRST_ENTRY ; acl_get_entry(aclconf, i, &entryconf) ; i=ACL_NEXT_ENTRY) {
304 			if (0 > acl_create_entry (&aclfile, &entryfile) ||
305 				0 > acl_copy_entry(entryfile, entryconf)) {
306 				zlog(ZLOG_SYSERROR, "[pool %s] failed to add entry to the ACL of the socket '%s'", wp->config->name, path);
307 				acl_free(aclfile);
308 				return -1;
309 			}
310 		}
311 		/* Write the socket ACL */
312 		if (0 > acl_calc_mask (&aclfile) ||
313 			0 > acl_valid (aclfile) ||
314 			0 > acl_set_file (path, ACL_TYPE_ACCESS, aclfile)) {
315 			zlog(ZLOG_SYSERROR, "[pool %s] failed to write the ACL of the socket '%s'", wp->config->name, path);
316 			acl_free(aclfile);
317 			return -1;
318 		} else {
319 			zlog(ZLOG_DEBUG, "[pool %s] ACL of the socket '%s' is set", wp->config->name, path);
320 		}
321 
322 		acl_free(aclfile);
323 		return 0;
324 	}
325 	/* When listen.users and listen.groups not configured, continue with standard right */
326 #endif
327 
328 	if (wp->socket_uid != -1 || wp->socket_gid != -1) {
329 		if (0 > chown(path, wp->socket_uid, wp->socket_gid)) {
330 			zlog(ZLOG_SYSERROR, "[pool %s] failed to chown() the socket '%s'", wp->config->name, wp->config->listen_address);
331 			return -1;
332 		}
333 	}
334 	return 0;
335 }
336 /* }}} */
337 
fpm_unix_free_socket_permissions(struct fpm_worker_pool_s * wp)338 int fpm_unix_free_socket_permissions(struct fpm_worker_pool_s *wp) /* {{{ */
339 {
340 #ifdef HAVE_FPM_ACL
341 	if (wp->socket_acl) {
342 		return acl_free(wp->socket_acl);
343 	}
344 #endif
345 	return 0;
346 }
347 /* }}} */
348 
fpm_unix_conf_wp(struct fpm_worker_pool_s * wp)349 static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */
350 {
351 	struct passwd *pwd;
352 	int is_root = !geteuid();
353 
354 	if (is_root) {
355 		if (wp->config->user && *wp->config->user) {
356 			if (fpm_unix_is_id(wp->config->user)) {
357 				wp->set_uid = strtoul(wp->config->user, 0, 10);
358 				pwd = getpwuid(wp->set_uid);
359 				if (pwd) {
360 					wp->set_gid = pwd->pw_gid;
361 					wp->set_user = strdup(pwd->pw_name);
362 				}
363 			} else {
364 				struct passwd *pwd;
365 
366 				pwd = fpm_unix_get_passwd(wp, wp->config->user, ZLOG_ERROR);
367 				if (!pwd) {
368 					return -1;
369 				}
370 
371 				wp->set_uid = pwd->pw_uid;
372 				wp->set_gid = pwd->pw_gid;
373 
374 				wp->user = strdup(pwd->pw_name);
375 				wp->home = strdup(pwd->pw_dir);
376 			}
377 		}
378 
379 		if (wp->config->group && *wp->config->group) {
380 			if (fpm_unix_is_id(wp->config->group)) {
381 				wp->set_gid = strtoul(wp->config->group, 0, 10);
382 			} else {
383 				struct group *grp;
384 
385 				grp = fpm_unix_get_group(wp, wp->config->group, ZLOG_ERROR);
386 				if (!grp) {
387 					return -1;
388 				}
389 				wp->set_gid = grp->gr_gid;
390 			}
391 		}
392 
393 		if (!fpm_globals.run_as_root) {
394 			if (wp->set_uid == 0 || wp->set_gid == 0) {
395 				zlog(ZLOG_ERROR, "[pool %s] please specify user and group other than root", wp->config->name);
396 				return -1;
397 			}
398 		}
399 	} else { /* not root */
400 		if (wp->config->user && *wp->config->user) {
401 			zlog(ZLOG_NOTICE, "[pool %s] 'user' directive is ignored when FPM is not running as root", wp->config->name);
402 		}
403 		if (wp->config->group && *wp->config->group) {
404 			zlog(ZLOG_NOTICE, "[pool %s] 'group' directive is ignored when FPM is not running as root", wp->config->name);
405 		}
406 		if (wp->config->chroot && *wp->config->chroot) {
407 			zlog(ZLOG_NOTICE, "[pool %s] 'chroot' directive is ignored when FPM is not running as root", wp->config->name);
408 		}
409 		if (wp->config->process_priority != 64) {
410 			zlog(ZLOG_NOTICE, "[pool %s] 'process.priority' directive is ignored when FPM is not running as root", wp->config->name);
411 		}
412 
413 		/* set up HOME and USER anyway */
414 		pwd = getpwuid(getuid());
415 		if (pwd) {
416 			wp->user = strdup(pwd->pw_name);
417 			wp->home = strdup(pwd->pw_dir);
418 		}
419 	}
420 	return 0;
421 }
422 /* }}} */
423 
fpm_unix_init_child(struct fpm_worker_pool_s * wp)424 int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
425 {
426 	int is_root = !geteuid();
427 	int made_chroot = 0;
428 
429 	if (wp->config->rlimit_files) {
430 		struct rlimit r;
431 
432 		r.rlim_max = r.rlim_cur = (rlim_t) wp->config->rlimit_files;
433 
434 		if (0 > setrlimit(RLIMIT_NOFILE, &r)) {
435 			zlog(ZLOG_SYSERROR, "[pool %s] failed to set rlimit_files for this pool. Please check your system limits or decrease rlimit_files. setrlimit(RLIMIT_NOFILE, %d)", wp->config->name, wp->config->rlimit_files);
436 		}
437 	}
438 
439 	if (wp->config->rlimit_core) {
440 		struct rlimit r;
441 
442 		r.rlim_max = r.rlim_cur = wp->config->rlimit_core == -1 ? (rlim_t) RLIM_INFINITY : (rlim_t) wp->config->rlimit_core;
443 
444 		if (0 > setrlimit(RLIMIT_CORE, &r)) {
445 			zlog(ZLOG_SYSERROR, "[pool %s] failed to set rlimit_core for this pool. Please check your system limits or decrease rlimit_core. setrlimit(RLIMIT_CORE, %d)", wp->config->name, wp->config->rlimit_core);
446 		}
447 	}
448 
449 	if (is_root && wp->config->chroot && *wp->config->chroot) {
450 		if (0 > chroot(wp->config->chroot)) {
451 			zlog(ZLOG_SYSERROR, "[pool %s] failed to chroot(%s)",  wp->config->name, wp->config->chroot);
452 			return -1;
453 		}
454 		made_chroot = 1;
455 	}
456 
457 	if (wp->config->chdir && *wp->config->chdir) {
458 		if (0 > chdir(wp->config->chdir)) {
459 			zlog(ZLOG_SYSERROR, "[pool %s] failed to chdir(%s)", wp->config->name, wp->config->chdir);
460 			return -1;
461 		}
462 	} else if (made_chroot) {
463 		if (0 > chdir("/")) {
464 			zlog(ZLOG_WARNING, "[pool %s] failed to chdir(/)", wp->config->name);
465 		}
466 	}
467 
468 	if (is_root) {
469 
470 		if (wp->config->process_priority != 64) {
471 			if (setpriority(PRIO_PROCESS, 0, wp->config->process_priority) < 0) {
472 				zlog(ZLOG_SYSERROR, "[pool %s] Unable to set priority for this new process", wp->config->name);
473 				return -1;
474 			}
475 		}
476 
477 		if (wp->set_gid) {
478 			if (0 > setgid(wp->set_gid)) {
479 				zlog(ZLOG_SYSERROR, "[pool %s] failed to setgid(%d)", wp->config->name, wp->set_gid);
480 				return -1;
481 			}
482 		}
483 		if (wp->set_uid) {
484 			if (0 > initgroups(wp->set_user ? wp->set_user : wp->config->user, wp->set_gid)) {
485 				zlog(ZLOG_SYSERROR, "[pool %s] failed to initgroups(%s, %d)", wp->config->name, wp->config->user, wp->set_gid);
486 				return -1;
487 			}
488 			if (0 > setuid(wp->set_uid)) {
489 				zlog(ZLOG_SYSERROR, "[pool %s] failed to setuid(%d)", wp->config->name, wp->set_uid);
490 				return -1;
491 			}
492 		}
493 	}
494 
495 #ifdef HAVE_PRCTL
496 	if (wp->config->process_dumpable) {
497 		int dumpable = 1;
498 #ifdef HAVE_SELINUX
499 		if (security_get_boolean_active("deny_ptrace") == 1) {
500 			zlog(ZLOG_SYSERROR, "[pool %s] ptrace is denied", wp->config->name);
501 			dumpable = 0;
502 		}
503 #endif
504 		if (dumpable && 0 > prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) {
505 			zlog(ZLOG_SYSERROR, "[pool %s] failed to prctl(PR_SET_DUMPABLE)", wp->config->name);
506 		}
507 	}
508 #endif
509 
510 #ifdef HAVE_PROCCTL
511 	int dumpable = PROC_TRACE_CTL_ENABLE;
512 	if (wp->config->process_dumpable && -1 == procctl(P_PID, getpid(), PROC_TRACE_CTL, &dumpable)) {
513 		zlog(ZLOG_SYSERROR, "[pool %s] failed to procctl(PROC_TRACE_CTL)", wp->config->name);
514 	}
515 #endif
516 
517 #ifdef HAVE_SETPFLAGS
518 	if (wp->config->process_dumpable && 0 > setpflags(__PROC_PROTECT, 0)) {
519 		zlog(ZLOG_SYSERROR, "[pool %s] failed to setpflags(__PROC_PROTECT)", wp->config->name);
520 	}
521 #endif
522 
523 	if (0 > fpm_clock_init()) {
524 		return -1;
525 	}
526 
527 #ifdef HAVE_APPARMOR
528 	if (wp->config->apparmor_hat) {
529 		char *con, *new_con;
530 
531 		if (aa_getcon(&con, NULL) == -1) {
532 			zlog(ZLOG_SYSERROR, "[pool %s] failed to query apparmor confinement. Please check if \"/proc/*/attr/current\" is read and writeable.", wp->config->name);
533 			return -1;
534 		}
535 
536 		new_con = malloc(strlen(con) + strlen(wp->config->apparmor_hat) + 3); // // + 0 Byte
537 		if (!new_con) {
538 			zlog(ZLOG_SYSERROR, "[pool %s] failed to allocate memory for apparmor hat change.", wp->config->name);
539 			free(con);
540 			return -1;
541 		}
542 
543 		if (0 > sprintf(new_con, "%s//%s", con, wp->config->apparmor_hat)) {
544 			zlog(ZLOG_SYSERROR, "[pool %s] failed to construct apparmor confinement.", wp->config->name);
545 			free(con);
546 			free(new_con);
547 			return -1;
548 		}
549 
550 		if (0 > aa_change_profile(new_con)) {
551 			zlog(ZLOG_SYSERROR, "[pool %s] failed to change to new confinement (%s). Please check if \"/proc/*/attr/current\" is read and writeable and \"change_profile -> %s//*\" is allowed.", wp->config->name, new_con, con);
552 			free(con);
553 			free(new_con);
554 			return -1;
555 		}
556 
557 		free(con);
558 		free(new_con);
559 	}
560 #endif
561 
562 	return 0;
563 }
564 /* }}} */
565 
fpm_unix_init_main(void)566 int fpm_unix_init_main(void)
567 {
568 	struct fpm_worker_pool_s *wp;
569 	int is_root = !geteuid();
570 
571 	if (fpm_global_config.rlimit_files) {
572 		struct rlimit r;
573 
574 		r.rlim_max = r.rlim_cur = (rlim_t) fpm_global_config.rlimit_files;
575 
576 		if (0 > setrlimit(RLIMIT_NOFILE, &r)) {
577 			zlog(ZLOG_SYSERROR, "failed to set rlimit_files for this pool. Please check your system limits or decrease rlimit_files. setrlimit(RLIMIT_NOFILE, %d)", fpm_global_config.rlimit_files);
578 			return -1;
579 		}
580 	}
581 
582 	if (fpm_global_config.rlimit_core) {
583 		struct rlimit r;
584 
585 		r.rlim_max = r.rlim_cur = fpm_global_config.rlimit_core == -1 ? (rlim_t) RLIM_INFINITY : (rlim_t) fpm_global_config.rlimit_core;
586 
587 		if (0 > setrlimit(RLIMIT_CORE, &r)) {
588 			zlog(ZLOG_SYSERROR, "failed to set rlimit_core for this pool. Please check your system limits or decrease rlimit_core. setrlimit(RLIMIT_CORE, %d)", fpm_global_config.rlimit_core);
589 			return -1;
590 		}
591 	}
592 
593 	fpm_pagesize = getpagesize();
594 	if (fpm_global_config.daemonize) {
595 		/*
596 		 * If daemonize, the calling process will die soon
597 		 * and the master process continues to initialize itself.
598 		 *
599 		 * The parent process has then to wait for the master
600 		 * process to initialize to return a consistent exit
601 		 * value. For this purpose, the master process will
602 		 * send \"1\" into the pipe if everything went well
603 		 * and \"0\" otherwise.
604 		 */
605 
606 
607 		struct timeval tv;
608 		fd_set rfds;
609 		int ret;
610 
611 		if (pipe(fpm_globals.send_config_pipe) == -1) {
612 			zlog(ZLOG_SYSERROR, "failed to create pipe");
613 			return -1;
614 		}
615 
616 		/* then fork */
617 		pid_t pid = fork();
618 		switch (pid) {
619 
620 			case -1 : /* error */
621 				zlog(ZLOG_SYSERROR, "failed to daemonize");
622 				return -1;
623 
624 			case 0 : /* children */
625 				close(fpm_globals.send_config_pipe[0]); /* close the read side of the pipe */
626 				break;
627 
628 			default : /* parent */
629 				close(fpm_globals.send_config_pipe[1]); /* close the write side of the pipe */
630 
631 				/*
632 				 * wait for 10s before exiting with error
633 				 * the child is supposed to send 1 or 0 into the pipe to tell the parent
634 				 * how it goes for it
635 				 */
636 				FD_ZERO(&rfds);
637 				FD_SET(fpm_globals.send_config_pipe[0], &rfds);
638 
639 				tv.tv_sec = 10;
640 				tv.tv_usec = 0;
641 
642 				zlog(ZLOG_DEBUG, "The calling process is waiting for the master process to ping via fd=%d", fpm_globals.send_config_pipe[0]);
643 				ret = select(fpm_globals.send_config_pipe[0] + 1, &rfds, NULL, NULL, &tv);
644 				if (ret == -1) {
645 					zlog(ZLOG_SYSERROR, "failed to select");
646 					exit(FPM_EXIT_SOFTWARE);
647 				}
648 				if (ret) { /* data available */
649 					int readval;
650 					ret = read(fpm_globals.send_config_pipe[0], &readval, sizeof(readval));
651 					if (ret == -1) {
652 						zlog(ZLOG_SYSERROR, "failed to read from pipe");
653 						exit(FPM_EXIT_SOFTWARE);
654 					}
655 
656 					if (ret == 0) {
657 						zlog(ZLOG_ERROR, "no data have been read from pipe");
658 						exit(FPM_EXIT_SOFTWARE);
659 					} else {
660 						if (readval == 1) {
661 							zlog(ZLOG_DEBUG, "I received a valid acknowledge from the master process, I can exit without error");
662 							fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT);
663 							exit(FPM_EXIT_OK);
664 						} else {
665 							zlog(ZLOG_DEBUG, "The master process returned an error !");
666 							exit(FPM_EXIT_SOFTWARE);
667 						}
668 					}
669 				} else { /* no date sent ! */
670 					zlog(ZLOG_ERROR, "the master process didn't send back its status (via the pipe to the calling process)");
671 				  exit(FPM_EXIT_SOFTWARE);
672 				}
673 				exit(FPM_EXIT_SOFTWARE);
674 		}
675 	}
676 
677 	/* continue as a child */
678 	setsid();
679 	if (0 > fpm_clock_init()) {
680 		return -1;
681 	}
682 
683 	if (fpm_global_config.process_priority != 64) {
684 		if (is_root) {
685 			if (setpriority(PRIO_PROCESS, 0, fpm_global_config.process_priority) < 0) {
686 				zlog(ZLOG_SYSERROR, "Unable to set priority for the master process");
687 				return -1;
688 			}
689 		} else {
690 			zlog(ZLOG_NOTICE, "'process.priority' directive is ignored when FPM is not running as root");
691 		}
692 	}
693 
694 	fpm_globals.parent_pid = getpid();
695 	for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
696 		if (0 > fpm_unix_conf_wp(wp)) {
697 			return -1;
698 		}
699 	}
700 
701 	return 0;
702 }
703