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