1. 程式人生 > >Cron連線正常工作5次後異常原因分析

Cron連線正常工作5次後異常原因分析

目錄

目錄 1

問題描述 1

分析定位 1

解決方法 2

附1:Cron工作流 3

附2:SIGPIPE發生的位置 3

 

如果一個shell命令的“$?”值為141,則它是收到了SIGPIPE訊號。一些shell指令碼中的sleep或ps、wc等命令無效,也可能是本文描述的原因,解決辦法是忽略掉SIGPIPE,指令碼中可以加句:trap "" SIGPIPE。

問題描述

在Crontab中僅配置如下一條命令(為簡化問題的描述和定位,剔除所有其它的):

*/1 * * * * echo

 hello >> /tmp/hello.txt

 

也就是每分鐘執行一下“echo hello >> /tmp/hello.txt”。

 

通過觀察發現:

每次重啟cron程序後,都只能連續正常工作5次,也就是可以看到“/tmp/hello.txt”新增5行“hello”。

分析定位

藉助strace工具,cron程序仍然在工作,只是發生了異常:

[pid 12497] select(5, NULL, [4], NULL, {0, 10000}) = 1 (out [4], left {0, 10000})

[pid 12497] --- SIGPIPE (Broken pipe) @ 0 (0) ---

Process 12497 detached

--- SIGCHLD (Child exited) @ 0 (0) ---

 

發生了SIGPIPE,導致了子程序退出。翻閱cron的原始碼,確認cron沒有呼叫“signal(SIGPIPE, SIG_IGN);”來忽略SIGPIPE,因此當收到SIGPIPE訊號時,程序必然退出。

 

進一步追蹤發現,PIPE連線的是“/usr/local/sa/agent/log/sap1012.sock”,另一端則是sap1012

# lsof /usr/local/sa/agent/log/sap1012.sock

COMMAND   PID USER   FD   TYPE     DEVICE SIZE       NODE NAME

sap1012 15415 root    5u  unix 0xd940de40      3985983520 /usr/local/sa/agent/log/sap1012.sock

sap1012 15415 root   11u  unix 0xe22fa3c0      3970596394 /usr/local/sa/agent/log/sap1012.sock

# ls -l /proc/15415

lrwxrwxrwx  1 root root 0 Apr 17 12:43 exe -> /usr/local/sa/agent/plugins/sap1012-v5.1.4

 

使用valgrind可以看到對PIPE的寫(send)是在“/lib/libsandbox_web_ips.so”中進行的,利用ldd可以發現這個共享庫在編譯期間就被連結進了cron程式檔案中:

# ldd /usr/sbin/cron

        linux-gate.so.1 =>  (0xffffe000)

        /lib/libbash_strip_env.so (0xb7f8c000)

        /lib/libsandbox_web_ips.so (0xb7f85000)

        libpam.so.0 => /lib/libpam.so.0 (0xb7f70000)

        libpam_misc.so.0 => /lib/libpam_misc.so.0 (0xb7f6d000)

        libc.so.6 => /lib/libc.so.6 (0xb7e4b000)

        libdl.so.2 => /lib/libdl.so.2 (0xb7e47000)

        libpthread.so.0 => /lib/libpthread.so.0 (0xb7e32000)

        libaudit.so.0 => /lib/libaudit.so.0 (0xb7e1f000)

        /lib/ld-linux.so.2 (0xb7f90000)

 

在Google和Baidu中找不到任何有關“libsandbox_web_ips.so”的蹤影,猜測是有可能是私有的。Cron的Makefile本身並沒有包含libsandbox_web_ips.so”和“/lib/libbash_strip_env.so”,如:

cc  -o cron cron.o database.o user.o entry.o job.o do_command.o misc.o env.o popen.o compat.o

 

經實踐確認,編譯生成可執行檔案後,可執行檔案都會依賴“libsandbox_web_ips.so”和“/lib/libbash_strip_env.so”兩個共享庫,而且它們可能會在被載入時自動執行,但因為符號被stripped掉了,看不到細節。

 

終於在/etc/ld.so.preload中找到了兩者:

# cat /etc/ld.so.preload

/lib/libbash_strip_env.so

/lib/libsandbox_web_ips.so

 

它們兩個如同木馬,會伴隨任一程式一起執行,但libsandbox_web_ips.so可能存在問題,導致cron執行異常。

解決方法

kill掉sap1012程序,然後重啟cron程序,這樣cron就可以正常工作了。cron必須在sap1012之前啟動,以規避問題。通過strace會發現變成如下:

[pid 11704] socket(PF_FILE, SOCK_STREAM, 0) = 3

[pid 11704] fcntl64(3, F_GETFL)         = 0x2 (flags O_RDWR)

[pid 11704] fcntl64(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0

[pid 11704] connect(3, {sa_family=AF_FILE, path="/usr/local/sa/agent/log/sap1012.sock"}, 110) = -1 ECONNREFUSED (Connection refused)

[pid 11704] close(3) 

 

更好的解決辦法將/lib/libbash_strip_env.so和/lib/libsandbox_web_ips.so,從/etc/ld.so.preload中剔除,但是它們就不能發揮作用了。

附1:Cron工作流

真正執行Cron命令的是vfork(有些版本為fork呼叫)出來的程序,寫標準輸出的fork是可選的,只有當存在“%”配置時才會生效,目的是通過寫標準輸出往vfork產生的程序輸入內容。

附2:SIGPIPE發生的位置

SIGPIPE正是發生在下圖所示的“send()”呼叫,至於是因為sap1012關閉了讀端,還是其它原因,暫不清楚原因。