当前位置: 首页 > news >正文

lighttpd cgi不能重启

1. 背景

cgi出现coredump后,lighttpd不能拉动cgi重启。

2. 重现问题

2.1. cgi实现

/*! cgi简单实现 */
#include <stdio.h>
#include <fcgiapp.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>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;
}

2.2. 场景重现

# 运行lighttpd,此处将worker线程配置为4个
/smbdir/third_party/sbin/lighttpd -f /smbdir/third_party/lighttpd/etc/lighttpd.conf -D# 手动kill掉cgi会出现cgi不能正常启动的问题
killall -11 cgi

3. 原因

lighttpd利用mod_facgi模块实现与cgi的交互,而cgi利用标准输入与lighttpd之间的信息互通,当在cgi中执行shell命令时,子进程会继承父进程的一些属性(标准输入也会被继承)。

3.1. lighttpd判断cgi是否正在运行

    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进程失败

3.2. 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;}}
}

4. 解决方案

自行封装形如popen或system类的接口,内部使用execl系列函数执行shell命令。但在执行命令前优先关闭标准输入(close(0);)即可解决该问题。

相关文章:

  • 【毕业设计】Django 校园二手交易平台(有源码+mysql数据)
  • 笔记-python map函数
  • 视频智能分析平台智能边缘分析一体机安防监控平台打手机检测算法工作原理介绍
  • 2024年旅游与经济发展国际会议(ICTED 2024)
  • 在WordPress上添加亚马逊联盟链接的三种方法
  • 网络安全筑基篇——SQL注入
  • 什么是粘性代理IP
  • Ubuntu 22.04.4 LTS openresty(Nginx) 通过Lua+Redis 实现动态封禁IP
  • 中介子方程二十八
  • Talking-Heads Attention
  • Kotlin 中的 infix 关键字(中缀函数)
  • C# 集合(二) —— List/Queue类
  • 马斯克的Grok-1:开源AI模型的突破与挑战
  • TrueNAS系统在ARM平台上的移植
  • 傅佩荣教授讲座视频全集,傅佩荣讲座大全,傅佩荣国学讲座全集百度网盘
  • [译] 怎样写一个基础的编译器
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • 2017-08-04 前端日报
  • Dubbo 整合 Pinpoint 做分布式服务请求跟踪
  • ES6语法详解(一)
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • JAVA_NIO系列——Channel和Buffer详解
  • js如何打印object对象
  • JS学习笔记——闭包
  • oldjun 检测网站的经验
  • Spring Boot MyBatis配置多种数据库
  • spring学习第二天
  • XML已死 ?
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 前端工程化(Gulp、Webpack)-webpack
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 深入浅出webpack学习(1)--核心概念
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 我看到的前端
  • 做一名精致的JavaScripter 01:JavaScript简介
  • 回归生活:清理微信公众号
  • ​必胜客礼品卡回收多少钱,回收平台哪家好
  • ​用户画像从0到100的构建思路
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • (+4)2.2UML建模图
  • (70min)字节暑假实习二面(已挂)
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (Ruby)Ubuntu12.04安装Rails环境
  • (TipsTricks)用客户端模板精简JavaScript代码
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (笔记自用)LeetCode:快乐数
  • (补充)IDEA项目结构
  • (六)软件测试分工
  • (数据结构)顺序表的定义
  • (图)IntelliTrace Tools 跟踪云端程序
  • (一)项目实践-利用Appdesigner制作目标跟踪仿真软件
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法