為什麼這兩個ps命令執行結果不同?

ps命令執行以後 什麼樣的進程才會被記錄呢?

我的OS X上是這樣的:

然而一本書上是這樣記載的


好問題!我遍訪Google,居然沒能快速找到這個問題的回答。

確實,在Linux下運行ps,默認顯示屬於當前用戶的進程,例如:

$ ps
PID TTY TIME CMD
7115 pts/2 00:00:00 bash
7149 pts/2 00:00:00 ps

而在OS X下面運行時,ps消失了

? ps
PID TTY TIME CMD
19263 ttys000 0:00.32 -zsh
4989 ttys001 0:02.14 -zsh

鑒於OS X基於FreeBSD,我以為這是BSD系統與Linux下面ps實現的差異,就找了台FreeBSD來試:

$ ps
PID TT STAT TIME COMMAND
879 0 Ss 0:00.01 -sh (sh)
880 0 R+ 0:00.00 ps

也是有列出ps自身。

我不能接受這種事情,就搜了Apple開源的ps源碼 ps.c 來看。基本上,就是通過BSD系統調用KERN_PROC來獲得運行中進程的列表,再輔以各種過濾參數。並沒有發現什麼特意在結果中隱藏自身的代碼。

然後又向下搜FreeBSD的內核代碼freebsd/kern_proc.c at GitHub,也沒看到有什麼特別。

無法解釋。我隨手在OS X上跑了一下ps a:

? ps a
PID TT STAT TIME COMMAND
19262 s000 Us 0:00.04 login -pfl rick /bin/bash -c exec -la zsh /bin/zsh
19263 s000 S+ 0:00.32 -zsh
4988 s001 Us 0:00.02 login -pfl rick /bin/bash -c exec -la zsh /bin/zsh
4989 s001 S 0:02.15 -zsh
61687 s001 R+ 0:00.00 ps a

ps出現了!"-a"開關的意思是也顯示屬於其他用戶的進程。那麼到底是誰?

再跑ps au:

? ps au
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
rick 19263 0.0 0.0 2464932 4532 s000 S+ 五07下午 0:00.32 -zsh
root 19262 0.0 0.0 2471532 3040 s000 Us 五07下午 0:00.04 login -pfl rick /bin/bash -c exec -la zsh /bin/zsh
rick 4989 0.0 0.0 2464932 5260 s001 S 22 316 0:02.16 -zsh
root 4988 0.0 0.0 2471532 3040 s001 Us 22 316 0:00.02 login -pfl rick /bin/bash -c exec -la zsh /bin/zsh
root 61858 0.0 0.0 2435204 992 s001 R+ 6:25下午 0:00.00 ps au

居然ps是以root的身份在跑。

那麼答案就只有一個...

? ls -l /bin/ps
-rwsr-xr-x 1 root wheel 51008 12 3 14:36 /bin/ps

注意許可權位中的"s"。

OS X的ps命令居然是個看起來很嚇人的setuid程序。

如果把 /bin/ps 複製一份,用 chmod u-s 拿掉s位,對比輸出,會發現有趣的現象:

? ./ps au
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
rick 19263 0.0 0.0 0 0 s000 ?+ 五07下午 0:00.00 -zsh
root 19262 0.0 0.0 0 0 s000 ?s 五07下午 0:00.00 (login)
rick 4989 0.0 0.0 0 0 s001 ? 22 316 0:00.00 -zsh
root 4988 0.0 0.0 0 0 s001 ?s 22 316 0:00.00 (login)
rick 62709 0.0 0.0 2435212 1000 s001 R+ 6:41下午 0:00.00 ./ps au

以普通用戶身份運行的ps雖然還是能成功的獲取進程清單,但除了UID, PID和STARTED以外的信息大都被屏蔽了。

最後總結回答問題:OS X的ps命令總是以root身份運行,因此在默認不加-a開關時是不會出現在屬於你的進程列表裡的。


OSX上沒有procfs,ps通過Mach task port獲取進程信息,而這個task port功能太多了(OSX上gdb就是通過這個東西實現的),所以ps必須要以root身份運行才能訪問所有進程。

Linux和FreeBSD上有procfs,所以不需要setuid。

更正一下,FreeBSD默認應該在用procstat,不是procfs。

PS. 我似乎記得在FreeBSD預設不載入procfs的年代,ps用的是kmem?這樣的話似乎它也得setuid才能轉?那天有精神查一下……


執行 alias | grep ps 看看結果?


推薦閱讀:

Linux 的正確發音是什麼?
Android 系統無法被分支 (fork) 嗎,AOSP 和 GMS 是何關係?
linux g++以及build-essential 安裝問題?
請推薦 編程書籍 結合各位自己的實際?
為什麼 Linux 內核中不經常使用 typedef?

TAG:macOS | Linux | Unix | Unix入門 |