發表文章

使用 SquashFS 免受核心版本不支援之苦

SquashFS是一個即時解壓縮的檔案系統,如同Cloop、CramFS一般。只是,SquashFS的壓縮比更高、速度更快,又不像CramFS有單一檔案大小或整體檔案系統大小的限制,在LiveCD的應用上非常有用。但往往這種特殊的模組,並不像 Cramfs是內建於Linux Kernel之中。要使用他,我們必須去抓回最新的 Patch,對自己的Kernel做修改。 問題是,Patch 永遠跟不上 Kernel 發行的速度,如果我們要使用最新的核心,不見得Patch一定能夠跟上支援,導致在考量之下,有時必須退而求其次使用舊的核心。但是,如果將Patch做成模組,就可不必管Kernel的變化,無論Kernel多新,我們都還是可以使用 SquashFS。 這是我對原 Patch 的分解修改 : squashfs-fred.tar.gz 只要解開後直接 make 就可以製作出 .ko 的模組,接著只要將此模組複製到 /lib/modules/ /kernel/fs/squashfs/ 之中即可使用。修改成單純模組的缺點是,開機時的 initrd 不支援SquashFS,因為若要支援必須修改核心的 init/do_mounts_rd.c 並重新編譯 Kernel,所以若做成 patch 勢必又將與核心版本扯上關係。我做此修正的重點是要讓每一版的Linux Kernel都能很容易使用SquashFS,不需要因為 Kernel 太新而不能使用。有興趣的人可以試試看。 註:本修改只在 Kernel 2.6 版以上測試過。

hotplug 舊時代的產物?udev 才有未來!

什麼是 hotplug ﹝熱插拔﹞?傳統的 PCI 、 ISA ,都需要在電腦處於冷機的時候,才能插上裝置,因為這些規格都不具備 hotplug 的能力。hotplug 意味著不必讓電腦關機、切斷電源後就能插上你的裝置。我們常見的隨身碟就是最好的例子。 常常我們文件完後想要儲存帶走,就會拿起隨身碟插入 USB 連接孔,一般狀況下,系統馬上就能偵測到新的儲存裝置,並做新增配置,讓你可以立刻將資料存放於隨身碟裡。用完後,只要將隨身碟拔起,就可將資料帶走。這種在電腦熱機狀態就增減硬體的機制就是 hotplug。 在 Linux 裡,過去大家都是用 hotplug 套件包來達成動態增減裝置的功能,還必須設定 /proc/sys/kernel/hotplug ,讓核心在偵測到有新的 hotplug 裝置時,會通知 hotplug 套件包去做相關配置。 稍微有注意的人都知道,Linux 2.6 版核心後,全面採用 udev 取代過去的 devfs ,裝置檔現在都改用 udev 自動產生。原因是 udev 在設計理念上比過去的 devfs 擁有更大的格局,他不只是一個設備檔產生器,而是一個核心訊息的監聽器,它總在隨時監聽核心是否有新增裝置或是載入新的模組,並做出相對應的處理。在 udev 發展的過渡時期,由於對新裝置的對應處理機制並沒有設計的很完善,暫時只能充當設備檔產生器,而在 hotplug 機制的部份,設計了一個小程式 udevsend 與過去的 hotplug 套件包做整合。 udev 發展到今天,已逐漸成熟,hotplug 機制已不必過度仰賴舊的 hotplug 套件包,udevsend 這支程式已經在新版的 udev 中拿掉了,關於這部份可以在 Fedora Core 5 的系統中看到實作。

Static 與 Shared 的函式庫撰寫

簡單來說函式庫分為兩種類型: Static﹝靜態﹞和 Shared﹝共享﹞,前者你可以想像是嵌入式,將函式嵌入到主程式中;後者是主程式能以 Dynamic (動態)方式指定呼叫的外部函式庫。 最近將一些程式模組化,把許多函式分門別類拉到主程式外做成函式庫模組。這工程雖不算浩大,但也挺累人的。因為函式庫的撰寫很有實用價值,我就隨手將它記下來,還有將以前所看過的文件重新翻出來復習一番。有一篇 《 Program Library HOWTO 》詳細記載了撰寫函式庫的方法和過程,有興趣的人可以參考。 撰寫程式時,程式碼裡的任何工作,扣除程式語法不算,總是由許許多多函式所組成,可別以為這些函式是電腦內建的,CPU可沒有這麼厲害,可以內建這樣龐大的指令集。這些函式都是由前人不斷發展提供的,可能是作業系統研發者,也可能是某應用程式的設計者。 一些公認標準的共用函式庫,讓一般程式設計師可以方便的使用各種功能,例如,當你想要在螢幕上顯示一行文字,你只要呼叫如 printf() 這種函式,而不必再去處理 低階的 BIOS Interrupt,然後控制 CPU 上的 Register 來達成螢幕輸出的工作。共用函式庫最大的好處,就是能讓許多工作不必重覆撰寫,以省下不少時間,更棒的是,你可以使用各種程式語言來呼叫使用這些函式。 文章一開始就提到函式庫分兩種類型:Static Library、Shared Library。 關於 Static Library ,應該大多程式設計者都很熟悉,就是將自定的函式寫再不同的 .c 檔中,在編譯時,透過編譯器去連結各個 .c 產生出來的二進位 .o 檔,將所有的函式都寫入同一執行檔中,使執行檔主程式能夠使用這些外部函式。 Shared Library 可就沒有這麼中央集權,我們可以將函式庫做成一個個的 .so 檔,你可以將它放入系統函式庫資料夾中,讓所有程式都能呼叫他。當你想要將自定的函式編譯成 Shared Library 時,可用以下指令: 摘錄於《 Program Library - More Example 》 # 將自定函式的 .c 檔案編譯成 .o gcc -fPIC -Wall -g -c libhello.c # 將 .o 連結成 .so 檔 gcc -g -shared -Wl,-soname,libhello.so.0 -o lib...

建立良好的寫程式風格

大概最近許多人都在趕作業或是要考試吧,有不少人拿著一些他們的心血跑來問我問題。然而,我看到差點沒吐血,我只能說,那真的是一堆人類讀不懂的程式碼。或許我講得太誇張了,但是這卻是不爭的事實。由於許多人良好的 Coding 習慣尚未建立,所以他們所寫出來的東西,真得是『醜』的很可怕。我甚至相信,短短不到100行的程式碼,在半年後他一定讀不出來自己在寫什麼。這一切讓我不禁懷疑,難到他們的老師都沒有告訴他們寫程式的習慣這件事嗎? 其實,擁有好的寫程式習慣,可以讓我們寫出來的程式碼乾淨明瞭,不但在當下能夠容易除錯,日後也容易維護,因它而省下的時間,絕對是值回票價的。因此,建立良好的寫程式習慣是每個程式設計者所不可缺少的一環。 在建立良好的寫程式習慣之前,我們要先建立自己寫程式的風格。在今天資訊科技這麼發達的世界,透過網路的交流,多數程式設計者流傳了一些不成文的風格定義,像是八格的縮排等等。你可以追隨前人,延用他們的風格,也可以自己創造一套風格,但不管你的風格如何,適當的駐解、縮排和乾淨的程式,絕對都是不能缺少的。 這邊提供了一份關於 Linux Kernel 程式的編寫風格說明以供參考: http://www.linuxjournal.com/node/5780/print 有許多尚未建立習慣風格的人﹝多半是初學者﹞跑來問我問題時,我發現他們寫出來的程式會無法編譯通過,很多都是因為少了一個 { 或 }。追根究底,都是因為程式碼沒有縮排,我們很難看出其巢狀結構,自然就無法發現是否多或少了結尾符號。由此可知,良好的寫程式習慣和風格,是寫好程式的第一要素。 你還沒有好的習慣嗎?趕快去建立吧!

用 C 呼叫 rand() 每次都回傳相同結果?

為了寫一個隨機產生 ID 的程式,我用C去呼叫 rand() 這亂數產生函式,然而經過測試後發現,每次程式執行所產生的亂數都是一樣的。這問題讓我花了點時間研究了一下,我發現並非每次執行都一樣,而是每秒內產生 出來的亂數是一樣的。很明顯的,這裡的亂數種子設定出了點問題。 在過去習慣上,在使用亂數前 我們會用 srand(time(0)) 設定亂數種子,而一般的書籍也是這樣教我們。但這種方式設定亂數種子,種子的變化是以秒為單位,也就是每秒只變動一次。由於種子在一秒鐘之內都是一樣的, 每次使用 rand() 時,產生出來的亂數也都會是相同的。 這樣設定亂數種子其實 並沒有錯,因為一般程式只需要在開頭設定第一次,之後就不必再設。但如果我們要寫的是一個指令,使用者就可能在一秒鐘之內重覆執行你的程式很多遍。那將會 導致亂數種子被重新定義很多遍。每當種子被重新設定,rand()自然就會把亂數表重頭讀取,當然,每次所得到的亂數就會相同。 我暫時想出了個解決辦法,就是針對種子再給予時間以外的變數,讓每次執行的種子變得更不一樣。於是我將種子設定改成這樣: srand(time(0)+getpid()); 這 以程式執行時的行程處理ID加了進來當種子,因為每個程式的 PID 一定不一樣,如果要一樣也要等許多的程式執行後,重頭分配 PID 才有可能相同。以 PID 再加上原本每秒產生出來的時間,如此產生出來的種子必定獨一無二。這點小技巧能夠解決 rand() 每次回傳都相同的問題。 註:本文是架構在 Linux 上,並以 gcc 編譯所產生的程式當基準,若在 Windows 等其他平台和以 VC++ 、Turbo C等其他款編譯器,不能保證本文所談到的東西能起任何作用。

用心智圖軟體整理自己的思緒

圖片
以前寫各式各樣的程式,總是邊寫邊想其中的邏輯運作。碰到大一點的專案,最多是在紙張上用手畫一畫結構圖,寫一些重點關鍵。但講是講寫一些,最後一定是整疊的資料。 最近因緣際會發現了一個好用的軟體 FreeMind,你可以在 http://freemind.sourceforge.net/ 抓到它,它可以幫我很快的整理思緒,隨時可以刪減、修改或移動。更好用的是,它除了可以用圖顯示外,也可以轉成 HTML、XHTML、XML 等檔案,並條列式的將你的心智圖列出來。什麼是心智圖呢?可以參考下圖: 以 FreeMind 完成的心智圖 以 前寫程式邊想邊寫,碰到比較複雜的問題,每次都因為太複雜一時想不出頭緒而心情煩躁,嚴重點甚至缺少往下寫的意願。現在,我管他三七二十一,就是先把整個 程式結構流程寫出來就對了。然後就會發現,一項項原本混亂的想法,都可在心智圖上歸類。而且許多想法在此架構下是否妥當,都可以在製作這張心智圖時就會發 現,並很快可以修改。不容易再發生像過去一樣當程式寫到某種程度時,才發現它的架構並不妥當,面臨是否要重新改寫的問題了。當製作完這張圖後,我只要照圖 上的邏輯流程,用我的頭腦轉換成程式碼就好了,不用再去煩惱其中的結構問題,真是好用! 因為它,我現在寫程式效率倍增!歡迎大家一同來使用這好用的 FreeMind!

Linux 的 random 總是裝死

應該有不少人碰過 Apache 啟動時卡在 digest module 過不去,導致 PHP 不能使用,或是碰過某些程式卡在某個地方很久沒動作。這時候大家可能要去檢查一下 /dev/random 這個設備檔案。可以用 cat /dev/random 來看它的內容,如果你發現他一直沒顯示任何內容﹝可能是亂碼數字之類的﹞,那就是它出問題了。 據我從 digest module 的 source code 裡所知,這模組呼叫了一個亂數產生的函數,此函數會呼叫 /dev/random。所以當 /dev/random 卡住顯示不出內容時,很自然的任何 read() 它的程式會停在那等它回應。 我了解 Linux kernel 的 source code 之後發現,/dev/random 會使用 key/mouse/disk 的 interrupt 當做亂數種子的計算來源,好處是會有更大的安全性,但問題是當我們沒在使用 key/mouse/disk 或是他們的 interrupt 訊號量不足以產生亂數種子時,/dev/random 就會永遠是空白沒東西。 這問題有個暫時的解決辦法,就是將 /dev/random 砍掉,先用 link的方式使用 /dev/urandom 取代 /dev/random。 要完全解決此問題,可至 SourceForge 找到 gkernel 這 Project。 下載 rng-tool 回來編譯安裝。 然後於開機的 Scripts 中加入: rngd -b -o /dev/random -r /dev/urandom 此 Deamon 將會在沒足夠 interrupt 訊號時使用 urandom 的亂數當random 的亂數種子。

用 UPX 幫你的二進位執行檔瘦身

什麼是 UPX ?它的全名是 the Ultimate Packer for eXecutables,顧名思義就是能將執行檔做壓縮,使執行檔變得很小。有多小呢?一般狀況下可以壓縮成原來的 40% 甚至更小! 程式執行會不會變慢? 關於被壓縮過後的程式執行速度,只有執行剛開始需要解壓縮會比較慢,當程式啟動完畢後就和原先速度一樣,所以最多是啟動時速度比較慢而已。據官方數據統計,在 Pentium 133 的系統上,解壓縮的速度每秒可達 10mb;而在 Athlon XP 2000+ 的系統上,每秒可達 200mb,程式會到達 200 mb 的應該沒有才是。所以說啟動速度只慢個一秒不到,甚至感覺不到有慢,尤其今天的 CPU 隨便就 3.0GHz 以上,解壓縮速度的問題根本就不用煩惱。 能應用在哪裡呢? 一般人不會無聊到要去省那一點點的空間,反正現在硬碟大的很。但是,若用在嵌入式及 LiveCD 系統中,這可以省下不少空間,甚至在 LiveCD 中,程式執行效能還會增加。程式執行效能增加?何解呢?因為光碟讀取是機械動作,速度極慢,尤其當光碟有刮損、不乾淨時,更是一點點資料讀半天。若是用 upx 將執行檔壓縮成一半大小不到,就可以減少光跌機讀取的時間。如此,速度不就增加了嗎? 如何使用呢? 可以去官方網站 Download 壓縮主程式: http://upx.sourceforge.net/ 裝好後,就可以用 upx 壓縮執行檔了,如下: upx <binary-file> 後記 UPX 除了可處理 Linux kernel 和 ELF 檔外,在其他的平台如 Windows、 DOS上也可運作,官方網站上有詳細的資料。

迷惑

當什麼都想通了,真的就到達神仙的境界了。但是,當什麼都想通了,卻也什麼都迷惑了。很矛盾,卻也不矛盾。因為想不通的是人,運轉的是天啊。或許我的心中真的放不下一片天,才讓我來來去去永遠不停地在原地打轉,永遠看不透藏在人生命運中某個角落的片段。 我可以解釋一切世上發生的事,但卻無法阻檔必須發生的事。就算我知道來龍去脈,但我還是在這洪流之中,無法改變順流而下的命運。乍看之下這多麼可悲,卻也多麼幸運。可悲的是無法逃脫,幸運的是看到了真像。這不是人定勝天這麼簡單,有人一生奮鬥,卻只是為了身為自己而奮鬥,一輩子累積的財富,不外乎名聲錢財。可是,這些東西花一生取得,最後又讓他回歸虛無,這又有何意義?這場遊戲規則到底是誰在定的?我們又是為何被迫要參加這場遊戲?勝天?最多是勝過這遊戲中的命運牌吧!遊戲終究會有它不變的結果。知道嗎?我們都被這宇宙的主宰給徹底玩弄在手掌心了! 真的看不透,隱隱約約藏在心中的不安,那一點點不確定感。知道該這樣走,卻又感覺到這樣走背後另有目地,黑黑的、看不見的意圖,令人毛骨悚然。不過你看得懂我在寫什麼也好,看不懂我在寫什麼也好,一切就是這樣,該會寫的我也寫了,不會被我寫出來的我也不會寫。 嘻嘻哈哈很開心,卻也是灌醉自己的方法。這主宰對我們最大的恩惠,就是情感。我們可以藉由情感,去忽略忘記自己的可悲,去掩蓋別人的可悲,去過的更不一樣。有人生起伏,何嘗不好?

解決 Linux Kernel 2.6 的龐大體積

Linux Kernel 2.6 在設計上進步太多太多了,讓許多人急於跟進。但應該有人會發現,當 2.6 版的 kernel 編譯好後,他的 Modules 居然有快 400mb!真的是技術進步,身材也跟著進步了呢! 解決辦法就是用 strip 指令去縮小他。但很多人應該都試過,如果用 strip 去減少模組的大小,這些被處理過的模組都會壞掉不能使用。其實,並不是不能用 strip ,而是要有條件的用,以免刪到模組中重要的東西。你可以使用以下指令可以在不破壞模組程式下,將模組的體積縮小: strip -g -S -d *.ko PS. 關於 strip 有許多 Options,可以自行查閱。 後記 雖然 Linux 核心的模組選單中有自動 strip 模組的項目,但我發現並不是一定有效果,往往就算勾選,最後也是沒有做 strip 的動作。所以,在預設 strip 沒效果的情況下,就可以使用 find 指令搭配上述 strip 方法,縮減模組的體積。