MacOS Mojave下launchd管理LLDP守护进程异常终止问题求助
解决LaunchDaemon脚本启动lldpd后被自动杀死的问题
这个问题我之前帮同事排查过,核心坑点就是launchd的进程管理逻辑和咱们平时在终端里跑脚本完全不一样——它会把由LaunchDaemon启动的脚本及其所有子进程纳入同一个进程组。当你的lldp_check.sh脚本执行完毕退出时,launchd会给整个进程组发送SIGTERM信号,哪怕你用&把lldpd放到后台、甚至加了nohup都没用,因为nohup只是忽略SIGHUP信号,挡不住launchd的SIGTERM。
下面给你两种靠谱的解决思路:
方法一:让lldpd彻底脱离脚本的进程上下文
修改脚本中启动lldpd的命令,用setsid让它在新的会话中运行,完全跳出launchd追踪的进程组:
# 替换原来的 /usr/local/sbin/lldpd & setsid /usr/local/sbin/lldpd > /dev/null 2>&1 &
setsid会创建一个独立的会话和进程组,让lldpd成为会话首进程,这样脚本退出时,launchd找不到它的关联,就不会杀死它。- 后面的
> /dev/null 2>&1是把标准输出和错误输出都重定向,避免残留的文件描述符被launchd追踪到。
方法二:用launchd直接管理lldpd(更符合macOS规范)
既然你本来就是用launchd做监控,不如把逻辑拆成两部分,完全贴合Apple的服务管理机制,更稳定:
- 保留你的监控plist(
XXX_LLDP_check),但让它的脚本只负责状态检查和触发lldpd的启停,不再直接启动lldpd。 - 为lldpd单独写一个LaunchDaemon plist(比如命名为
com.yourcompany.lldpd.plist),放到/Library/LaunchDaemons/目录下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.yourcompany.lldpd</string> <key>UserName</key> <string>root</string> <key>ProgramArguments</key> <array> <string>/usr/local/sbin/lldpd</string> </array> <key>KeepAlive</key> <false/> <key>RunAtLoad</key> <false/> </dict> </plist>
- 修改你的
lldp_check.sh脚本,根据网络状态来加载/卸载这个lldpd的plist:
#!/bin/bash sleep 5 ethernet_if=$(networksetup -listallhardwareports | awk '/Ethernet/{getline;print}' | awk 'NR==1 {print $2}') ethernet_status=$(ifconfig "$ethernet_if" | grep status | awk '{print $2}') if [ "$ethernet_status" = "active" ]; then echo "ETHERNET WIRED LINK IS UP" >> /tmp/test.log if ping -c 1 1.1.1.1 &> /dev/null; then echo "ON CORPORATE NETWORK. STARTING LLDPD" >> /tmp/test.log # 加载lldpd的LaunchDaemon launchctl load /Library/LaunchDaemons/com.yourcompany.lldpd.plist echo "LLDP started via launchd" >> /tmp/test.log else echo "NOT ON CORPORATE NETWORK" >> /tmp/test.log launchctl unload /Library/LaunchDaemons/com.yourcompany.lldpd.plist echo "LLDP stopped via launchd" >> /tmp/test.log fi else echo "ETHERNET WIRED LINK DOWN" >> /tmp/test.log launchctl unload /Library/LaunchDaemons/com.yourcompany.lldpd.plist echo "LLDP stopped via launchd" >> /tmp/test.log fi
额外注意事项
- 修改完plist文件后,一定要确保权限正确:
sudo chown root:wheel /Library/LaunchDaemons/*.plist,权限设置为644,不然launchd会拒绝加载。 - 测试时可以用
sudo launchctl start XXX_LLDP_check手动触发脚本,然后用ps aux | grep lldpd查看进程是否正常存活。 - 脚本里的
sleep 5是为了等待网络状态稳定,你可以根据实际网络环境调整这个时间。
内容的提问来源于stack exchange,提问作者AnthoB




