cgi出现coredump后,lighttpd不能拉动cgi重启。
- /*! cgi简单实现 */
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- int main(int argc, const char *argv)
- {
- while (1) {
- FCGX_Request request = {0};
- FCGX_InitRequest(&request, 0, 0);
- FCGX_Accept_r(&request);
- system("sleep 100000000");
- FCGX_Finish_r(&request);
- }
-
- return 0;
- }
- # 运行lighttpd,此处将worker线程配置为4个
- /smbdir/third_party/sbin/lighttpd -f /smbdir/third_party/lighttpd/etc/lighttpd.conf -D
-
- # 手动kill掉cgi会出现cgi不能正常启动的问题
- killall -11 cgi
lighttpd利用mod_facgi模块实现与cgi的交互,而cgi利用标准输入与lighttpd之间的信息互通,当在cgi中执行shell命令时,子进程会继承父进程的一些属性(标准输入也会被继承)。
- gw_fd = fdevent_socket_cloexec(proc->saddr->sa_family, SOCK_STREAM, 0);
- if (-1 == gw_fd) {
- log_perror(errh, __FILE__, __LINE__, "socket()");
- return -1;
- }
-
- do {
- status = connect(gw_fd, proc->saddr, proc->saddrlen);
- log_perror(errh, __FILE__, __LINE__, "status[%d], reason[%s], errno[%d]", status, strerror(errno), errno);
- } while (-1 == status && errno == EINTR);
-
- if (-1 == status && errno != ENOENT && proc->unixsocket) {
- log_perror(errh, __FILE__, __LINE__,
- "connect %s", proc->unixsocket->ptr);
- unlink(proc->unixsocket->ptr);
- }
-
- close(gw_fd);
如果此时cgi进程出现coredump,而由其产生的子进程由于继承了cgi的标准输入,会使上述connect系统调用正常返回0,从而导致lighttpd重启cgi进程失败。
- int status;
-
- /*! lighttpd管理进程会在此处监听子进程状态,如果有子进程终止运行,则fdevent_waitpid_intr会返回 */
- if (-1 != (pid = fdevent_waitpid_intr(-1, &status))) {
- log_monotonic_secs = server_monotonic_secs();
- log_epoch_secs = server_epoch_secs(srv);
-
- /*! 子进程终止运行后,该函数会最终调用gw_spawn_connection重启cgi进程 */
- if (plugins_call_handle_waitpid(srv, pid, status) != HANDLER_GO_ON) {
- if (!timer) alarm((timer = 5));
- continue;
- }
- switch (fdlog_pipes_waitpid_cb(pid)) {
- default: break;
- case -1: if (!timer) alarm((timer = 5));
- __attribute_fallthrough__
- case 1: continue;
- }
- /**
- * check if one of our workers went away
- */
- for (int n = 0; n < npids; ++n) {
- if (pid == pids[n]) {
- pids[n] = -1;
- num_childs++;
- break;
- }
- }
- }
自行封装形如popen或system类的接口,内部使用execl系列函数执行shell命令。但在执行命令前优先关闭标准输入(close(0);)即可解决该问题。