devfs 架設過程實錄

devfs, 讓我想起 Linuxer 第 20 期正好有這麼一篇介紹的文章.
大家可以參考這篇文章來作做看.
以下是我嘗試架設的過程,我使用的kernel是 2.4.7-10:
首先要先把 kernel 中的選項打開,但是第一次進去找,我始終都找不到這個選項,後來把 “Prompt for development and/or incomplete code/drivers” 此選項打開之後,才在 File System 裡面找到.
然後就把他打開,重新 build kernel.
依照慣例,把 vmlinux, vmlinuz, System.map 都複製到 /boot 之後
我很快樂的重新開機,結果,開不起來. poor.
原來是因為沒有安裝 devfsd 的緣故~ Linuxer 的文章中有提到,而我以為 kernel 裡面已經有了說~ sad ~
上網去找到 devfsd.tar.gz, 這是最新的版本,不是 1.3.9 的喔~
下載之後,執行 make 來重新編譯
無法編譯,依照編譯的錯誤訊息指示
我在 linux/devfs.h 裡面的 #define DEVFSD_NOTIFY_CREATE 後面加上
#define DEVFSD_NOTIFY_DELETE 7
這行
同時在 make 的時候改用下列敘述來 make (這是在make時指定環境變數的方法)
KERNEL_DIR=/usr/src/linux make
然後就 compile ok 了
接著執行
make install
依照文章指示,/etc/rc.d/rc.sysint 裡面還要有一行
[-e /dev/.devfsd -a -x /bin/devfsd] && /sbin/devfsd /dev
可是我的 /etc/rc.d/rc.sysint 檔案裡面早就已經有了
注意,這一行要放在很前面喔,否則我猜想可能會開不起來
於是再重新開機
果然就 ok 了~~
可是,文字模式下的滑鼠起不來
於是我又把 /etc/sysconfig/mouse 裡面的 DEVICE 改為 /dev/psaux
重新開機後,文字模式下的滑鼠就 ok 了
可是有些特定的設備,我還不會設定( 設定檔在 /etc/devfsd.conf )
比如我自己寫的一個 driver 還是起不來~~
devfsd 相關的套件,可以利用 Google 搜尋引擎找到.
個人覺得 devfs 與原來的 /dev 相容性蠻高的,幾乎不用作什麼修改.在Documents/filesystems/devfs/README 這份文件說的蠻清楚的,什麼有支援,什麼不支援,裡面都有說~
/dev/mouse 是確定不支援的,要改成 /dev/psaux;其他的一些 driver,我想修改 /etc/devfsd.conf 應該一切都能搞定,只是我還不會設.
coding 的話~~
現在所有中文有關 kernel 的書,講到的 register_chrdev() 都是舊的方法.
如果要支援 devfs 的話,直接使用
devfs_register_chrdev() / devfs_unregister_chrdev()
devfs_register_blkdev() / devfs_unregister_blkdev()
devfs_register() / devfs_unregister()
來註冊,跟原來的語法用法是很接近的
函數的原型參考,可以在 include/linux/devfs_fs_kernel.h 裡面找到
事實上在 devfs_fs_kernel.h 裡面
已經有利用 CONFIG_DEVFS_FS 來作判斷了
當 CONFIG_DEVFS_FS 有被定義的時候, devfs_register() / devfs_unregister() 是有東西的,如果沒被定義,那麼則是空殼子~
此外 devfs_fs_kernel.h 裡面有許多關於 devfs 的函數,而函數的實作則是放在 fs/devfs/base.c 裡面~
driver 寫的時候,建議的順序是這樣子的(看了兩三個driver的source才了解)
1.用 devfs_handle_t 宣告一個 handle.
2.用 devfs_register_chrdev() / devfs_register_blkdev() 註冊裝備的動作,MAJOR號碼以及名稱
3.再用 devfs_register() 去 /dev 裡面註冊一個設備檔案
當然如果有很多的話,可以先用 devfs_mk_dir() 去註冊一個目錄,再利用 devfs_register_series() 去註冊一狗票的設備檔案或者利用迴圈去註冊一狗票的設備檔案.
然後就 ok 了
release 的時候,則是:
1. 先 devfs_unregister() 掉設備檔案
2. 再 devfs_unregister_chrdev() / devfs_unregister_blkdev()

Stream Server – icecast 架設實錄

前兩個星期在 Linux fab 上看到一則新聞
說 icecast 已經釋出新版本了
But what is icecast?
仔細一看
才明白,原來他是一個 stream server,就類似微軟的 media service.
這樣講也許還不是很清楚,拿個實例來說吧:如廣播電台,目前廣播電台都已經可以在網路上收聽了,他們就是架設一個 server 並提供一個 url, 讓你在 media player 或 real player 裡面輸入,於是你就可以收聽到即時的節目了.又比如之前紅極一時的Naked News也是這樣子做的,只是他們輸出的是影音新聞節目.
架設的時候你必須到 icecast 網站先取得 icecast 套件,目前最新的版本是 1.3.11.
取得之後,依照 linux 的慣例安裝三部曲,輸入
./configure
make
make install
於是安裝完成~~
接下來我切換到套件預設的安裝路徑 /usr/local/icecast/
將 conf 裡面的 icecast.conf.dist 複製到 /etc, 並命名為 icecast.conf
修改裡面的
streamurl 為 http://redhat71
server_name 為 redhat71
接著就要啟用囉
請輸入
/usr/local/icecast/bin/icecast -c /etc/icecast.conf -b
以啟動 icecast server
當然到這裡都很簡單,只是依照套件內附的文件行事而已
接下來,要怎麼讓音樂播放出來呢??
這可讓我傷透了腦筋
最後才在 icecast 網站的 getting start找到方法.
我用的是 shout, 這同樣也是 icecast 網站提供的另外一個套件
請下載 shout ,依照 linux 慣例安裝三部曲來安裝.
接著,要製作 mp3 play list
我們可以利用如下指令來製作
find /mnt/cdrom -name *.mp3 -print >> /etc/mp3.lst
不過據我實驗的結果,中文的檔案名稱似乎無法用 find 來取得~~討厭~~
本來想把所有的 mp3 都用 stream server 來播放的~
最後就可以使用如下的指令來將 mp3 塞到 stream server 了
/usr/local/icecast/bin/shout localhost -P hackme -a -x -p /etc/mp3.lst -l -n “A sample name”
shout 可接的參數,在此就不再贅述,可以自行加上 –help 參數來取得.
(看到 localhost 了嗎??這表示你也可以從遠端來控制要播出的節目喔.)

RPM常用指令

rpm 的幾個必要用法:
安裝:
rpm -i lcdctld-1.0.0-1.i386.rpm
rpm -ivh lcdctld-1.0.0-1.i386.rpm #加上 vh 是顯示安裝進度及狀態
rpm -i ftp://your_site/lcdctld-1.0.0-1.i386.rpm #從 ftp 站下載並安裝
升級:
rpm -U lcdctld-1.0.1-1.i386.rpm
rpm -Uvh lcdctld-1.0.1-1.i386.rpm #加上 vh 是顯示升級進度及狀態
移除:
rpm -e lcdctld-1.0.0-1.i386.rpm
求助:
rpm –help
man rpm
如何了解目前 rpm 包的一個狀態(用個大陸用法”包”,別介意):
檢查是否有檔案被誤刪:
rpm -Va
查詢檔案屬於哪個包:
rpm -qf /usr/sbin/lcdctld
查詢包的資訊
rpm -qpi lcdctld-1.0.0-1.i386.rpm
查詢包裡面的檔案會被安裝到哪兒
rpm -qpl lcdctld-1.0.0-1.i386.rpm
怎麼建立包
建立包的程序,你可以參考上一篇的程序.
.spec 的格式說明
要注意的一點,一般一個包,裡面會包含 Source 和 Binary.
Header
.spec 檔是挺重要的檔案,有幾個 header,咱們必得放進去:
Summary:放一行簡單的說明
Name:放包的名稱
Version:放包的版本
Release:放包的釋出編號
Copyright:放包的版權宣告,譬如:GPL,BSD,MIT,public domain, distributable或 commerical
Group:包的分類,參考後面的附表一
Source:來源檔案的檔名,可以有多個,多個的時候,則用 Source0, Source1…
Patch:修正包的檔名,同樣地,可以有多個,多個的時候,用 Patch0, Patch1…
[*]BuildRoot:指定一個安裝路徑,通常命名為 name-root.
description 則可有可無~,建議是放上去,作一個詳細的說明,因為 Summary 提供的說明只有一行而已
Sections
prep:這個 section 一開始通常是放 %setup,%setup會先把SOURCES裡面的包解開放到 BUILD 目錄,再切換到該目錄下.再者就是 %patch,可以讓你對源碼作 patch 的動作,如果你前面的 header 有多個 patch 檔,那麼這裡只要用 %patch0 -p1 %patch1 -p2 就行了.
build:這個 section 則是建立.我參考 thttpd.spec, thttpd.spec 在這裡是放 configure 的動作,我認為此處也可以順便做 make的動作,反正都已經解開也patch過,Makefile 也出來了.不過一般似乎都是已經先 make 好了.
install:這個 section 就是放安裝的動作了,在這裡除了用笨方法 %{__mkdir}, install..等一些 shell script 去安裝之外,還可以用 make install 去安裝,這正好證實了我的推論,在 build section 中可以用 make.
clean:把之前在 prep section 解開放到 BUILD 的目錄給移除掉.
可有可無的Sections
pre:作安裝前的準備,yes, 就是 On_BeforeInstall
post:作安裝後的處置, yes, 就是 On_AfterInstall
preun:作移除安裝前的準備, 嗯, 就是 On_BeforeUnInstall
postun:作移除安裝後的擦屁股動作,就是 On_AfterUnInstall
files Section
這是一個很重要的 section, 他記錄了這個包有放什麼檔案到什麼地方.
簡單的用法就是寫
/usr/sbin/lcdctld
直接以絕對路徑+檔名指明,當然這樣子很累啦.
rpm 包有提供一些 macro 讓你省去這樣子的功夫.
%doc
%config
%dir
%defattr
%files
%doc 的位置是 /usr/doc/name-xx.xx.xx-xx, 你可以這麼用: %doc README INSTALL HISTORY ChangeLog
%config 就是指一些設定檔,例如: /etc/xxxxxx
%dir 表示特定屬於這個包的目錄,舉例來說就是 /etc/httpd/
%defattr 設定檔案的屬性,語法是 %defattr (mode,owner,group) filename
%files 看不懂,我猜應該跟直接列出檔名是一樣的
不過我看 thttpd.spec, %dir 可以直接用 /etc/httpd 來代替,前面不需要加上%dir, %defattr 則可以用 %attr 來代替.
changelog Section
這主要是讓維護包的人,可以放歷史紀錄,格式是
* Fri Dec 14 2001 Ellery Tsai
– do nothing, but eat, drink, sleep.
打包
打包的語法是:
rpm -ba lcdctld-1.0.0.spec

rpm -bb lcdctld-1.0.0.spec
ba 跟 bb 的差別是,ba 會連 source 和 binary 都打包,結果會產生兩個 rpm ,而 bb 只包 binary,只出現一個 rpm.
其他還有一些用法:
列出 files section 的檔案
rpm -bl lcdctld-1.0.0.spec
只做某些步驟,我猜想是便於內部測試用:
rpm -bc lcdctld-1.0.0.spec
rpm -bi lcdctld-1.0.0.spec
rpm -bp lcdctld-1.0.0.spec
建議
建議最好是先到 SOURCES 去手動一步一步來
先解開 tar 檔,並且先複製一份,並更名為 name-xx.xx.xx.orig,這主要是為了方便製作 patch 用.接著,依照說明去作:
patch
configure
make
make install
在 make install 的時候,順便把檔案位置都記下來,然後再把位置放到 .spec 檔中的 files section 裡面.
如果在前面幾個步驟,有需要修正一些東西,那麼表示你要做一個 patch 檔
作 patch 檔的語法如下:
diff -uNr name-xx.xx.xx.orig name-xx.xx.xx > name-xx.xx.xx-linux.patch
接著到 .spec 檔裡面的 patch header, 作修正.
最後
Yes, That’s All.
資料來源:RPM HOW-TO
此份文件在 \\xserver\linux\Datasheet\Linux-HOWTOs\English_pdf 這裡有.
附表一:
Amusements/Games
Amusements/Graphics
Applications/Archiving
Applications/Communications
Applications/Databases
Applications/Editors
Applications/Emulators
Applications/Engineering
Applications/File
Applications/Internet
Applications/Multimedia
Applications/Productivity
Applications/Publishing
Applications/System
Applications/Text
Development/Debuggers
Development/Languages
Development/Libraries
Development/System
Development/Tools
Documentation
System Environment/Base
System Environment/Daemons
System Environment/Kernel
System Environment/Libraries
System Environment/Shells
User Interface/Desktops
User Interface/X
User Interface/X Hardware Support

RPM製作簡單說明

在此直接以我在公司開發的 lcd daemon 來作為實例
首先把我的 lcd daemon 編譯過,得到 lcdctld, 假設為 1.0.0 版,release 第一次
接著,隨便在某個地方建立目錄,命名為 lcdctld-1.0.0
在裡面建立 /usr/sbin
然後把 lcdctld 放到 lcdctld-1.0.0/usr/sbin 裡面去
利用
tar cvzf lcdctld-1.0.0.tar.gz lcdctld-1.0.0
這個指令得到 tar.gz 檔案
把這個檔案丟到 /usr/src/redhat/SOURCES 裡面去
接著就是最重要的地方了
要編輯 lcdctld.spec 檔案
內容如下:

%define name lcdctld
%define ver 1.0.0
Summary: MS-9507 LCD Daemon
Name: %{name}
Version: %{ver}
Release: 1
License: Micro Star Inc.
Group: System Environment/Daemons
BuildRoot: %{_tmppath}/%{name}-%{ver}-root%
description
lcdctld is a daemon that listen MS-9507 device.
%prep
%setup -q
%build
%install
rm -rf $RPM_BUILD_ROOT
%{__mkdir} $RPM_BUILD_ROOT/
%{__mkdir} $RPM_BUILD_ROOT/usr
%{__mkdir} $RPM_BUILD_ROOT/usr/sbin
install -m555 usr/sbin/lcdctld $RPM_BUILD_ROOT/usr/sbin
rm -f tmp
%cleanrm -rf $RPM_BUILD_ROOT
%files/usr/sbin/lcdctld

這裡面有很多東西,建議直接找個範本來修改比較好,我是直接拿 thttpd 的來作修改.
主要要修改的有上面的欄位:Summary, License, Name, Version, Group, …等等的
還有 %install 開始的地方,這裡主要就是寫複製檔案的 script.事實上, RPM 會自動把你 SOURCES 下的 tar.gz 檔解開,所以你只要把對應的檔案複製到 RPM_BUILD_ROOT 對應的目錄去就好了.
最後還有 %files ,如果這裡沒有東西,rpm 會發生錯誤.這裡主要是放檔案的列表,讓 rpm 知道這個 package 裡面有什麼檔案.
編輯好 lcdctld.spec 之後,輸入
rpm -bb lcdctld.spec
順利的話,你應該會在 /usr/src/redhat/RPMS/i386 目錄下看到 lcdctld-1.0.0-1.rpm 才對~~
你可以使用
rpm -Uvh lcdctld-1.0.0-1.rpm
來安裝
然後使用
rpm -e lcdctld-1.0.0-1
來移除
.spec 裡面的一些用法
%define -> 定義一些變數
%{xxx} -> 引用變數
%{_tmppath} -> 會指到 /var/tmp 下面
%{__command}-> shell的指令幾乎都可以引用,只是前面要加上兩個底線,例如 mkdir 就是 %{__mkdir}.
%prep
%setup
%build
%install
%clean
%files -> 這些都是表示特定的步驟,雜誌上只說在 %install, %clean, %files 要加東西而已,其他不清楚
我想這樣子在目前的使用上,應該就足夠了吧~
將來如果有新的發現,會在這個主題上繼續累加~
資料參考來源: Linuxer 雜誌第 12 期以及 Linux in a NutShell
Linux in a NutShell 只有說明 rpm 指令有哪些參數而已,完全沒有說明 .spec 檔要如何編輯

NumLock

在 Red Hat 環境下,NumLock 老是關閉的(Mandrake 不會)
如果懶得一個一個去把 NumLock 按成 On
可以在
/etc/rc.local 最後,放如下指令:[bash]# Enable NumLock
for tty in /dev/tty[1-6]; do
setleds -D +num < $tty
done[/bash]
即可
另外,此行據稱可以加速,但我不知道是什麼意思
[bash]echo “base=0xd8000000 size=0x800000 type=write-combining” > /proc/mtrr[/bash]
也可以一併放在 /etc/rc.local 中

Build Library How-to

程式碼
======
假設 main() 呼叫 iloveso() 這個函式,而且程式分開的話,程式碼就會像這樣子:
callso.c
#include <stdio.h>
void iloveso(void);
int
main(void)
{
printf(“\nmain() begin\n”);
iloveso();
printf(“main() end\n”);
}
iloveso.c
#include <stdio.h>
extern void iloveso(void);
void
iloveso(void)
{
printf(“here is so!!\n”);
}
一般做法
========
一般的情況下,我們會這樣去編譯程式
gcc callso.c iloveso.c –o callso
編譯出來後,直接執行 ./callso 就可以執行程式了。
靜態連結
========
因為 iloveso() 這個函式,其他程式也可能會使用到,我們希望把他獨立出來,這樣子,別人就可以直接連結他,而不需要重新編譯一次。
我們可以先編譯為 obj 檔之後,再利用 ar 指令,將 obj 檔變為 .a (靜態library) 檔。
再執行Ranlib 以確保 .a 檔能跟 unix 相容。
gcc -c iloveso.c -o iloveso.o
ar rcv libiloveso.a iloveso.o
ranlib libiloveso.a
為了驗證這樣子是可行的,請先在 /etc/ld.so.conf 最後加上 /usr/local/lib。
接著執行 ldconfig。然後將 libiloveso.a 放到 /usr/local/lib
執行
gcc –o callso callso.c –liloveso
沒有錯誤訊息的話表示成功,請執行 ./callso 試試。
如果有錯誤的話,通常是因為 ld.so.conf 檔案未設定,或設定後未執行 ldconfig 的緣故。
動態連結
========
當有很多程式都使用同一個靜態Library時,每個程式都會將該靜態連結檔給含括進來,所以會造成空間浪費,我們可以利用動態連結避免掉這個缺點。
同樣的,我們可以利用下列的程式來編譯動態連結檔
gcc -shared -Wl,-soname,libiloveso.so -o libiloveso.so iloveso.c -lc
這樣子就直接產出 libiloveso.so 了。
接下來同樣安裝到 /usr/local/lib,確定ld.so.conf有增加/usr/local/lib後,執行 ldconfig,以完成設定。
然後利用如下指令編譯 callso.c
gcc -o callso callso.c –liloveso
這樣就 ok 了,你可以試著用 ldd callso 去驗證一下,是不是真的有連結到。
結論及注意事項
==============
發現了嗎??不管是靜態或動態,程式碼和程式指令都不曾變更過,只有編譯Library 檔時,有些許差別而已。這對程式設計師來說,真是方便很多。
要特別注意的是Library檔必須以 lib 為開頭;另外,當 .a 和.so 同時存在時,gcc 會自動以 .so 作為優先連結對象,若你要強迫gcc作靜態連結,就要在編譯時加上 –static 。