You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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的服务管理机制,更稳定:

  1. 保留你的监控plist(XXX_LLDP_check),但让它的脚本只负责状态检查和触发lldpd的启停,不再直接启动lldpd。
  2. 为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>
  1. 修改你的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

火山引擎 最新活动