2012年9月27日 星期四

最近 將要在2013 年面世的Debian 7 將要支援MultiArch.
照表面上看來,這會是要把 Linux 套件同時能夠支援32bit/64bit 做個加強。
但是既然名為MutiArch,表示其格局不會被限制在x86/x64 之上,這樣表示能夠在x86的系統上, 保留其他平台的Library , 譬如在 x64 平台上, 保留 x86 平台的 run time library 或保留 Power PC平台的 run time library. 這樣好處應該是以後裝 cross compiler 比較方便. 如果配合 Qemu user mode + bin_fmt 應該相對容易作到在 x86 系統 直接執行其他平台程式, 例如 ARM, MIPS...

2008年7月28日 星期一

[讀書心得] 草菅人命

1.最近搞了一些中醫的書來研究, 對於咱祖先2000年的中醫智慧感覺真是博大精深. 愚曾學過 計算機相關的演算法, 很多的解法並非對於問題本身的領域來解, 而是先將問題本身轉換到另一種領域D', 在此 D' 領域上解決問題, 再將結果對應回來. 傳統中醫似乎也有此特性;沒看過中醫書籍者似乎總有成見, 譬如頭痛醫腳, 腳痛醫頭. 其實是經之所過, 病之所治. 把針插在經脈所經過的地方, 可以治療該條經脈上的病痛.
把人的身體上的運作, 轉換到另一種領域上來看, 如易經,五行, 將人體的運作予以抽象化. 譬如中醫的胃 並非單指胃臟, 而是指整個消化系統.看到身邊的人, 治糖尿治到截肢, 我有99.9999%以上機率懷疑, 現今西醫使用的治療方法根本上有很大的錯誤. 如果該治法是對的, 會越來越惡化那問題就很大了. 不過還好西醫們治死人不犯法,不然我們以前所羨慕的西醫醫生, 其社會地位必定一落千丈.
中醫歷史有2000年之臨床經驗, 而西醫只有200多年. 西醫的理論還需要時間的驗證, 搞不好以後西方人改用中醫治法反過來治我們. 到那時就可真有趣了.


2. 牛奶 冰品 油炸品 不要吃 , 多運動 才是長保健康之道

3. 中醫重視吸收學而非營養學

4. 牛奶喝的多的國家, 其骨質疏鬆症越嚴重

5. 預防針和疫苗 別亂打, 因為打了不一定有用.

6. 燒燙傷(高溫) 用沖脫泡蓋送可能會後悔一輩子

7. 電視廣告某種程度上和利益團體有掛勾, 他們的東西賣的出去才有錢賺.

8. 證照制度某種程度上也是個害人的制度, 拿到證照之後有多少人不思長進, 某種程度上只是會不會讀書的差別.

9. 中醫認為弱肉強食, 與菌共生

10. 以水災來說, 災民基本上要的關心是何時不會有水災, 而不是一天到晚的視察. 弄到不會淹水, 才是治本之道, 搞個防災應變中心,填填土, 每次大雨,大大小小官員們弄得像條狗, 還要到災區視察 勘災, 那些都是之標不治本.

11. 原則上,開刀是下下策,尤其是截肢, 摘除器官不要用這種方式. 化療是向閻王請藥單. 除非必要, 絕不能用此殺敵一千, 自損八百;甚至是玉石俱焚的治療方式.

12. 該書作者 月眉居士 黃成義 先生 甘冒著擋人財路的危險寫出這些書, 乃真英雄. 吾甚佩服之.

13. 清末民初的西醫、中醫之爭,最後中醫沒被「不科學」這個大弱點打敗的原因,就在於關於醫療,「能治好」才是唯一重要的,不能治好,即便再科學,都失去意義。

GNU/Linux 的 file 指令

GNU/Linux 的 file 指令不同於微軟的系統在於利用 file 指令可以很快的識別檔案種類.但是如果是最多人用的M$ 系統, 基本上只能倚靠副檔名.
直接看副檔名的方式算是最簡單的, 但是如果有人把 .zip 的檔案 改個檔名 , 例如 .bin , 這樣是不是就可以閃避過某些防毒的掃描呢 ?

在 GNU/Linux 的系統, file 指令可以不受副檔名的影響來辨識檔案種類的原因是 它根本不看 副檔名, 而是去查看檔案內容是不是符合某些特徵. 這個特徵叫做 magic number (魔術數字, 我個人稱之為神奇數字). 防毒軟體的掃描方式有一部分也是比對特徵.

用 less 指令看看 magic number 的特徵檔
less /usr/share/file/magic


搜尋一下 PE executable for Windows

0 string MZ
>0 string MZ\0\0\0\0\0\0\0\0\0\0PE\0\0 PE executable for MS Windows

這應該就是所謂的特徵比對

如果M$ 的系統也想用這種方式辨認檔案, 其實只要裝 cygwin 就可以有這種功能了

2008年2月18日 星期一

[原創]state event action 框架



寫程式時如果是使用事件驅動, 很可能會有狀態轉移的問題。
即(1)輸入事件,(2)輸入現在狀態,(3)執行動作。
反?到程式上應該會有很多做法。
譬如使用慢吞吞的 switch case,時間複雜度為 O(E*S),E 為輸入事件,S為現在狀態
有沒有方法可以變成 O(1)呢?
使用查表法應可以達成。

前提是:狀態和事件一定要連續
使用二維函數指標可達成此要求
在下的實踐方式如下:


#include <cstdlib>
#include <cstdio>

using namespace std;

#define STATE_SIZE 5
#define EVENT_SIZE 5

//定義狀態
enum STATE
{

ST0 = 0,ST1 = 1,ST2 = 2,ST3 = 3,ST4 = 4

};

//定義事件
enum EVENT
{

EVENT0 = 0,EVENT1 = 1,EVENT2 = 2,EVENT3 = 3,EVENT4 = 4

};


//定義2維指標陣列
typedef void (*action)(void);
action actions[STATE_SIZE][EVENT_SIZE];

//隨便定幾個函數來測試
void no_fun(void)
{

printf("no_fun\n");
}


void
fun1_1(void)
{


printf("fun1_1\n");
}


void
fun2_1(void)
{

printf("fun2_1\n");
}


void
fun1_3(void)
{

printf("fun1_3\n");
}


void
fun4_4(void)
{


printf("fun4_4\n");
}



int
main(int argc, char *argv[])
{


int
i,j;
for
(i=0;i<STATE_SIZE;i++)
{


for
(j=0;j<EVENT_SIZE;j++)
{

actions[i][j] = &no_fun;
}
}


//把函數指上去
actions[1][1] = &fun1_1;
actions[2][1] = &fun2_1;

actions[1][3] = &fun1_3;
actions[4][4] = &fun4_4;

//call 幾個函數看看
actions[ST1][EVENT1]();
actions[ST2][EVENT1]();

actions[ST1][EVENT3]();
actions[ST4][EVENT4]();
actions[ST1][EVENT0]();

system("PAUSE");
return
EXIT_SUCCESS;
}




執行結果:
-----------------
fun1_1
fun2_1
fun1_3
fun4_4
no_fun


2008年2月12日 星期二

[原創] Linux Bridge 下 清除 MAC Address Table

先用2張網卡 組合出一台bridge 再說:
ifconfig eth1 0.0.0.0
ifconfig eth2 0.0.0.0

brctl addbr br0
brctl addif br0 eth1
brctl addif br0 eth2
此時 橋接器 br0 已經完成

在 /sys/class/net/br0/bridge/ 目錄下有這些檔案
ageing_time group_addr root_id topology_change
bridge_id hello_time root_path_cost topology_change_detected
flush hello_timer root_port topology_change_timer
forward_delay max_age stp_state
gc_timer priority tcn_timer

這些檔案和 STP 協定有關

如果想要強制清除 MAC Address table
只要動此檔案
/sys/class/net/br0/bridge/flush

所以
先打 brctl showmacs br0

root@switch-master:/sys/class/net/br0/bridge# brctl showmacs br0
port no mac addr is local? ageing timer
1 00:01:53:81:c5:3e no 270.57
1 00:01:53:81:fa:de no 53.61
1 00:01:53:82:0a:d7 no 1.47
2 00:01:53:82:18:41 yes 0.00
1 00:01:53:82:2f:a8 yes 0.00


成為 root
echo "1" > /sys/class/net/br0/bridge/flush

在看看 mac address table 的變化

root@switch-master:/sys/class/net/br0/bridge# brctl showmacs br0

port no mac addr is local? ageing timer
2 00:01:53:82:18:41 yes 0.00
1 00:01:53:82:2f:a8 yes 0.00

哈哈, 清掉了

2008年1月30日 星期三

CLI 選單界面想法

通常在嵌入式系統尤其是網通的嵌入式系統,通常會有
web,RS232 ,Telnet,SSH(不一定)接口 ,用來登入系統做管理。
而選單介面除了可以讓使用者不必記很多指令就能快速上手,這是其最大好處。

我提了4個層次的想法來做選單介面:
1. console 介面 web browser
若系統本身就要提供web 介面,個人建議可用用 links2 或 lynx 文字介面瀏覽器當成文字選單介面,這樣好處是可以一套web 介面兩用web , telnet , rs232 都可以用(web & console),還有滑鼠可以點。缺點是web 版的介面必須不能太花俏,必須以text 介面browser 為考量。

2. charva
這種方式 是先用 jbuilder 或者可以快速產生 GUI 的程式預先畫好介面,然後再用此library 從swing 轉成 console 介面,也是一魚兩吃(GUI & console),缺點是tool chain 必須要有 gcj。適合想從頭做起的專案。

3.libnewt
由RedHat 開發的console 介面 windowing library, 適合從頭幹起的專案

4.ncurses
一套行之有年的console ui library,用來移植 現有的程式用

5.如果要搞一套 Cisco like 的command line, 可參考
http://libcli.sourceforge.net/

2007年12月1日 星期六

玩玩 strace

strace 這個指令可以追蹤 system call




System call 是 process 與作業系統之間的介面。
System call 是由 Linux kernel 所實作並提供給使用者,一般的user-space program 可使用 system call 與Linux kernel 溝通。標準的Linux 上的C語言要使用 system call 通常會透過GLIBC來呼叫system call。

通常 GLIBC 提供呼叫 system call 的介面稱為 wrapper routine,
wrapper routine 可以看成一個軟體中間層。 目的只是代理呼叫 Linux 的 system call handler,最後再由 system call handler 找到service routine 的所在的位址,並交由 service routine 完成工作。

而這個 service routine , 例如 open(), read(),writ(),close(), 如果牽涉到硬體 通常就是 Linux Driver 要負責實作的。

在 Linux kernel , 通常system call 會對應到函數指標, 因為設備對象不同, 但是system call 名字相同, 所以用函數指標( function pointer ) 可以輕鬆隔開。如同 C++ 的抽象化的概念。





$ strace ./hello

execve("./hello", ["./hello"], [/* 59 vars */]) = 0
brk(0) = 0x804a000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=51994, ...}) = 0
mmap2(NULL, 51994, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f01000
close(3) = 0
open("/lib/i686/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360`\1"..., 512) = 512
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f00000
fstat64(3, {st_mode=S_IFREG|0755, st_size=1298800, ...}) = 0
mmap2(NULL, 1308112, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7dc0000
mmap2(0xb7efa000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x139) = 0xb7efa000
mmap2(0xb7efd000, 9680, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7efd000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7dbf000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7dbf6c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb7efa000, 4096, PROT_READ) = 0
mprotect(0xb7f27000, 4096, PROT_READ) = 0
munmap(0xb7f01000, 51994) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_size=makedev(0, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f0d000
write(1, "hello\n", 6hello
) = 6
exit_group(0) = ?
Process 9711 detached


想不到一個簡單的, 用 printf() 搞出來的 hello, 竟然暗藏這麼多system call


write(1, "hello\n", 6hello
) = 6

第2個hello 左邊那個6表示欲寫入6個字元
等號的右邊那個6 表示 已經寫入6個字元
1 表示 file descriptor, 表示標準輸出





看來寫Driver 時要好好用這招了



$ strace -e open ./hello

只追蹤 open() 系統呼叫

open("/etc/ld.so.cache", O_RDONLY) = 3
open("/lib/i686/libc.so.6", O_RDONLY) = 3
hello
Process 20140 detached




strace 參數:
usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]
[-p pid] ... [-s strsize] [-u username] [-E var=val] ...
[command [arg ...]]
or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...
[command [arg ...]]




參數說明:
-c 統計每一系統調用的所執行的時間,次數和出錯的次數等.
-d 輸出strace關於標準錯誤的調試信息.
-f 跟蹤由fork調用所產生的子進程.
-ff 如果提供-o filename,則所有進程的跟蹤結果輸出到相應的filename.pid中,pid是各進程的進程號.
-F 嘗試跟蹤vfork調用.在-f時,vfork不被跟蹤.
-h 輸出簡要的幫助信息.
-i 輸出系統調用的入口指針.
-q 禁止輸出關於脫離的消息.
-r 打印出相對時間關於,,每一個系統調用.
-t 在輸出中的每一行前加上時間信息.
-tt 在輸出中的每一行前加上時間信息,微秒級.
-ttt 微秒級輸出,以秒了表示時間.
-T 顯示每一調用所耗的時間.
-v 輸出所有的系統調用.一些調用關於環境變量,狀態,輸入輸出等調用由於使用頻繁,默認不輸出.
-V 輸出strace的版本信息.
-x 以十六進制形式輸出非標準字符串
-xx 所有字符串以十六進制形式輸出.
-a column
設置返回值的輸出位置.默認為40.
-e expr
指定一個表達式,用來控制如何跟蹤.格式如下:
[qualifier=][!]value1[,value2]...
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用來限定的符號或數字.默認的qualifier是 trace.感嘆號是否定符號.例如:
-eopen等價於 -e trace=open,表示只跟蹤open調用.而-etrace!=open表示跟蹤除了open以外的其他調用.有兩個特殊的符號 all 和 none.
注意有些shell使用!來執行歷史記錄裡的命令,所以要使用\\.
-e trace=set
只跟蹤指定的系統調用.例如:-e trace=open,close,rean,write表示只跟蹤這四個系統調用.默認的為set=all.
-e trace=file
只跟蹤有關文件操作的系統調用.
-e trace=process
只跟蹤有關進程控制的系統調用.
-e trace=network
跟蹤與網絡有關的所有系統調用.
-e strace=signal
跟蹤所有與系統信號有關的系統調用
-e trace=ipc
跟蹤所有與進程通訊有關的系統調用
-e abbrev=set
設定strace輸出的系統調用的結果集.-v 等與 abbrev=none.默認為abbrev=all.
-e raw=set
將指定的系統調用的參數以十六進制顯示.
-e signal=set
指定跟蹤的系統信號.默認為all.如signal=!SIGIO(或者signal=!io),表示不跟蹤SIGIO信號.
-e read=set
輸出從指定文件中讀出的數據.例如:
-e read=3,5
-e write=set
輸出寫入到指定文件中的數據.
-o filename
將strace的輸出寫入文件filename
-p pid
跟蹤指定的進程pid.
-s strsize
指定輸出的字符串的最大長度.默認為32.文件名一直全部輸出.
-u username
以username的UID和GID執行被跟蹤的命令.