/* Spawn the piped logger process pl->program. */ static apr_status_t piped_log_spawn(piped_log *pl) { apr_procattr_t *procattr; apr_proc_t *procnew = NULL; apr_status_t status; if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) || ((status = apr_procattr_cmdtype_set(procattr, pl->cmdtype)) != APR_SUCCESS) || ((status = apr_procattr_child_in_set(procattr, ap_piped_log_read_fd(pl), ap_piped_log_write_fd(pl))) != APR_SUCCESS) || ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn)) != APR_SUCCESS) || ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) { char buf[120]; /* Something bad happened, give up and go away. */ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "piped_log_spawn: unable to setup child process '%s': %s", pl->program, apr_strerror(status, buf, sizeof(buf))); } else { char **args; const char *pname; apr_file_t *outfile, *errfile; if ((status = apr_file_open_stdout(&outfile, pl->p)) == APR_SUCCESS) status = apr_procattr_child_out_set(procattr, outfile, NULL); if ((status = apr_file_open_stderr(&errfile, pl->p)) == APR_SUCCESS) status = apr_procattr_child_err_set(procattr, errfile, NULL); apr_tokenize_to_argv(pl->program, &args, pl->p); pname = apr_pstrdup(pl->p, args[0]); procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t)); status = apr_proc_create(procnew, pname, (const char * const *) args, NULL, procattr, pl->p); if (status == APR_SUCCESS) { pl->pid = procnew; /* procnew->in was dup2'd from ap_piped_log_write_fd(pl); * since the original fd is still valid, close the copy to * avoid a leak. */ apr_file_close(procnew->in); procnew->in = NULL; apr_proc_other_child_register(procnew, piped_log_maintenance, pl, ap_piped_log_write_fd(pl), pl->p); close_handle_in_child(pl->p, ap_piped_log_read_fd(pl)); } else { char buf[120]; /* Something bad happened, give up and go away. */ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "unable to start piped log program '%s': %s", pl->program, apr_strerror(status, buf, sizeof(buf))); } } return status; }
/* It would be great if we could stress this stuff more, and make the test * more granular. */ static void test_child_kill(abts_case *tc, void *data) { apr_file_t *std = NULL; apr_proc_t newproc; apr_procattr_t *procattr = NULL; const char *args[3]; apr_status_t rv; args[0] = apr_pstrdup(p, "occhild" EXTENSION); args[1] = apr_pstrdup(p, "-X"); args[2] = NULL; rv = apr_procattr_create(&procattr, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_NO_PIPE, APR_NO_PIPE); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); rv = apr_proc_create(&newproc, "./occhild" EXTENSION, args, NULL, procattr, p); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ABTS_PTR_NOTNULL(tc, newproc.in); ABTS_PTR_EQUAL(tc, NULL, newproc.out); ABTS_PTR_EQUAL(tc, NULL, newproc.err); std = newproc.in; apr_proc_other_child_register(&newproc, ocmaint, NULL, std, p); apr_sleep(apr_time_from_sec(1)); rv = apr_proc_kill(&newproc, SIGKILL); ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); /* allow time for things to settle... */ apr_sleep(apr_time_from_sec(3)); apr_proc_other_child_refresh_all(APR_OC_REASON_RUNNING); ABTS_STR_EQUAL(tc, "APR_OC_REASON_DEATH", reasonstr); }
static apr_status_t create_process_manager(server_rec * main_server, apr_pool_t * configpool) { apr_status_t rv; g_process_manager = (apr_proc_t *) apr_pcalloc(configpool, sizeof(*g_process_manager)); rv = apr_proc_fork(g_process_manager, configpool); if (rv == APR_INCHILD) { /* I am the child */ g_pm_pid = getpid(); ap_log_error(APLOG_MARK, APLOG_INFO, 0, main_server, "mod_fcgid: Process manager %" APR_PID_T_FMT " started", getpid()); if ((rv = init_signal(main_server)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server, "mod_fcgid: can't install signal handler, exiting now"); exit(DAEMON_STARTUP_ERROR); } /* If running as root, switch to configured user. * * When running children via suexec, only the effective uid is * switched, so that the PM can return to euid 0 to kill child * processes. * * When running children as the configured user, the real uid * is switched. */ if (ap_unixd_config.suexec_enabled) { if (getuid() != 0) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, main_server, "mod_fcgid: current user is not root while suexec is enabled, exiting now"); exit(DAEMON_STARTUP_ERROR); } suexec_setup_child(); } else ap_unixd_setup_child(); apr_file_pipe_timeout_set(g_pm_read_pipe, apr_time_from_sec(g_wakeup_timeout)); apr_file_close(g_ap_write_pipe); apr_file_close(g_ap_read_pipe); /* Initialize spawn controler */ spawn_control_init(main_server, configpool); pm_main(main_server, configpool); ap_log_error(APLOG_MARK, APLOG_INFO, 0, main_server, "mod_fcgid: Process manager %" APR_PID_T_FMT " stopped", getpid()); exit(0); } else if (rv != APR_INPARENT) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server, "mod_fcgid: Create process manager error"); exit(1); } /* I am the parent I will send the stop signal in procmgr_stop_procmgr() */ apr_pool_note_subprocess(configpool, g_process_manager, APR_KILL_ONLY_ONCE); apr_proc_other_child_register(g_process_manager, fcgid_maint, g_process_manager, NULL, configpool); return APR_SUCCESS; }