2008年12月5日 星期五

詳解ttysnoops

前言:
ttysnoops是一個監視文字console的一個小工具,如果在embedded system開發環境,通常是使用com port或是使用telnet ssh之類的方法去做溝通。但是如果你的機器並不在你身邊,你卻想要知道你寫的程式過得怎樣,一個人在遠方是否有什麼異狀,想要知道它輸出的訊息?
這時該怎麼辦? 這時就會需要用到ttysnoops了。

原理:
ttysnoops 需要在執行login之前先被執行。ttysnoops執行時,如同ssh一樣,會先開一對/dev/ptm、/dev/pts/x。
然後會用execv來執行login,並且使用dup2來轉移login的stdio到/dev/pts/x上面,如此一來ttysnoops就可以利用對應的/dev/ptm來做存取。

解析source code:
ttysnoops會先開啟一個/dev/ptm,kernel會自動生出一個/dev/pts/0出來,find_ptyxx中,ttyfd可能是/dev/pts/0,dup2將ttyfd複製給stdio。 如此一來,這個行程(ttysnoops的子行程)的所作所為就會反映到/dev/pts/0,而不會在stdio上,又/dev/pts/0對映到/dev/ptm,因此ttysnoop可以讀寫/dev/ptm來達成與(ttysnoops的子行程)溝通。所以ttysnoops稍後會有一個處裡,也就是查看ptyfd(/dev/ptm)若有資料,會寫到ttysnoops的stdio,來讓使用者以為一切都很正常。
因此稍後執行login以後,它所顯示的東西會寫到/dev/pts/0上面,而不會顯示在stdio上,又因為父行程(ttysnoops)繼續執行去監視ptyfd(/dev/ptm),就會感覺是直接跟login直接溝通,但其實資料流已經透過ttysnoops攔截下來了。如果有一個client連進來後,ttysnoops又會fork出一個子行程,然後它會開啟一個/var/spool/ttysnoops/0這個named socket,然後再一次使用dup2將stdio導向到這個socket,如此一來,login的所作所為就有兩個行程會知道了,ttysnoopys以及連進來監視的client。
使用情境:
1. 當執行login以後,login會輸出login:的字樣,提示輸入帳號
2. 此時login只會寫到ptyfd上面,因此ttysnoop會將這個字串讀出並寫入自己的stdout
3. 這時候本機上就顯示login:了
4. 如果本機上打字進去,會由ttysnoop先收到,收到以後就寫給ptyfd,然後login就會去做後續工作....
5. 這時,有client登入了,登入以後,如果ttysnoops從ptyfd讀出東西,就會輸出給他自己的stdout,當然就也會輸出給authfd
6. 若是client打字進來,authfd收到以後,因為他對應到ttysnoops的stdio,所以ttysnoops也會從他的stdin收到字串,收到以後就會使用write寫給pthfd
下載連結:

2008年8月31日 星期日

做案子真的需要UML

今天買了一本書叫做OCUP UML初級認證攻略,作者是邱郁惠,她寫了不少關於系統設計的書。


這一本我索性的買了下來,因為這本書給了一個目標就是考取UML的初級認證,終於有一個學習UML的目標了。如果沒有一個認證,在公司裡面真的很難有人會相信你、認同你使用UML來描述系統。我是認為UML絕對是非常直得學習的語言,因為一張圖可代表千言萬語,也非常有助於愛開會的台灣公司,有一個可以開會討論的工具。不要每次開會都是天馬行空,開完後沒有任何結果與紀錄。

開發嵌入式系統更是需要這類的工具,因為這種專案不是只有跟某一種領域的人交談,而是跟軟體、硬體、業務、PM、工廠等等...各種不同專業不同個性的人合作。

2008年8月23日 星期六

handle class in C language

在C++中有一種模組設計的技巧叫做handle class,其宗旨就是要讓封裝的特性更強烈。只提供一個handle來控制這個物件,其他所有資料均不開放。而在C語言裡面,要怎麼弄出一個handle clasee呢?我在此提供我的方法:

1. 首先我的習慣是一個.c檔配一個.h檔,而這一組就是相當於一個class,相信很多人也都這樣做。
2. 所有的Globol variable與private function都使用static宣告,讓其他.c無法使用,也避免掉重複宣告的困擾。
3. 在.h檔裡面增加define如下

////////////////////test.h/////////////////////////
#ifdef TEST_C

struct{

int a;
int b;
int c;

}test

#else

void test_hanle;

#endif


extern void test_init( struct test *test_handle);

/////////////////////////////////////////////////////

如此一來只要在test.c裡面宣告#define TEST_C就可以讓tset.c只看到他自己的成員們,但是別的.c檔想要來#include "test.h"的時候,就只能看到test這個模組釋放出來的函式,以及一個handle---void test_hanlde,那所有的function都可以設計成必須要傳入test_handle 才能使用這個模組。

如果test.c裡面有修改到什麼實作細節,也不會影響到include "test.h"的上層程式。因為其他的.c檔,只會參考到test.h裡面的void teset_handle而已。所以編譯的時候,只會編到test.c為止。

2008年5月27日 星期二

Father process is killed by a signal after calling system()

大家都知道system()是在程式裡面執行shell命令的函式,它裡面會使用fork去創造一個shell行程,並且用shell行程去執行shell命令。但是man裡面並沒有提到他會發出一個signal 17,有些版本的Linux系統收到此signal後,會執行Term的動作,此網頁有詳細介紹:http://linux.about.com/od/commands/l/blcmdl7_signal.htm

為了避免system()會因為它裡面所開的子行程要結束,而送出signal 17,必須要在安裝一個signal的時候所使用的sigaction函式,加上SA_NOCLDSTOP的flag。才不會讓父行程收到signal 17,這樣才不會無緣無故的呼叫system後父行程因為system()而死掉。

這邊提醒一下,不是只有這個signal要擷取。而是所有的signal都需要擷取下來,然後做妥善的處理。

2008年5月10日 星期六

呼叫pthread_cancel發生segmentation fault

可能是因為pthread_cancel裡面是使用動態記憶體配置,如果拿同一個pthread_t傳入pthread_cancel兩次,那麼第二次呼叫的時候就會收到SIGSEGV信號。這個問題通常是沒做好資源保護,而造成的race condition。

這個pthread_cancel一呼叫後,預設動作並不會馬上就把該thread給停掉,而是在某些system call裡面來做停止的動作,因此這些system call也就是所謂的cancel point。所以使用這個function時候需要非常非常的小心,因此我的建議是在你的一生中,都不要用這個function....。或許太嚴重了,不過真的要非常小心才是。因為還有非常多方法可以避免掉呼叫這個function,來結束一個thread

所以一個thread,最好幫他設計一個Finite State Machine(FSM),藉由狀態的控制,來改變thread的行為。因為FSM的設計可以讓你限定這個Thread的狀態,狀態的切換之間可準確的控制資源的配置與釋放。如果使用一般無組織的flag來決定thread的運作,那這些flag的所有組合,你都要去測試一變,才能知道有無問題。

2008年4月21日 星期一

Linux的Messge queue簡介

Message queue應該是蠻常用的一種IPC,主要的特點是它能夠暫存不同型態的message,並且每一種型態都以Queue的存取方式來操作。比起share memory;Message Queue更能夠處理非同步的訊息。如果使用share memory的話,將會帶來非常多的同步問題,因為share memory只是一塊記憶體,沒有彈性去處理更多的資訊。而Message Queue卻可以讓訊息好好的排隊等著被處理來達成Producer & Consumer的處理模型 。

在Linux上面,可以用ipcs的shell指令來觀察目前所有的IPC資源使用情況:
#ipcs -s
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status

------ Semaphore Arrays --------
key semid owner perms nsems

------ Message Queues --------
key msqid owner perms used-bytes messages
0x000004d2 42631168 root 666 8 1
0x0000270f 42663937 root 666 2080 4
0x0000270e 42401794 root 666 0 0

一些使用法在Google上都可以找到,下面列出一些使用Message queue的重點:

1. 在Message Queue使用上來說,主要是靠一個號碼去跟Kernel要一個新的Message Queue。如果其他的行程也都用這個號碼開啟Message Queue的話,那每個行程都可以看到這個MessageQueue裡的東西。但是Message Queue可以存放著不同的型態的Message,因此各行程可以某個特定的形態去取得特定的Message。所以可以架構成多對多的通訊方式。

2. 如果任一行程將這個號碼的Message Queue做移除的動作,那正在操作Message Queue的行程都會讓msgrecv return -1。此時需要再去做message開啟的動作。

3. 如果msgrecv的返回值為-1而且errno=EINTR,這並不是因為message queue出錯,而是在等待message queue的同時,發生了signal中斷,因此kernel就會讓msgrecv返回-1,並且設定errno=EINTR。所以一定要去判斷errno,到底是為什麼傳回了-1。

2008年3月15日 星期六


今天到天瓏晃晃,想找看看有沒有新的書可以讓我充實一下。無意間看到這一本書就拿起來翻一翻,隨便一翻都會看到在職場上會碰到的問題,然後我就索性在天瓏給他買下來了。就如同書裡說的一樣,這本書已經是很多文章與經驗的菁華,也有非常多的引用,並不是唬爛的。它點出了一個軟體系統在實際寫程式前,需要做的功課有多重要。

蓋房子之所以能這麼快、這麼精準的在蓋完後就可以賣,全拜建築業早已有許多的流程與制度來輔佐設計師、工程師與工人。但軟體有沒有一些流程呢?可能有,但採用的公司非常的少。因為很多公司會認為軟體工程是不必要的,但奇怪的是這些公司在徵人的時候卻要找軟體工程師而不是程式設計師。這本書不是在講軟體工程的理論,而是告訴你如何做工程,才能以最短時間生出一個成功的軟體。