Pages

顯示具有 Linux 標籤的文章。 顯示所有文章
顯示具有 Linux 標籤的文章。 顯示所有文章

2013年9月24日 星期二

Build Static, Shared and Dynamic Loader Library

這篇文章詳細介紹在Unix-like環境底下, 如何編譯以及使用 static/shared/dynamic loader libraries, 也介紹 shared library 檔名的意義:
http://hsian-studio.blogspot.tw/2008/09/make-library-for-linux.html

2011年12月28日 星期三

Unix-like Command

Join
範例一
$ cat a
3 aa
5 uu
4 bb
7 38
2 oo

$ cat b
uu test
38 abc
oo def

$ sort -k 2 a | sed "s/ /:/" > a.sorted  # 將主 key 做排序, 並將空白變成 ":"
7:38
3:aa
4:bb
2:oo
5:uu

Ubuntu Note

uBuntu 更換中文輸入法
  • 例如:要將 iBus 換成 gcin ##ReadMore##

    sudo update-alternatives --config xinput-zh_TW // 整個系統都切換

    或者

    im-switch -s gcin // 只切換該帳號

    設定完,登出再登入即可套用。
  • 網址:http://thaddeusnotes.blogspot.com/2010/09/ubuntu.html

apt 常用參數

apt-cache search [關鍵字] - 搜尋未安裝套件
apt-get install [套件名稱] - 安裝新套件
apt-get remove [套件名稱] - 移除套件但不刪除設定檔
apt-get remove --purge [套件名稱] - 刪除套件也刪除設定檔
apt-cache depends [套件名稱] - 顯示套件相依的相關資訊

apt-get clean - 移除所有套件的 deb 暫存檔
apt-get autoclean - 移除舊版所有套件的 deb 暫存檔
ps: apt 下載安裝過的檔案會放在 /var/cache/apt/archives/ 裡面,
apt-get clean / autoclen 會清除在裡面的檔案。所以只要沒執行過這兩個指
令,都可以到這個路徑看到已經有安裝過哪些檔案。

apt-cache show [套件名稱] - 列出套件詳細資訊
apt-cache stats - 套件庫中的資訊
apt-setup - 設定 /etc/apt/sources.list

apt-get update - 更新套件索引
apt-get upgrade - 升級已安裝套件
apt-get dist-upgrade - 考慮套件相依性進行升級
apt-get -s dist-upgrade - 列出過程中執行的動作
apt-get -d dist-upgrade - 僅下載相關套件,而不安裝
apt-get -y dist-upgrade - 用 yes 回答所有設定問答
apt-update.sh
#! /bin/bash
apt-get update
apt-get -y -d dist-upgrade
apt-get -s dist-upgrade
<來源> http://jctalk.blogspot.com/2008/01/apt.html


RPM 轉 DEB 工具 - Alien

Alien 是一個將 rpm, dpkg, stampede slp 及 slackware tgz 檔案格式間轉換的工具。

$ sudo apt-get install alien
$ sudo alien -d name-of-rpm-file.rpm

[註] 需要有 root 權限才可以轉換,當然轉換後可以依需要 chown、chgrp、chmod。


開機自動掛載 ntfs 檔案系統
/etc/fstab 可以自動掛載特定的檔案系統,特別在系統啟動的時候。在這個檔案裡,描述了檔案系統,掛載點和其他選項。下面是一個/etc/fstab檔案的內容:


/dev/hda1       /                      ext2          defaults              1 1
/dev/hda5       /home             ext2           defaults              1 2
/dev/hda6       swap              swap         defaults              0 0
/dev/fd0         /mnt/floppy     auto           sync,user,noauto,nosuid,nodev,unhide 0 0
/dev/cdrom     /mnt/cdrom     auto          user,noauto,nosuid,exec,nodev,ro 0 0
none                /proc              proc          defaults              0 0
none                /dev/pts          devpts      mode=0622        0 0


每一行的參數按照順序代表
  • 擁有檔案系統的裝置,
  • 掛載點
  • 檔案系統型態
  • 掛載選項
  • 備份程式dump的旗標
  • fsck(FileSystem Check)檢查分割區的順序
所以說,如果我想把 ntfs 的檔案系統在開機就自動掛載上去,就修改這個檔案。例如:

/dev/sda2 /media/disk ntfs defaults 0 2

然後在 /media 建立一個對應的資料夾: sudo mkdir /media/disk。至於最後一個參數通常就擺「2」,可以 man 看看。

使用 fuser 的指令
要怎麼找出是哪個程式掛在那個目錄上, 可以使用 fuser - identify processes using files or sockets

假設現在 mount 起來的目錄是 /media/share
查詢:  
               fuser -m /media/share
顯示:
               /media/share: 25023c

就代表是 process 25023(pid) 有使用到此目錄, 後面 c 代表的意思可參考下述:
c: current directory.
e: executable being run.
f: open file. f is omitted in default display mode.
F: open file for writing. F is omitted in default display mode.
r: root directory.
m: mmap'ed file or shared library.

要把這個資源釋放的話, 可以有下述做法:
1) kill -9 25023 # ps aux | grep 25023 
2) fuser -m -v -i -k /media/share # 會問你是不是要把 25023 這個 kill 掉, 選 y 就會 kill 掉
    訊息如下:
    USER PID ACCESS COMMAND
    /meida/share: root 25023 ..c.. bash
    Kill process 25023 ? (y/N) y

http://plog.longwin.com.tw/my_note-unix/2008/11/18/debian-ubuntu-linux-umount-device-busy-2008


不用密碼直接用 ssh 登入到遠端電腦
多年前 telnet 當道,但在安全意識漸漸浮上檯面之後,telnet 在登入時的安全就被大家質疑,後來 ssh (Secure Shell) 出現時,改變了當初的習慣,大家在管理 Linux 時,現在都使用 ssh 來登入,而 ssh 好處我在這也不再多做說明,因為他還可以配合 rsync 做出遠端備份,一旦設定好 ssh 之後,還會有 scp 可以使用!這樣就可以在不同電腦間 copy 檔案,並且為傳輸的資料加密了!

Shell Script & ssh

自動化的工作可以讓管理員有效率的完成目標,也不用浪費人力和時間做同樣的事情,在無人職守的情況下,要讓 script 自動連入遠端系統做事是件有些麻煩的事,因為您必需登入系統才可以繼續工作,為了不略過登入系統這個步驟,我們可以製做一個
public key 讓遠端的機器信任我們,如此就只要直接連入就可以,而不用再輸入帳號和密碼。


製作 public keys & private keys

利用 ssh-keygen 來做出公用和私有鑰匙,並傳送 public key 到遠端機器使其信任本機登入。

[steven@cute steven]$ ssh-keygen -t dsa

Generating public/private dsa key pair.
Enter file in which to save the key (/home/steven/.ssh/id_dsa):
Enter passphrase (empty for no passphrase): <- 不用輸入
Enter same passphrase again: <- 不用輸入
Your identification has been saved in /home/steven/.ssh/id_dsa.
Your public key has been saved in /home/steven/.ssh/id_dsa.pub.
The key fingerprint is:

fa:c9:a9:e4:d5:70:52:88:cc:f3:25:fd:68:ae:c4:4b steven@cute.com.tw

[steven@cute steven]$


接著,再到 /home/steven/.ssh 裡看看,會多出 id_dsa 和 id_dsa.pub 這兩個檔案。

[steven@cute steven]$ cd .ssh
[steven@cute .ssh]$ ls
id_dsa id_dsa.pub known_hosts
[steven@cute .ssh]$


現在我們要使遠端機器 mirror.abc.com,使用 sandy 登入時不用輸入密碼,因為,我們應該複製一份 id_dsa.pub 到 sandy@mirror.abc.com 去,並加入到 authorized_keys。


[steven@cute .ssh]$ scp id_dsa.pub sandy@mirror.abc.com:~/id_dsa_steven.pub
sandy@mirror.abc.com's password:
id_dsa.pub 100% |*****************************| 607 00:00

[steven@cute .ssh]$


登入 sandy@mirror.abc.com

[steven@cute .ssh]$ ssh sandy@mirror.abc.com
sandy@mirror.abc.com's password:
-bash-2.05b$ ls id_dsa_steven.pub
id_dsa_steven.pub
-bash-2.05b$ cat id_dsa_steven.pub >> .ssh/authorized_keys
-bash-2.05b$ exit

完成後離開,回到本機,再做一次 ssh 到 mirror.abc.com

[steven@cute .ssh]$ ssh sandy@mirror.abc.com
-bash-2.05b$

如此就不用輸入密碼就直接登入了!


保護你的私有金匙

在製做 dsa key 時,會有一份私有和一份公有金匙,實務上會保留起來,並做備份,因為當 ssh 在登入時,會使用 id_dsa.pub 和本機的 id_dsa 做確認,因此如果這兩者比對不成功時就會再次要求輸入密碼。

參考資料 http://www.l-penguin.idv.tw/article/ssh-keygen.htm


Ubuntu Linux下single模式無需密碼方法
  1. 按Esc進入系統啟動功能表,選擇"Ubuntu, kernel 2.6.20-16-generic (recovery mode),然後按e。
  2. 在第二層功能表選擇"kernel /boot/vmlinux-2.6.20-16-generic root=UUID=ae424e-bod0-475c-2342433 ro single" 按下e進行編輯。 
  3. 修改啟動參數為"kernel /boot/vmlinux-2.6.20-16-generic root=UUID=ae424e-bod0-475c-2342433 rw single init=/bin/bash" 然後按回車。 
  4. 按b啟動系統就可以進入single模式而不需要密碼了。
參考資料
http://big5.ccidnet.com:89/gate/big5/linux.ccidnet.com/art/302/20080605/1467721_1.html

VMWare 的 Linux 對於 mplayer 的設定
首先要先安裝 codec,不管是不是用 VMWare 都要裝:

sudo wget http://www.medibuntu.org/sources.list.d/gutsy.list -O /etc/apt/sources.list.d/medibuntu.list &&
wget -q http://packages.medibuntu.org/medibuntu-key.gpg -O- | sudo apt-key add - && sudo apt-get update && sudo apt-get install w32codecs


接著開啟 mplayer,"按右鍵 -> Performance -> Vedio -> 將 xv 改成 x11",重開 mplayer 即可。另外,記得要"按右鍵 -> Performance -> Font",選個字型檔載入。 例如:/usr/share/fonts/truetype/arphic/ukai.ttf


在 Windows 環境下遠端 Linux
做法一
這裡用 client 是 Windows XP;server 是 Ubuntu

Server端 - 安裝VNC
% sudo apt-get install x11vnc
% sudo x11vnc -storepasswd [password] /etc/x11vnc.pass
執行VNC
% sudo x11vnc

Client端至 http://www.realvnc.com/index.html 下載 vncviewer 安裝連線即可

做法二
直接用 Windows XP 的遠端工具即可,但沒嘗試過,參考網頁 http://axp1.csie.ncu.edu.tw/~rick/blog/?p=117


安裝字型
在終端機裡以「su」指令切換到「root」,也就是管理員的身份(請注意:在Ubuntu裡切換root身份的方法是用「sudo」,在Fedora裡也可以用sudo,不過筆者偏好使用su),然後把arialuni.ttf複製到「/usr/share/fonts/」目錄下:

程式碼
cp 來源子目錄/arialuni.ttf /usr/share/fonts/
fc-cache –v –f /usr/share/fonts/

注意:新安裝的系統可能會發生檔案時間在未來,以致fc-cache不能寫入的情況,解決方法就是用touch指令「碰」一下檔案,讓檔案時間變成現在:

touch /usr/share/fonts
touch /usr/share/fonts/*
touch /usr/share/fonts/*/*
touch /usr/share/fonts/*/*/*

再執行一次「fc-cache –v –f /usr/share/fonts/」即可。
做完這兩步,系統裡就多了這個字型讓你選用。GNOME使用者可以到「系統>偏好設定>外觀與感覺>字型」,KDE使用者是到「選單>控制中心>主題與外觀>字型」裡查看,是不是多了Arial Unicode MS這一項呢?要注意除了固定寬度字型,其他都可以改成Arial Unicode MS。

fc-cache指令是什麼?
fc-cache的功能是掃描字型檔的子目錄,然後再建立包含字型資訊的快取(cache)給應用程式。簡單的說就是讓系統登錄指定目錄的字型。在我們執行fc-cache後面的「-f」參數,是強迫寫入(force)的意思,而「-v」是顯示執行資訊(verbose)的意思。




參考資料
http://tech.chinatimes.com/2007Cti/2007Cti-News/Inc/2007cti-news-Tech-inc/Tech-Content/0,4703,171701+172007122502835,00.html


備份 VMWare 檔案,之後 restore 造成網路不通的情形發生
前鎮子重灌電腦,便把 VMWare 的 .vmdk 以及 .vmx 備份下來,重灌完之後直接把檔案 restore,結果發生網路不通,檢查一下發現在 /etc/udev/rule.d 當中 70-persistent-net.rules 的這一行:

# PCI device 0x1022:0x2000 (pcnet32)
SUBSYSTEM=="net", DRIVERS=="?*", ATTRS{address}=="00:0c:29:0b:8e:62", NAME="eth1"

linux 應該以 eth0 為預設的網卡,不過這邊會是 eth1,我想應該是因為當初是在有 Windows 的情況下去安裝 Ubuntu,雖然是共享實體網卡,不過虛擬機器讓 Ubuntu 以為有另一張網卡,所以才會是 eth1。

不過現在的情形我並沒有重新安裝 Ubuntu,而是直接 restore,在沒有依正常管道安裝的情況下,Ubuntu 會以預設的 eth0,去抓網卡,導致偵測不到。所以結論就是,只要把以上用螢光筆畫下來的部份改成 eth0 即可。


安裝 ubuntu 後的基本設定
紀錄一下安裝完畢後設定網路的部分,到 /etc/network/,sudo vi interfaces
將底下內容
# The primary network interface
auto eth0
iface eth0 inet dhcp

修改成底下的固定IP
# The primary network interface
auto eth0
iface eth0 inet static
address 140.113.208.102
netmask 255.255.255.0
gateway 140.113.208.254
dns-nameservers 140.113.1.1

然後 sudo /etc/init.d/networking restart
試著 ping tw.yahoo.com,如果發現有問題,可能是DNS設定有誤,到 /etc/resolv.conf
把 nameserver 改成你要的 DNS Server,然後再用上面指令 restart 一次即可
  1. sudo apt-get install build-essential 會安裝基本套件,例如 gcc、g++、linux-library、make, etc。
  2. sudo apt-get install openssh-server 安裝 ssh serevr,然後就可以用 putty or pietty 遠端連線。
  3. 如果要修改自己的PATH,只要修改 ~/.profile 此檔案即可。


scim
搜尋 scim 會列出相關的套件,安裝 scim 、 scim-gtk2-immodule 、 scim-modules-socket (或是 scim-frontend-socket)、scim-chewing 還有 scim-tables-zh (如果原本就已經安裝就可以略過)。選好要安裝這些套件後就按下「套用」它就會開始安裝了。

然後在終端機下執行下列指令:

sudo gedit /etc/X11/Xsession.d/74scim

然後在這個檔案中加入下列內容:

export XMODIFIERS="@im=SCIM"
export GTK_IM_MODULE=SCIM
export QT_IM_MODULE=SCIM
export XIMPROGRAM="scim -d"
scim -d

接著你只需要重新啟動桌面環境就可以了,重新啟動的方法:
  1. Ctrl + Alt + F1 切到 console mode 下登入。
  2. 執行 sudo /etc/init.d/gdm restart

重新啟動 gnome

1) sudo /etc/init.d/gdm restart
2) Ctrl + Alt + backspace


Bash的環境設定說明
和Bash的環境設定有關的檔案有

/etc/profile (主要)
$HOME/.bash_profile (主要)
$HOME/.bash_login
$HOME/.profile
$HOME/.bash_logout (主要)
$HOME/.bashrc (主要)
/etc/bashrc

登入(login)時
先執行 /etc/profile,接著bash會檢查使用者的自家目錄中,是否有 .bash_profile 或者 .bash_login 或者 .profile,若有,則會執行其中一個,執行順序為:

.bash_profile 最優先
.bash_login其次
.profile 最後

這三個檔案只有在登入時,才會被bash讀取

登出(exit/logout)時
bash會檢查使用者自家目錄中是否有 .bash_logout,若有,則bash會執行其中的指令

登入後啟動一個新的shell
此時我們稱之為一個 subshell, 也就是說在命令列中鍵入 bash, 除了原先登入時的bash 之外, 又另外啟動了一個新的 bash shell.

bash 會檢查使用者的自家目錄中是否有 .bashrc,若有則予以執行,可以在在各檔中加入 echo 指令, 以觀察其執行順序。

各檔案用途說明
/etc/profile 由 root 所控管, 用來設定適合全體使用者的shell環境若使用者自己覺得 /etc/profile 的設定, 並不合意, 可以修改自家目錄中的 .bash_profile既然有了 .bash_profile。

為何要有 .bash_login 及 .profile ?這是因為有些人可能是從 Bourne shell 移轉過來的, 那麼, 只要將 Bourne shell 主要的起動檔 .profile 移到自家目錄中, 放棄使用 .bash_profile 及 .bash_login 即可繼續沿用以前的設定環境。

.bash_login 存在理由或許和 c shell 有關, 但因為 bash 和 c shell 二者語法並不完全相容, 因此, 並不建議將 c shell 的啟動檔直接移過來使用。

.bashrc 則是用來設定 subshell 的環境的, 之所以要有這個 .bashrc 是為免 subshell產生時, 又重覆將 /etc/profile 執行一次. 我們發現 .bashrc 中已預先會去執行 /etc/bashrc 的指令, 這表示, 或許 root 會將產生 subshell 時的環境設好了,使用者只要沿用 /etc/bashrc 的內容, 應該不會有任何問題.

.bash_logout 是使用者登出主機之前, 會去執行的設定檔, 如果使用者希望在他登出系統之後, 能幫他自動處理一些瑣事, 比如: 清除暫存檔, 清除螢幕等, 可以在這個檔案中加以設定.

http://linux.tnc.edu.tw/techdoc/Bash-env.htm


vim相關設定
若出現以下語法不支援之類的訊息,就去確認一下是否有安裝 vim,有可能只有安裝 vim-tiny 或者 vim-common,導致以下的設定檔無法使用,可以利用 sudo dpkg -l | grep vim 檢查。

/etc/vim/vimrc
-----------------------------------------------------------------
set nocompatible " use vim defaults
set ls=2 " allways show status line
set tabstop=4 " numbers of spaces of tab character
set shiftwidth=4 " numbers of spaces to (auto)indent
set scrolloff=3 " keep 3 lines when scrolling
set cindent " cindent
set smartindent " smart indent
set autoindent " always set autoindenting on
set showcmd " display incomplete commands
set hlsearch " highlight searches " 將搜尋所符合的關鍵字全部 highlight
set incsearch " do incremental searching
set ruler " show the cursor position all the time " 等同於 set ru,會在右下角顯示游標所在的行數及列數
set visualbell t_vb= " turn off error beep/flash
set novisualbell " turn off visual bell
set nobackup " do not keep a backup file
set number " show line numbers
set ignorecase " ignore case when searching
"set noignorecase " don't ignore case
set title " show title in console title bar
set ttyfast " smoother changes
"set ttyscroll=0 " turn off scrolling, didn't work well with PuTTY
set modeline " last lines in document sets vim mode
set modelines=3 " number lines checked for modelines
set shortmess=atI " Abbreviate messages
set nostartofline " don't jump to first character when paging
set whichwrap=b,s,h,l,<,>,[,] " move freely between files

"set autowrite " auto saves changes when quitting and swiching buffer
"set expandtab " tabs are converted to spaces, use only when required
"set sm " show matching braces, somewhat annoying...
"set nowrap " don't wrap lines
set mouse=a
set backspace=2

if version>=600
syntax on " syntax highlighing

"---- Options for Windows
if has("gui_running")
set guifont=Courier " use this font
set lines=50 " height = 50 lines
set columns=100 " width = 100 columns
set background=light " adapt colors for background
set selectmode=mouse,key,cmd
set keymodel=
else
set background=dark " adapt colors for dark background
colorscheme elflord " use this color scheme
endif

" Filetypes (au = autocmd)
au filetype help set nonumber " no line numbers when viewing help
au filetype help nnoremap <buffer><cr> <c-]> " Enter selects subject
au filetype help nnoremap <buffer><bs> <c-T> " Backspace to go back

" When using mutt, text width=72
"au filetype mail set textwidth=72
"au filetype tex set textwidth=72
"au BufRead mutt*[0-9] set tw=72

" Automatically chmod +x Shell and Perl scripts
au BufWritePost *.sh !chmod +x %
au BufWritePost *.pl !chmod +x %

" File formats
au BufNewFile,BufRead *.pls set syntax=dosini
au BufNewFile,BufRead modprobe.conf set syntax=modconf
endif

" Keyboard mappings
map <F1> :previous<CR> " map F1 to open previous buffer
map <F2> :next<CR> " map F2 to open next buffer
map <silent> <C-N> :silent noh<CR> " turn off highlighted search
map ,v :sp ~/.vimrc<cr> " edit my .vimrc file in a split
map ,e :e ~/.vimrc<cr> " edit my .vimrc file
map ,u :source ~/.vimrc<cr> " update the system settings from my vimrc file
"----- write out html file
map ,h :source $VIM/vim70/syntax/2html.vim<cr>:w<cr>:clo<cr>:n<cr>,h

" Common command line typos
"cmap W w
"cmap Q q

" Keyboard mapping for numeric keypad " 對應鍵盤右邊的按鍵
imap <Esc>OM <c-m>
map <Esc>OM <c-m>
imap <Esc>OP <nop>
map <Esc>OP <nop>
imap <Esc>OQ /
map <Esc>OQ /
imap <Esc>OR *
map <Esc>OR *
imap <Esc>OS -
map <Esc>OS -

imap <Esc>Ol +
imap <Esc>Om -
imap <Esc>On ,
imap <Esc>Op 0
imap <Esc>Oq 1
imap <Esc>Or 2
imap <Esc>Os 3
imap <Esc>Ot 4
imap <Esc>Ou 5
imap <Esc>Ov 6
imap <Esc>Ow 7
imap <Esc>Ox 8
imap <Esc>Oy 9
imap <Esc>Oz 0
" All system-wide defaults are set in $VIMRUNTIME/debian.vim (usually just
" /usr/share/vim/vimcurrent/debian.vim) and sourced by the call to :runtime
" you can find below. If you wish to change any of those settings, you should
" do it in this file (/etc/vim/vimrc), since debian.vim will be overwritten
" everytime an upgrade of the vim packages is performed. It is recommended to
" make changes after sourcing debian.vim since it alters the value of the
" 'compatible' option.

" This line should not be removed as it ensures that various options are
" properly set to work with the Vim-related packages available in Debian.
runtime! debian.vim

" Uncomment the next line to make Vim more Vi-compatible
" NOTE: debian.vim sets 'nocompatible'. Setting 'compatible' changes numerous
" options, so any other options should be set AFTER setting 'compatible'.
"set compatible

" Vim5 and later versions support syntax highlighting. Uncommenting the next
" line enables syntax highlighting by default.
syntax on

" If using a dark background within the editing area and syntax highlighting
" turn on this option as well
set background=dark

" Uncomment the following to have Vim jump to the last position when
" reopening a file
if has("autocmd")
au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$")
\| exe "normal g'\"" | endif
endif

" Uncomment the following to have Vim load indentation rules according to the
" detected filetype. Per default Debian Vim only load filetype specific
" plugins.
if has("autocmd")
filetype indent on
endif

" The following are commented out as they cause vim to behave a lot
" differently from regular Vi. They are highly recommended though.
set showcmd " Show (partial) command in status line.
set showmatch " Show matching brackets.
"set ignorecase " Do case insensitive matching
"set smartcase " Do smart case matching
"set incsearch " Incremental search
"set autowrite " Automatically save before commands like :next and :make
"set hidden " Hide buffers when they are abandoned
"set mouse=a " Enable mouse usage (all modes) in terminals

" Source a global configuration file if available
" XXX Deprecated, please move your changes here in /etc/vim/vimrc
if filereadable("/etc/vim/vimrc.local")
source /etc/vim/vimrc.local
endif
http://packages.ubuntu.com/edgy-backports/editors/vim-common


USB 無法自動讀入
錯誤訊息:
Cannot mount volume
Unable to mount the volume 'IBM_PRELOAD'

Details:
Volume is scheduled for check. Please boot into Windows TWICE, or use the 'force' mount option. For example type on the command line:

mount -t ntfs-3g /dev/sdb1 /media/IBM_PRELOAD -o force

Or add the option to the relevant row in the /etc/fstab file: /dev/sdb1 /media/IBM_PRELOAD ntfs-3g defaults,force 0 0

手動掛載吧!
sudo mkdir /media/windows
sudo mount -t ntfs-3g -o force /dev/sdb1 /media/windows

看不到中文的話,執行 sudo mount -o iocharset=utf8 /dev/sdb2 /media/USB/

Linux Driver Build & Common Struct/API

msleep

說明:對 msleep() 的調用是不可中斷的,能確保進程睡眠至少給定的毫秒數。
 

     void msleep(unsigned int msecs)
     {
         unsigned long timeout = msecs_to_jiffies(msecs) + 1;
         while (timeout)
             timeout = schedule_timeout_uninterruptible(timeout);
     } ##ReadMore##

參考:



dmesg
  • 在 kernel module 中 printk,可以透過 dmesg 印出訊息,至於訊息的內容,<x> 是優先權;[xxxx.xxxxxx] 是時間,單位是秒。
<4>[ 8544.290000] 14: get interrupt
<4>[ 8544.290000] [x,y]=(583,259)14: input_sync
<4>[ 8544.320000] [x,y]=(583,259)14: input_sync



Device Node

  • MKDEV (引入標頭檔 #include <linux/cdev.h>)mudule_init 的 callback function 中加入
    -----------------------------------------------------
    struct cdev * Videocdev;
    int ret;
    dev_t devNum;
    devNum = MKDEV(88, 0);
    ret = register_chrdev_region(devNum, 2, "/dev/video1" );
    Videocdev = cdev_alloc(); // struct cdev *cdev_alloc(void);
    cdev_add( Videocdev , devNum , 1 ); // int cdev_add(struct cdev *, dev_t, unsigned);

    Videocdev->owner = THIS_MODULE; // #define THIS_MODULE (&__this_module)
    Videocdev->ops = &uvc_fops;
    mudule_exit 的 callback function 中加入
    -----------------------------------------------------
    cdev_del(Videocdev); // void cdev_del(struct cdev *);
    unregister_chrdev_region(MKDEV(88, 0) , 2); // extern void unregister_chrdev_region(dev_t, unsigned);
    另外在程式中用 mknod 建立裝置節點。


Copy Function

  • copy_to_user:
    當應用程式利用 read 讀取某裝置的資料,例如 camera,整個呼叫過程是:read -> ... -> sys_read -> ... -> read file operation,然後 uvcvideo driver 裡頭實作 read file operation,就會透過 copy_to_user,把資料複製給應用程式。
  • copy_from_user:
    當應用程式利用 write 寫入資料到某裝置,就會呼叫這支 API。

Task Struct

  • task_struct:這個結構定義在 #include/linux/sched.h,他就是我們熟知的 Process Control Block,他紀錄著一個行程的一大堆資訊,參考網址。如果我們想要知道目前取得 cpu 執行的程式名稱、process id 等等,可以透過巨集 current 來得到。
char process_name[] = current->comm; // 目前執行的應用程式名稱
pid_t process_id = current->tgid; // process id (thread group id)
pid_t thread_id = current->pid // thread id

[註] 若沒有使用執行緒,則 pid = tgid。


Atomic Operation

  • 連動運算(Atomic Operation):
    我們平常做的 ++a 其實是兩個動作:加法與指派。為了確保這兩個指令連續執行,所衍生的產物。若沒有這種東西,而程式開發者也未對資料做同步,就會因為 race condition 造成資料上的問題。

#include <asm/atomic.h> // typedef struct { int counter; } atomic_t;

atomic_t count = ATOMIC_INIT(0);

atomic_dec(&
count); // 將值遞減1

atomic_inc_return(&
count); // 將值遞增1,並回傳目前的值(回傳整數)

atomic_inc(&
count); // 將值遞增1

atomic_read(&
count);
// 讀取目前的值(回傳整數)

...


Asynchronous Notification

  • 異步通知(Asynchronous Notification):
    這是驅動程式用來發送 signal 給應用程式的方式,而發送的訊號類型為 SIGIO。原始碼
For Kernel Space(device driver)

#include <linux/fs.h>

static struct fasync_struct async_queue; // 資料結構

kill_fasync(&async_queue, SIGIO, POLL_IN); // 發送通知給 file owner

static int uvc_v4l2_fasync(int fd, struct file* filp, int mode)
{
     int ret = fasync_helper(fd, filp, mode, &async_queue); // 加入異步通知的名單
     return ret;
}

uvc_v4l2_fasync(-1, file, 0); // 從異步名單中移除

struct file_operations uvc_fops = {
     .owner = THIS_MODULE,
     .open = uvc_v4l2_open,
     .release = uvc_v4l2_release,
     ....
     .fasync = uvc_v4l2_fasync, // 新增 file operation
};

For User Space(application)

#include <signal.h>
#include <fcntl.h>

// 利用 F_SETFL 請求加入通知名單,這會對應到 .fasync operation
void set_fcntl(int fd) 
{
     int ori_flags;
     fcntl(fd, F_SETOWN, getpid());
     ori_flags = fcntl(fd, F_GETFL);
     fcntl(fd, F_SETFL, ori_flags|FASYNC); // 加入通知名單
}

int main(int argc, char* argv[])
{
     ...
     int fd = open("test.txt");
    
set_fcntl(fd);
     ...
     return 0;
 
}



IPC

因為 driver 是 kernel module 的一部分,是用來提供給許許多多應用程式使用,所以函式大多定義成 reentrant,這時候如果有共享資料,就必須考慮的同步。
  • 同步控制(一):Semaphore
#include <asm/semaphore.h>
static struct semaphore sem;


sema_init(&sem, 1); // 可自行設定初值

init_MUTEX_LOCKED(&sem); // 初值為0
init_MUTEX_UNLOCKED(&sem);
// 初值為1

if(down_interruptible(&sem)) return -ERESTARTSYS; // sem--,可中斷的版本

Critical Section
up(&sem);
  • 同步控制(二):Mutex
#include <linux/mutex.h>
struct mutex mymutex;

mutex_init(&mymutex);
// 設定初值,且值為1



mutex_lock(&mymutex);
Critical Section
mutex_unlock(&mymutex);

不論使用何種同步控制,一定要把值恢復,否則一堆行程都會被卡死,造成系統當機。另外還有一種叫作「spinlock」,和上述兩種的差異是,spinlock 是 busy-waiting 的,所以,該同步控制的 Critical Section 絕對不能休眠(ready->sleep)。
  • 同步控制(三):Spinlock
#include <linux/spinlock.h>

static spinlock_t rw_lock;

spin_lock_init(&rw_lock);

spin_lock_irqsave(&rw_lock, irq_flags);
spin_unlock_irqrestore(&rw_lock, irq_flags);

spin_lock(&rw_lock);
spin_unlock(&rw_lock);


參考資料:http://www.lslnet.com/linux/f/docs1/i34/big5261423.htm



Build Kernel/Driver

驅動程式編譯的方式有兩種,一種是透過 /usr/src/ 底下的 kernel source tree(kernel header);另一種就是直接和 kernel source code 一起編譯。以下要說明若使用後者時,應該如何設定 Kconfig 和 Makefile:

假設要將 EC driver 加入,先放置到相關的資料夾中(應該是 xxx/driver/ 之類的),然後需修改四個檔案:
  1. driver/Kconfig 
  2. driver/Makefile
  3. driver/compalec/Kconfig 
  4. driver/compalec/Makefile

底下簡單截取片段...

driver/Kconfig
# drivers/Kconfig
menu "Device Drivers"
...
source "drivers/auxdisplay/Kconfig"
source "drivers/uio/Kconfig"
source "drivers/android/Kconfig"
source "drivers/uvcvideo/Kconfig"
source "drivers/compalec/Kconfig"
endmenu

driver/Makefile
obj-y += android/
obj-$(CONFIG_SSB) += ssb/
obj-$(CONFIG_VIRTIO) += virtio/

obj-$(CONFIG_UVCVIDEO) += uvcvideo/
obj-$(CONFIG_COMPAL_EC) += compalec/

driver/compalec/Kconfig
#
# Block device driver configuration
#
menuconfig COMPAL_EC_DRIVER
bool "Compal Ec"
default y
---help---
Say Y here to get to see options for Compal Ec driver.
If you say N, all options in this submenu will be skipped and disabled;
only do this if you know what you are doing.
if COMPAL_EC_DRIVER # if choosing menuconfig item, keep going config COMPAL_EC
tristate "Compal Ec driver"
---help---
This is the Compal Ec driver. Say Y or M.
endif # COMPAL_EC_DRIVER

driver/compalec/Makefile
EcIO-objs := EcIOMain.o EcLowerApi.o EcIndexMode.o EcPortCtrl.o Ec686C.o
obj-$(CONFIG_COMPAL_EC) += EcIO.o

[註] 下 make menuconfig 去重編 kernel,可以設定要將驅動程式 build-in(*) 或者 module(M),前者就讓選項空白;後者就讓選項顯示 M。
前者是開機會自動載入;後者用 lsmod 可以看到。


[註] 使用「make menuconfig」或者「make bzImage」前,須先把 gcc(build-essential)、make、以及 libncurses5-dev 安裝完畢。

2011年5月6日 星期五

config.gz

想了解 kernel config 的設定,可以在開機進入系統後,利用 adb tool 輸入以下指令:##ReadMore##
./adb pull /proc/config.gz

  解壓縮這個檔案,就可以得知 kernel configuration。例如:我想要把 VPN enable,Android OS 的部分已經完成,只須將底層設置打開,這時候就可以把 Nexus One 的 config.gz 拿出來比較一下。不過,想在開機後看到這個檔案,必須在編譯核心時,把 CONFIG_IKCONFIG_PROC=y 才能看到。

2011年3月3日 星期四

Ubuntu 10.04 64bits 安裝 adobe flash player

  如果使用 64 位元的 Ubuntu,安裝 flash player 時,需下載代號為「square」的版本,它是給 64 位元作業系統使用的... <點這裡>。接著依尋以下步驟:
  1. 找到「Download plug-in for 64-bit Linux」,然後下載。
  2. 解壓縮會看到 libflashplayer.so。
  3. 將檔案移動至 /usr/lib/firefox-3.6.8/plugins/。
  4. 重新啟動 FireFox 即可。

2010年12月17日 星期五

Minicom 設定

  minicom 這個工具可以將 kernel debug message 輸出至螢幕,而且是有資料就輸出,如此,就無須一直打 dmesg 這個指令,方便許多。

  首先,將 debug board 接到嵌入式裝置,我拿到的是一片裸板,一端外接在機器;另一端為 USB 輸出,就接在 PC。剩餘的步驟就看參考資料吧!我只點出幾個注意事項:
  1. 對 minicom 做完設定,按「Enter」確認、「Esc」跳出。
  2. 節點名稱:ttyUSBx,x為數字,去 /dev 找數字最大的就好。
  3. 有時候,minicom 會當掉,只好把終端機關掉重開。
  4. 如果輸入 minicom 無法進入設定畫面,就改成「minicom -s」。

參考資料

2009年10月7日 星期三

手動安裝 NVIDIA 顯示卡驅動程式

  每次裝完 Ubuntu,驅動程式都會自動安裝完畢,即使沒安裝到的,也可以從「受限制的驅動程式」去啟動它(像是我的工作機),不過,這次安裝 8.10 的機器,顯示卡是 GeForce 9700M GTS,受限制的驅動程式(173和177)都無法正常啟動,所以必須手動安裝。參考這裡,有詳細的說明,底下把重要的部份列舉出來:##ReadMore##
  1. 到 NVIDIA 驅動程式下載中心找到你要的版本,像我就是下載 GeForce 9M 系列的。下載的檔明為 NVIDIA-Linux-x86-185.18.36-pkg1.run。
  2. 修改檔案權限:chmod +x NVIDIA-Linux-x86-185.18.36-pkg1.run。
  3. 移除安裝過的 NVIDIA 套件:csudo apt-get --purge remove nvidia-*。
  4. 按 Ctrl+Alt+F1 進入文字模式。
  5. 關閉 X window:sudo /etc/init.d/gdm stop。
  6. 開始安裝驅動程式:sudo sh ./NVIDIA-Linux-x86-185.18.36-pkg1.run。過程中會去下載 kernel header,不過會下載失敗(我的 /usr/src/ 底下明明就有了),但沒關係,還是可以編譯並安裝成功。
  7. 重啟 X window:sudo /etc/init.d/gdm start。
  8. 大功告成,利用 glxinfo | grep "OpenGL version string: 看到顯式卡的型號、以及 NVIDIA X Server Settings 修改解析度以及刷新率。
  終於給這台 17 吋寬螢幕的 NB「1440x900」和「73 Hz」最後要提醒的一點是,如果有更新 kernel,記得要重新安裝驅動程式。

2009年9月17日 星期四

diff && patch

  這兩個指令一起使用等同於大陸人所說的「補丁」,目的就是當程式有新版的時候,用來替換舊版的做法之一,如果一個專案有需要多人一起修改,使用 patch 配合有意義的檔名,如:camera_preview.patch 會變得比較好管裡,因為可以掌握到底改過哪些地方。

首先,假設有兩個資料夾:
-baijuyi- [/home/Bachelor_91/linly/old] -13:48- ls
a.cc git
-baijuyi- [/home/Bachelor_91/linly/old] -13:48- cat a.cc
#include <iostream>

using namespace std;

int main()
{
a = 3;
}
-baijuyi- [/home/Bachelor_91/linly/new] -13:49- ls
a.cc git
-baijuyi- [/home/Bachelor_91/linly/new] -13:49- cat a.cc
#include <iostream>

using namespace std;

int main()
{
b = 3;
}
  在兩個資料夾都有 a.cc 和 git,而 new 資料夾的 a.cc 檔案中,把 a = 3; 改成 b = 3;,現在要做 patch:
-baijuyi- [/home/Bachelor_91/linly] -13:52- diff -ruN old/ new/ -x git > my.patch
-baijuyi- [/home/Bachelor_91/linly] -13:53- cat my.patch
diff -ruN -x git old/a.cc new/a.cc
--- old/a.cc 2009-09-17 13:48:36.000000000 +0800
+++ new/a.cc 2009-09-17 13:48:04.000000000 +0800
@@ -4,5 +4,5 @@

int main()
{
- a = 3;
+ b = 3;
}
  其中有一個參數:-x git,是省略這個檔案不比,有時候會有一些說明檔在裡頭,沒有必要去 patch 它。接著就是打 patch:
-baijuyi- [/home/Bachelor_91/linly] -13:59- patch -p0 < my.patch
-baijuyi- [/home/Bachelor_91/linly] -14:16- cat old/a.cc
using namespace std;

int main()
{
b = 3; // =>改變了
}
  這樣就完成程式碼的更新了,如果說我到 old/ 這個資料夾打 patch 的話,由於是往下一層,所以要把 -p0 改成 -p1。最後,因為我的用 patch,它會幫我把原先的舊檔案,以原檔名加上 .orig,所以想把這些檔案都刪除的話,可以利用 find 去做:
-baijuyi- [/home/Bachelor_91/linly] -14:03- ls old/
a.cc a.cc.orig git
-baijuyi- [/home/Bachelor_91/linly] -14:03- find . -name '*.orig' -exec rm -f {} ';'
-baijuyi- [/home/Bachelor_91/linly] -14:03- ls old/
a.cc git

2009年2月27日 星期五

驅動程式初體驗

因為需求,必須去了解 Linux Driver,所以就東問西問、看非常艱澀的驅動程式第3版、亂試一通,終於把 Dualview 給弄出來,所以趁著空檔時間,來po個文章..:)。##ReadMore##

這裡先簡單把如何寫一個驅動程式的基本程式碼列出來做說明,當然也可以從歐萊禮下載原始碼來做測試,如果官方網站掛掉還有這裡。
// 定義模組的初始函式(__init)與清理函式(__exit)
#include <linux/init.h>
// 定義許多 module_ 開頭的函式或 MODULE_ 開頭的巨集
#include <linux/module.h>

#define DRIVER_AUTHOR   "Linly"
#define DRIVER_DESC     "Hello World crap driver"
#ifndef DRIVER_VERSION
#define DRIVER_VERSION  "v0.0.1"
#endif

/*
* KERN_ALERT = <1>,代表訊息優先度,最高為 <0>
* 用法同 printf,只是不支援浮點數
*/
static int __init helloworld_init(void)
{
 printk(KERN_ALERT "Hello, world\n");
 return 0;
}

static void __exit helloworld_cleanup(void)
{
 printk(KERN_ALERT "Goodbye, cruel world\n");
}

module_init(helloworld_init);    // for insmod calls
module_exit(helloworld_cleanup); // for rmmod calls

// 模組資訊,可從 modinfo helloworld.ko 查詢
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
■ 說明如下:
  1. 前兩行的標頭檔通常都會加入,作用如註解所述。
  2. module_init 是模組(驅動程式)載入會執行的;module_exit 是模組(驅動程式)移除會執行的。
  3. printk 是寫 kernel module 會使用的 API,因為一般開發應用程式的 API 都不能再撰寫驅動程式時使用,只能使用 kernel API。而優先度的部份共分為七種<0>到<7>,數字越小代表優先度越高,如果你希望訊息可以再你期望的地方印出來,就讓它優先度高一點吧,我通常使用<1>,而這些訊息可以透過「dmesg」看到。
  4. MODULE_LICENSE 一定要加上所規定的一些字串,有幾種選擇,擇一即可,如:"GPL"、"GPL v2"、"GPL and additional rights"、"Dual BSD/GPL"、"Dual MPL/GPL"、"Proprietary"。
  5. 載入模組為「sudo insmod xxxx.ko」;移除模組為「sudo rmmod xxxx.ko」,如果說要重新掛載已經存在的模組,需先移除,然後再載入。  
再來就是 Makefile,它和以往所寫的不同,在於驅動程式使用的是核心提供的函式,所以編譯時必須把目錄切換至 kernel source tree 來做編譯,這個東西可以把它想成是 develop toolkit,像標頭檔就會這裡頭。如果是 Ubuntu,該路徑位於「/usr/src」;如果是 fedora,需要去下載安裝,因為作業系統裝好並不會存在。
KERNEL_VERSION    := `uname -r`
KERNEL_DIR    := /lib/modules/$(KERNEL_VERSION)/build

PWD        := $(shell pwd)

obj-m        := helloworld.o
#module-objs   := helloworld.o

all:
    echo "Building Hello World driver..."
    make -C $(KERNEL_DIR) M=$(PWD) modules

clean:
    -rm -f *.o *.ko *.mod.c Module.symvers version.h

你會看到 KERNEL_DIR 是指派成 bra bra build,不過實際到那邊看,會發現 build 其實是一個 symbolic link,指向 /usr/src/$(KERNEL_VERSION),也就是 kernel source tree。編譯後會回到 pwd,並且在程式的目錄下,產生 .o 檔案,最後再根據 obj-m 的名稱,產生 .ko 檔(如根據 helloworld.o 產生 helloworld.ko)。然後「sudo insmod helloworld.ko」,就可以再 dmesg 看到訊息囉。

2009年2月25日 星期三

Daemon

  Daemon 似乎不需要像 windows service 一樣去註冊,只要讓他開機自動執行即可,而他滿足幾項特性:
  1. 開機後即不斷執行。
  2. 父程序為 init。
  3. 不具有 tty (所以printf是幫不了你)。
  4. 執行者為 root (所以和他通訊的程序也必須是 superuser 所執行)。##ReadMore##

  在「Advanced Programming in the UNIX Environment」一書中提到撰寫 daemon 的規則,不過我也沒遵守,因為不了解這些規則的重要性,不過還是簡單列出該書所提到的部份:
  1. 需呼叫 fork,且父程序直接 exit。
  2. 呼叫 setsid。
  3. 改變工作目錄為「/」。
  4. 把 umask 設定為「0」,避免繼承來的遮罩導致檔案權限不如預期。
  5. 關閉無用的 file descriptor。
#include <sys/type.h>
#include <sys/stat.h>
#include <fcntl.h>

int daemon_init(void)
{
pid_t pid;
if((pid = fork()) < 0)
return -1;
else if(pid != 0)
exit(0);

setsid();
chdir("/");
umask(0);
return 0;
}
  
  以上是本書的初使化範例,不論如何,都需要寫一個 script 讓開機自動啟動 daemon,這裡的作法是在 /etc/init.d/rc.local 去執行我寫的一個 script,當然只要在 rc2.d 中會執行到的 script 中加入都是可以的 [註]。以下列出 script 內容;
#!/bin/sh

[ -x /home/linly/DualView/daemon/Dualview-Daemon ] || exit 0
#filename=/home/linly/DualView/daemon/Dualview-Daemon
#test ! -e $filename && echo "The filename '$filename' DO NOT exist" && exit 0

case "$1" in
start)
# Start daemons.
cd /home/linly/DualView/daemon
./Dualview-Daemon &
;;
stop)
# Stop daemons.
chk=`/usr/bin/pgrep -x Dualview-Daemon`
if [ "$chk" ]; then
echo -n "Shutting down Dualview Daemon "
kill -9 $chk
fi
echo ""
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: Dualview-Daemon {start|stop|status|restart}"
exit 1
esac

cd /home/linly/DualView/uvcvideo
/sbin/rmmod uvcvideo
/sbin/insmod uvcvideo.ko

exit 0

開機後輸入 ps -ajx | grep "Dualview-Daemon" 會看到以下內容:
PPID   PID    PGID   SID    TTY    TPGID  STAT   UID   TIME   COMMAND
1 6038 5067 5067 ? -1 S 0 0:00 ./Dualview-Daemon

  以我的 daemon 為例,由於 shared memory 擁有者是 root,所以權限不足是砍不掉的。而且需要用 signal 來通知 daemon 的應用程式,也必須是 superuser 所執行的應用程式。還有一點,如果需要印訊息,必須透過 syslog 這個 daemon 來達成(因為沒有終端機),以下列出相關的函式:
#include <syslog.h>
void openlog(char *ident, int option, int facility);
void syslog(int priority, char *format, ...);
void closelog(void);

  執行時發生一個問題,就是 gtk_init 無法順利初始化,導致程式被中斷,嘗試很久後,採用 gtk_init_check,該函式即使出始化失敗也不會中斷程式,且能夠順利初使 gdk 的元件,有達到我的需求。(初使做了很多動作,也不知道掛在哪裡,反正我要用的東西有初始好就好拉:P)


注意事項:
  • rc2.d 是一般開機進入圖形介面的過程中,會執行的腳本,像 rc0.d 就是關機會執行的;而 rc6.d 是重新開機會執行的。

2009年2月9日 星期一

Shared memory and Semaphore 的使用

形成通訊是蠻常會遇到的問題。當兩個 process 在執行過程中需要溝通,可以使用許多方式,例如:
  • socket(by AF_UNIX)
  • pipe or fifo
  • file
  • shared memory
  • mmap (我覺得可以歸類到file)
  • message queue (不會用XD)
這裡我所要舉得例子是:shared memory + semaphore。畢竟是共享資源,就要考慮同步,否則會發生 race condition。由於程式碼貼上來過於累贅,我就放在 google doc,程式碼的內容是 P1(write)會一直寫進去,而 P2(read)會去讀取並列印再終端機。[註1]
[註1] 若沒有使用 semaphore,印出來的結果會有重複的內容出現。
[註2] semaphore 是另外包裝的一組 API,提供七個函式,如下:
  1. sem_create - 產生 semaphore,並設定初值。
  2. sem_open - 開啟 semaphore,前題以執行過。
  3. sem_rm - 刪除 semaphore,給 sem_close 使用。
  4. sem_close - 關閉 semaphore,並做刪除(sem_rm)。
  5. sem_op - 給 sem_wait、sem_signal 使用。
  6. sem_wait - semaphore--。
  7. sem_signal - semaphore++。

2009年1月7日 星期三

Linux PAM

PAM 全名為「Pluggable Authentication Module」,是用來做認証的模組。許多程式,如: login、rlogin、sshd、ftpd、su、passwd...等都有支援 PAM,當然你也可以利用 ldd 指令來查詢某程式是否支援 PAM。
##ReadMore##
linly@linly-laptop:~$ ldd /usr/bin/passwd
...
libpam.so.0 => /lib/libpam.so.0 (0xb800f000)
libpam_misc.so.0 => /lib/libpam_misc.so.0 (0xb800b000)
...
PAM 有許多有趣的應用,例如:利用指紋辨識或臉部辨識登入電腦、限制某項服務的使用時間,資源,次數、設定密碼時檢查密碼強度等等。在陳柏菁的 PAM 認証模組 網頁中有詳細介紹 PAM 是什麼?該如何設定?在此就不加贅述,不過要提醒讀者幾件事情:
  1. 認証模組有堆疊特性:設定時可以使用多種認証方式。
  2. control flag 的先後次序:例如 sufficient 放在 required 之後來使用,那 sufficient 模組的成功與否就會被忽略。
  3. 要了解每種 control flags 的意義:例如 required 與 requisite 的差異。
接下來要做的事情就不是上面提到的「如何設定」,而是自己寫一個簡單的 PAM 應用程式和 PAM 模組。http://www.kernel.org/pub/linux/libs/pam/ 有提供管理、開發 PAM 的手冊。至於我要做的事情是:寫一個程式讓使用者輸入帳號密碼,然後進行驗證,成功與否都會出現提示訊息。有興趣的人可以從 PAM Application 與 PAM Module 的範例做修改,至於編譯的方式如下:
gcc -fPIC -c pam_module.c
gcc -shared -o pam_module.so pam_module.o -lpam
sudo cp pam_module.so /usr/lib/
gcc -o pam_app pam_app.c -lpam -lpam_misc -lpam_module
  • Hint:撰寫 pam application 時,需要做 pam_set_item,而 item type 不能使用 PAM_AUTHTOK 及 PAM_OLDAUTHTOK,所以就隨便設定一個。
  • Hint:撰寫 pam module 時,需要引用 當中的 getspnam 函式來取得加密過的密碼,至於為什麼要自己寫一個 module,因為 PAM 模組的帳密認証方式只能先輸入帳號,等他確認有這個使用者,才會在要求輸入密碼,既然說要改變他的行為,模組只好自己寫。
  最後,我把我寫好的程式碼放在 google docs,有興趣的讀者可以去看看,MY_PAM_APP、MY_PAM_MODULE。

2008年12月31日 星期三

mmap()

mmap 函式是用來將檔案映射到記憶體,video for linux two 就是透過這種方式,將 device memory mapping into user space,而 uvcvideo driver 會實作這個 file operation,來幫 camera application 建立 VMA 區段。mmap() 的原型如下:##ReadMore##

void *mmap(void *addr, size_t len, int prot,
      int
flags,int fildes, off_t off);
  • addr:用來告知從哪個記憶體位址開始映射,不過通常是擺 NULL,直接給作業系統決定,否則還要考慮對齊問題(alignment)
  • len:映射的大小
  • prot:對此記憶體的操作限制,如:PROT_READ、PROT_WRITE、PROT_EXEC、PROT_NONE
  • flags:對此記憶體的存取方式,如:MAP_SHARED、MAP_PRIVATE、MAP_FIXED,使用 MAP_SHARED 時,如果某一個行程有對 mmap 的記憶體做修改,那其他同樣有做 mmap 的行程會看到相同結果。(對同一個檔案)
  • fildes:open file 所得到的 fd。
  • off:指定檔案從哪裡開始對映
在此用 mmap 做個小實驗。首先建立一般的實體檔案,然後關閉它,接著透過映射到的記憶體來間接寫入字串到該檔案中。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#define FILE_LENGTH 0x400 /* 1024 */

int main(int argc, char *argv[])
{
    int fd;
    void *map_memory;

    if(argc < 2) {
        printf("Usage: ./a.out <string>\n");
        return 1;
    }

    /*
     * Open a file to be mapped.
     * S_IRUSR: read permission, owner
     * S_IWUSR: write permission, owner
     */
    fd = open("/tmp/shared_file", O_RDWR | O_CREAT,
        S_IRUSR | S_IWUSR);
        lseek(fd, FILE_LENGTH-1, SEEK_SET);
        write(fd, "", 1);
        lseek(fd, 0, SEEK_SET);

    /* Create map memory. */
    map_memory = mmap(0, FILE_LENGTH,
        PROT_WRITE, MAP_SHARED,
        fd, 0);
    
    close(fd);

    /* Write to mapped memory. */
    if(strlen(argv[1]) < FILE_LENGTH)
        sprintf((char*)map_memory, "%s", argv[1]);

    munmap(map_memory, FILE_LENGTH);
    return 0;
}
這樣的作法還是可以將內容寫入檔案,而且速度比單純寫入檔案還要快,但似乎 mmap有大小的限制,因為我設定到 0x40000000,程式執行完後,系統變得怪怪的 =.=?。以下是該測試程式的 VMA 區段,位於 /proc/xxxx/maps,其中 xxxx 是 process id,可以在執行程式時輸入 &,如:./mmaptest input_string &。
08048000-08049000 r-xp 00000000 08:06 606289 /home/linly/Sample/mmap_write
...
b7df2000-b7f4a000 r-xp 00000000 08:06 1497227 /lib/tls/i686/cmov/libc-2.8.90.so
...
b7f61000-b7f62000 -w-s 00000000 08:06 686791 /tmp/shared_file
...
b7f80000-b7f81000 rw-p 0001b000 08:06 1479875 /lib/ld-2.8.90.so
bff6c000-bff81000 rw-p bffeb000 00:00 0 [stack]

2008年12月12日 星期五

Video For Linux Two

  這是最近一兩個禮拜 study 的主題:V4L2,是在 Linux 中用來擷取影像的 API,隨著你安裝作業系統,V4L2 就會一併裝上去,以下是自己製作的投影片,Enjoy it... : )





參考資料:http://v4l2spec.bytesex.org/spec-single/v4l2.html
 
Blogger Templates