作者:陳柏菁  E-mail:pachingko@ms96.url.com.tw
第七章 壓縮、備份工具與套件管理

索引:
7.1 基本的壓縮指令
  7.1.1 使用 gzip 壓縮
  7.1.2 使用 bzip2 壓縮
7.2 備份工具
  7.2.1 tar 指令
  7.2.2 cpio 指令
  7.2.3 dd 指令 --- 建立 swap file備份 MBR 磁區及分割區
  7.2.4 備份時需考慮事項
7.3 在 Linux 上安裝軟體套件
  7.3.1 安裝 Tarball ---
原始碼編譯介紹實做練習 (configure scriptmakemake install)
  7.3.2 RPM 套件管理 ---
套件查詢套件安裝套件升級套件移除套件內容核對重建 RPM 資料庫
7.4 動態連結資料庫:DLL



7.1 基本的壓縮指令

 什麼時候您會想要壓縮檔案呢 ? 那當然是嫌檔案太大囉。比如您要寄附加檔案給別人時,就會希望這個檔案能小一點,以加快傳輸效率 ﹔另外像在做大量的資料備份時,可能會擔心佔用您儲存裝置太多的空間,因此會考慮把這些備份資料做個壓縮 ﹔再者像平常提供給 Client 端來下載的檔案,也可以事先將其壓縮,這樣一方面可以節省您的磁碟空間,另一方面也能縮短下載的時間。

 在 Linux 上頭壓縮檔的附檔名一般為 xx.gz、xx.bz2、xx.tar.gz、xx.tgz 等等,至於這些附檔名的主要作用是為了識別用的,因為藉由附檔名,才能了解當初是使用什麼壓縮工具來產生壓縮檔的,此時您要將它解開或瀏覽其內容時,才知道要執行哪個指令。

7.1.1 使用 gzip 壓縮

 
gzip 是 GUN 計劃所研發的一個壓縮檔案的指令,其只能針對個別檔案做壓縮。至於解壓縮時可使用 gunzip 指令。

指令語法
gzip [-cdflr1~9] [filename ...]

 當您執行「gzip file」時,原來檔案 file 就會變成 file.gz 的壓縮檔,其副檔名是自動產生的。

參數說明
-c 同於 --stdout。將壓縮或解壓縮後的內容做 standard output,此時原來檔案還是存在。
-d 同於 --decompress。就是解壓縮囉。「gzip -d」就等於 gunzip。
-l 同於 --list。列出 gzip 壓縮檔在未壓縮前的大小、檔名、壓縮後的大小及壓縮比。
-r 同於 --recursive。對所指定的目錄遞迴地做壓縮。gunzip 亦適用此參數。
-f 同於 --force。當進行壓縮或解壓縮時,如檔名已存在,則進行強制覆寫。
-1 ~ -9

使用 -9 能產生最佳的壓縮比,而 -1 雖然壓縮比是最低的,但其執行速度最快。預設是 -6。


範例說明
suse:/tmp # cp /etc/passwd file1 ; cp /etc/fstab file2
# 先建立兩個檔案,以準備等會兒實驗用

suse:/tmp # gzip file1 file2
suse:/tmp # ls
file1.gz file2.gz
# 對 file1 及 file2 個別做 gzip 壓縮壓縮後會自動產生 .gz 的附檔名。另外如果
# 壓縮檔的檔名原本已存在,則會詢問您是否要覆蓋的訊息,如以下所示:
# gzip: file1.gz already exists; do you wish to overwrite (y or n)?

suse:/tmp # gzip -l file1.gz
compressed  uncompressed  ratio uncompressed_name
    631      1413  57.0% file1

#
比較壓縮前後的一些數據  
 
suse:/tmp # gzip -d file1.gz 
# 對 file1.gz 做解壓縮

suse:/tmp # ls
file1 file2.gz
# file1.gz 已變成 file1。在進行解壓縮時,如 file1 已存在,也會詢問您是否要覆蓋。

suse:/tmp # gunzip file2.gz
suse:/tmp # ls
file1 file2
# 使用單一指令 gunzip,亦可達到與 "gzip -d" 同樣的效果

suse:/tmp # gzip -c file1 > file1.gz
# 將 file1 壓縮後的內容轉向輸出到 file1.gz。此時 file1 還是存在。

suse:/tmp # cat file1 file2 | gzip > file3.gz
# 將 cat 指令的輸出當成 gzip 指令的輸入,並將 gzip 壓縮過後的內容轉向輸出到 file3.gz。

suse:/tmp # gzip -c file1 file2 > file4.gz
# 跟上面的做法有異曲同工之妙。

suse:/tmp # gzip -c file1 > file5.gz
suse:/tmp # gzip -c file2 >> file5.gz
# 先將 file1 壓縮後的內容輸出至 file5.gz,再將 file2 壓縮後的內容附加至 file5.gz。

suse:/tmp # gzip -cd file1.gz
# 將 file1.gz 解壓縮後的內容做 standard output,這樣您就可以看到壓縮檔的內容了。

suse:/tmp # gunzip -c file1.gz
# 使用 "gunzip" 來代替 "gzip -d",所以跟上面的執行結果是相同的。
# 另外 gunzip 亦可支援附檔名為 .z、.Z、.tgz 及 .tar.gz 者。

suse:/tmp # zcat file1.gz
# 使用 zcat 這個單一指令來瀏覽 xx.gz 壓縮檔的內容。
# 另外 zcat 亦可支援附檔名為 .z、.Z、.tgz、.tar.gz 者。

# 以下是先建立一些目錄及檔案,然後再使用 gzip -r 來做遞迴壓縮:
suse:/tmp # mkdir -p dir/dir1
suse:/tmp # cp /etc/passwd dir/file1 ; cp /etc/passwd dir/dir1/file2
suse:/tmp # gzip -r dir
# 執行完後可至 dir 及 dir1 目錄下檢視看看。
# 如想遞迴解壓縮的話,則執行 "gunzip -r dir" 即可。


7.1.2 使用 bzip2 壓縮

 
這是另一個針對個別檔案做壓縮的指令,且其壓縮效果比 gzip 好噢 ! 至於解壓縮時可使用 bunzip2 指令。

指令語法
bzip2 [-cdkf1~9] [filenames ...]

 當您執行「bzip2 file」時,原來檔案 file 就會變成 file.bz2 的壓縮檔,且其副檔名也是自動產生的。

參數說明
-c 同於 --stdout。將壓縮或解壓縮後的內容做 standard output,此時原來檔案還是存在。
-d 同於 --decompress。解壓縮。「bzip2 -d」就等於 bunzip2。
-k 同於 --keep。保留原來檔案。bunzip2 亦適用此參數。
-f 同於 --force。當進行壓縮或解壓縮時,如檔名已存在,則進行強制覆寫。
-1 ~ -9 與 gzip 意思相同。預設為 -9。

範例說明
suse:/tmp # bzip2 file1 file2
suse:/tmp # ls
file1.bz2 file2.bz2
# 產生兩個 xx.bz2 的壓縮檔。

suse:/tmp # bzip2 -d file1.bz2 ; bunzip2 file2.bz2
suse:/tmp # ls
file1 file2
# 解壓縮後又回覆到原來的檔案名稱。

suse:/tmp # bzip2 -k file1
suse:/tmp # ls
file1  file1.bz2 file2
# 加上 -k 參數來保留原始檔案 file1。

suse:/tmp # bzip2 file1
bzip2: Output file file1.bz2 already exists.
suse:/tmp # bunzip2 file1.bz2
bunzip2: Output file file1 already exists.
# 以上兩個範例,說明了不允許覆寫檔名已經存在的檔案。

suse:/tmp # bunzip2 -f file1.bz2
# 如要強制覆寫,就加上 -f 參數囉。

suse:/tmp # bzip2 -c file1 file2 > file3.bz2
suse:/tmp # cat file1 file2 | bzip2 > file5.bz2
# 以上兩個範例是將 file1 及 file2 壓縮後的內容轉向輸出至另一個檔案。

suse:/tmp # bzip2 -cd file3.bz2
suse:/tmp # bunzip2 -c file3.bz2
suse:/tmp # bzcat file3.bz2
# 上面這三種方式,都可以用來瀏覽 file3.bz2 的內容。


7.2 備份工具

 講到備份,那可說是系統管理上非常重要的一環。平常如果有養成備份的習慣,萬一哪天因某些因素造成您系統資料的流失時,就可以執行備份還原,來恢復系統原本的一些相關重要資料。

 一般在執行備份時,都會將備份的工作寫到排程裡,這樣子排程時間一到,系統就會自動做這些工作,而不須我們操心,不過話雖如此,您還是要定期的去檢視您的備份檔,以了解是否備份完整。

 而能拿來做備份的工具有很多,或許您會問到底哪個工具比較好用呢 ? 其實這並沒有一定的答案,因為這要視您實際的需求及平常使用習慣來做決定,且有些時侯尚需考慮到儲存裝置、備份容量、備份還原的方便性、… 等等的問題,所以可能會使用不同的工具來達到您的目的。以下就跟大家介紹幾個常見的備份指令。

7.2.1 tar 指令

 tar 指令可以將一些檔案目錄一起打包到一個檔案內,而所建立的這個檔案就稱為 tarfile,是屬於 archive file 的一種。我們也可以使用 tar 來將資料打包至儲存媒體上,比如磁帶機之類的裝置 (如 /dev/st0、/dev/ht0)。

Tips:所謂的 archive file 是泛指那些包含很多檔案目錄資料的檔案。

指令語法
tar [-] [cvftxrzjP] tarfile filename… dirname…

 使用 tar 所建立起來的 tarfile 名稱,包括其附檔名,皆需自行指定,一般都是用 xx.tar,那如果此 tarfile 有使用 gzip 去壓縮,則可指定為 xx.tar.gz 或 xx.tgz,當然用 bzip2 壓縮的話,就可指定為 xx.tar.bz2 或 xx.tbz。

參數說明
-c 同於 --create。
用來建立一個新的 archive file。
-v 同於 --verbose。
顯示執行過程。
-f 同於 --file=filename。
表示其後要指定一個 archive file 或 device name。使用 tar 做備份時,最基本的就是「-cvf」這三個參數的組合。
-t 同於 --list。
列出 archive file 的內容。
-x 同於 --extract。
從 archive file 中解開這些被打包的檔案目錄,也就是備份還原啦 !
-r 同於 --append。
附加檔案至 archive file 內容的後面。
-k 同於 --keep-old-files。
執行備份還原時,不覆蓋已經存在的檔案。預設是會覆蓋的。
-P 同於 --absolute-paths。
備份進去的檔案目錄,皆保留完整路徑。將來要還原時,也可加這個參數來依原本路徑做還原。
-z 同於 --gzip 或 --ungzip。
用 gzip 來壓縮 archive file。比如您要建立一個用 gzip 壓縮的 archive file,就可搭配「-zcvf」參數來使用 ﹔反過來說,要解開當初用 gzip 壓縮的 archive file,則使用「-zxvf」即可。
-j 同於 --bzip2 或 --bunzip2。
用 bzip2 來壓縮 archive file。比如您要建立一個用 bzip2 壓縮的 archive file,就可搭配「-jcvf」參數來使用 ﹔反過來說,要解開當初用 bzip2 壓縮的 archive file,則使用「-jxvf」即可。
-C 同於 --directory=DIR。
備份還原至 -C 所指定的目錄之中。
-X 同於 --exclude-from=filename。
執行備份時,可以事先將欲排除備份的檔案目錄設定在一個檔案內,然後再使用「-X file」來排除就行了。
-g 同於 --listed-incremental=filename。
做遞增備份時,所指定的備份紀錄檔案。

範例說明

suse:~ # mkdir /backup
# 先建立一個備份目錄來集中管理。

suse:~ # tar -cvf /backup/bck.tar /etc/passwd /home
tar : Removing leading ' / ' from member names
# 上面訊息說明了tar 預設會將備份檔路徑中最前面的 " / " 移除,然後再備份至 tarfile 裡。
# 如果要備份整個完整路徑,加上 -P 參數即可。
/etc/passwd
/home/barry/
/home/barry/bin/
/home/barry/Documents/
/home/barry/Documents/.directory
/home/barry/.exrc
/home/barry/.bashrc
   : 略
# 將 /etc/passwd 檔案及 /home 目錄備份至 bck.tar 裡。

suse:~ # cd /backup
suse:/backup # tar -tf bck.tar
# 列出 tarfile 裡,所打包的檔案目錄清單。

suse:/backup # tar -rvf bck.tar /etc/fstab /var/spool/mail
# 附加檔案至 tarfile 裡。此處如使用 "-cvf" 的話,則會重新建立起一個新的 tarfile,
# 那原來的 tarfile 當然就被取代了。

suse:/backup # tar --delete -f bck.tar etc/fstab
# 將 fstab 檔案從 tarfile 中移除。

suse:/backup # tar -xvf bck.tar etc/passwd
# 只解開 etc 目錄下的 passwd 檔案。

suse:/backup # ls
bck.tar etc
# 解開後多了一個 etc 目錄出來,而此目錄的內容就是 passwd 檔案。

suse:/backup # tar -xvf bck.tar
# 將 tarfile 全部解開。

suse:/backup # ls
bck.tar etc home var

# 執行備份還原時,對於已經存在的檔案,預設是會覆蓋的,至於其他檔案則是不受影響,
# 您可以馬上做個實驗:先修改 /backup/etc/passwd,然後再執行一次備份還原,看看
# passwd 的內容有無被覆蓋 ?

# 如果您不想覆蓋已經存在的檔案,可加上 "-k" 參數:
suse:/backup # tar -xkvf bck.tar etc/passwd
etc/passwd
tar: etc/passwd: Cannot open: File exists
tar: Error exit delayed from previous errors

# 針對剛剛所建立起來的 tarfile,可以使用 gzip 或 bzip2 對其進行壓縮,
# 以 gzip 來做範例好了:
suse:/backup # gzip bck.tar
suse:/backup # ls
bck.tar.gz etc home var
# 結果就產生了 bck.tar.gz。這種被壓縮過後的 tarfile,一般就稱為 tarball。

# 我們也可以使用 tar 指令來直接進行打包兼壓縮:
suse:/backup # tar -zcvf test.tar.gz /etc/passwd /var/spool/mail
# 使用 -z 參數,對 tarfile 進行 gzip 壓縮。

suse:/backup # tar -jcvf test.tar.bz2 /etc/passwd /var/spool/mail
# 使用 -j 參數,對 tarfile 進行 bzip2 壓縮。

suse:/backup # tar -ztf test.tar.gz
# 瀏覽 tarball 清單。如欲瀏覽 test.tar.bz2 的清單,則執行 "tar -jtf test.tar.bz2"。

suse:/backup # tar -zxvf test.tar.gz etc/passwd
# 只解開 passwd 檔案。針對 bzip2:"tar -jxvf test.tar.bz2 etc/passwd"。

suse:/backup # tar -zxvf test.tar.gz
# 將整個 tarball 解開。針對 bzip2:"tar -jxvf test.tar.bz2"。

# 以下介紹一種比較特殊的解開方式:
suse:/backup # zcat test.tar.gz | tar xvf -
# 使用 zcat 來讀取 tarball 裡 test.tar 的格式內容後,交給 tar 指令處理,
# 此時 tar 會從 stdin 讀取內容並解開此 tarfile。所以說,tar 指令後的 "-"
# 就代表著 stdin,也就是那個 test.tar 囉。

# 使用 -C 參數,來指定要備份還原至 /tmp 目錄:
suse:/backup # tar -jxvf test.tar.bz2 -C /tmp

# 有些時候在對目錄進行備份時,會想排除目錄中的某些檔案或子目錄,也就是不想將其
# 備份進去之意,那要怎麼做呢 ?
# 以 /home 做例子好了,假使現在要備份/home,但/home/user01 及 /home/user02
# 這兩個家目錄不想備份進去,則此時可以先將這兩個欲排除的目錄寫入一個檔案中,
# 然後於利用 tar 指令進行備份時,搭配 -X 參數來使用即可:
suse:~ # vi excludefile
/home/user01
/home/user02
suse:~ # tar -zcvf /backup/home.tar.gz /home -X excludefile

# 執行備份工作時,為了增加備份的效率,可以考慮使用遞增備份 (incremental backup) 的
# 方式。所謂的遞增備份,就是此次備份只針對前面幾次備份完後尚有異動的資料做備份而已 ﹔
# 當您欲備份的資料很多時,利用這種方式會顯得特別的有效率。
# 進行以下的實驗中,您可以在每次備份完後,嘗試修改檔案目錄內容,然後再進行下一次的
# 備份,這樣將來在做備份還原時才看得出效果。底下就實做一次囉:
suse:/backup # tar -g increfile -zcvf home.tgz /home
# 使用 "-g" 參數,來將首次備份的記錄存放在 increfile 內。

suse:/backup # tar -g increfile -zcvf home1.tgz /home
# 執行第一次遞增備份。請記得每次執行遞增備份時,都必須指定那個備份紀錄檔。

suse:/backup # tar -g increfile -zcvf home2.tgz /home
# 執行第二次遞增備份。

# 完成後,接著把 /home 目錄刪除,然後開始執行備份還原 (從首次所做的備份來開始還原起):
suse:/backup # rm -rf /home
suse:/backup # tar -zxvf home.tgz -C /
suse:/backup # tar -zxvf home1.tgz -C /
suse:/backup # tar -zxvf home2.tgz -C /
# 如果您的 home 與 / 分屬不同 partition,會造成 /home 目錄無法刪除,此時執行:
# rm -rf /home/* 即可。


7.2.2 cpio 指令


 
cpio 指令可用來備份檔案至 archive 或從 archive 執行備份還原,因此它可以算是您平常做備份時的一個好工具。另外這裡的 archive file 可以是檔案或磁帶機之類的裝置。

 cpio 會從標準輸入讀取檔案名稱列表 (一個檔案名稱一行),並將結果輸出至您所指定的 archive file 裡。一般常用來產生檔案名稱列表的指令是 find,因此 cpio 常常會搭配 find 指令來使用。

參數說明
-o 此參數是執行在 copy-out 模式,意即把資料進行複製並輸出至檔案或裝置上。
-i 此參數是執行在 copy-in 模式,意即把資料從檔案或裝置中複製出來,就是備份還原囉 !
-t 列出 cpio 檔案或裝置的內容清單。
-F 藉由指定一個 archive file 的名稱,來替代 stdin 或 stdout。

範例說明

suse:~ # find /home | cpio -o > /backup/home.cpio
suse:~ # find /home | cpio -oF /backup/home.cpio
# 將 /home 目錄備份至 /backup/home.cpio。以上兩種做法都行噢。

suse:~ # cpio -t < /backup/home.cpio
suse:~ # cpio -tF /backup/home.cpio
# 查看 /backup/home.cpio 的內容。

# 接著把 /home 內容刪除,然後再進行備份還原的測試:
suse:~ # rm -rf /home/*

suse:~ # cpio -i < /backup/home.cpio

suse:~ # cpio -iF /backup/home.cpio
# 執行備份還原後, home 目錄會在目前工作目錄下產生,因為還原時,預設會把
# home 前面的 " / " 去除,所以無法按照原先的路徑來做還原。

# 如要依照完整路徑做還原,加上 --absolute-filenames 即可:
suse:~ # cpio --absolute-filenames -iF /backup/home.cpio
# 完成後,檢查看看 /home 裡面的資料還原沒。


7.2.3 dd 指令


 這是另一個複製的工具,且其具有某些特色是其他備份工具做不來的,比如可以備份 MBR 磁區、partition 上的 Boot Sector,甚至還可以備份某個分割區及整顆硬碟,很神奇吧 !

指令語法
dd if=FILE of=FILE [bs=BYTES|ibs=BYTES|obs=BYTES] count=BLOCKS …

常用參數
if=FILE if 就是 input file 之意,其後可以是檔案或裝置。而 if=FILE 即是藉著讀取 FILE 的內容來代替 stdin。
of=FILE of 就是 output file 之意,其後可以是檔案或裝置。而 of=FILE 即是將 output 寫入 FILE 來代替 stdout。
ibs=BYTES 一次讀入的區塊大小 (block size) 是多少 bytes。
obs=BYTES 一次寫入的區塊大小是多少 bytes。
bs=BYTES 即 ibs 與 obs 都相同,也就是讀入與寫入的區塊大小是一樣的。預設 bs=512。
count=BLOCKS 指定讀取多少個區塊數。

範例說明
suse:~ # ls -l /etc/passwd
-rw-r--r-- 1 root root 1413 Dec 9 19:13 /etc/passwd
# 先了解 /etc/passwd 的檔案大小為 1413 bytes。

suse:~ # dd if=/etc/passwd of=/tmp/file1 bs=1024
1+1 records in
1+1 records out
1413 bytes (1.4 kB) copied, 0.000509 seconds, 2.8 MB/s
#
由於指定讀入與寫入的區塊大小為 1024 bytes,又因為 passwd 檔案大小為 1413 bytes,
# 因此會從 /etc/passwd 讀入兩個 blocks,並將讀取的內容寫入 /tmp/file1,此時當然也是
# 寫入兩個 blocks。至於螢幕上出現的 "1+1 records in",表示共讀取兩個區塊紀錄
# 但因有一個 block 的資料是未填滿的,所以才會顯示 1+1,如果兩個 block 都是滿的,
# 就會變成 2+0 ﹔"1+1 records out" 也是一樣的意思。 

suse:~ # dd if=/etc/passwd of=/tmp/file2 bs=512 count=2
2+0 records in
2+0 records out
#
指定讀取與寫入的區塊大小為 512 bytes,並且使用 count 去限定讀入兩個區塊的內容,
#
也就是只複製 1024 bytes 啦。

suse:/tmp # dd if=/etc/passwd of=/tmp/file3 ibs=512 obs=2k count=2
2+0 records in
0+1 records out
#
指定讀取兩個 512 bytes 的區塊大小,換言之就是只複製 1024 bytes。
#
而 obs=2k,是表示把剛剛讀入 1024 bytes 的資料寫入大小為 2048 bytes 的區塊,此時
# 由於該區塊是未填滿的,因此螢幕上是出現 "0+1 records out"。

 接著再來看看 dd 指令的其他應用。

建立 swap file

 一般我們所熟知的是使用分割區來作 swap 空間,而 dd 指令能讓您使用檔案來規劃出 swap 空間噢。如果您覺得目前的 swap 空間太少,想要多增加個 100 M,這時候您就可以這麼做:

# 先規劃出 swapfile 空間的大小為 100 M:
suse:~ # dd if=/dev/zero of=/tmp/swapfile bs=1000k count=100
100+0 records in
100+0 records out

# 對 swapfile 進行格式化
suse:~ # mkswap /tmp/swapfile 
Setting up swapspace version 1, size = 102395 kB

# 啟用 swapfile
suse:~ # swapon /tmp/swapfile 

 完成後,可使用 free 指令去瞧瞧 swap 空間有沒有多了 100 M。另外如果想在下次開機時,能自動啟用此 swap file,那就在 /etc/fstab 內補上一行設定:

/tmp/swapfile   swap   swap   defaults   0  0

備份 MBR 磁區及分割區

 真是神奇,dd 居然也能備份 MBR 磁區或分割區,而且還很簡單,請參考以下的範例:

# 備份 MBR 磁區:
suse:~ # dd if=/dev/hda of=mbrbck bs=512 count=1
# 可不要忘了指定 count=1 啊,不然會變成備份整顆硬碟噢。

suse:~ # file mbrbck
mbrbck: x86 boot sector, code offset 0x48

# 備份 partition
suse:~ # dd if=/dev/hda3 of=hda3bck
# 請注意,of 後所指定的檔案位置,必須是存在於 /dev/hda3 以外的 partition。

7.2.4 備份時需考慮事項

 備份是需要經過事先規劃的,而您在制定備份策略時,可能需要先做個全盤考慮,這樣的備份才會比較完善。以下就列出幾點來給各位參考:

  欲備份的資料
    您是想對整顆硬碟、某幾個 partition 還是某些檔案做備份,這可是要好好的想一想啊。如果只是想針對比較重要的資料做備份時,則首選當然是針對 /etc、/home、/srv、/var、/root、/boot 這幾個目錄來下手,另外若您有把軟體安裝在 /usr/local 中的話,也可把這個目錄備份起來。至於不需備份的目錄有 /dev、/proc、/mnt、/media、/tmp 等,另外 swap 當然也不需備份啦 !
     
  要備份到哪裡:
    打算要備份至同主機的另一顆硬碟、不同主機的硬碟、異地備援、或者是像 CD-ROM、MO、Tap、… 這一類的儲存媒體。
     
  採取的備份模式:
    一般常見到的備份方式有完全備份 (full backup)、部分備份 (partial backup)、遞增備份 (incremental backup)、差異備份 (differential backup)。其意義如下:
 ˙完全備份:將整個檔案系統備份下來。
 ˙部分備份:只針對某個目錄或分割區進行備份。
 ˙遞增備份:針對上次完全備份及遞增備份後才異動的資料進行備份。
 ˙差異備份:針對上次完全備份後才異動的資料進行備份。
     
  多久備份一次:
    這要視您資料的重要性才能做決定。比如您是以 full backup 及 incremental backup 來搭配使用的話,可以規劃每個月的第一週進行 full backup,爾後的每一週進行一次 incremental backup,當然如果是特別重要的資料,則可能要額外的進行每天備份囉 !

7.3 在 Linux 上安裝軟體套件

 大家應該都有在 Windows 中安裝軟體的經驗,就是把軟體下載回來後,直接執行安裝程式,然後一直按 [下一步 ],最後就很輕易地完成安裝了。

 因為 Windows 所提供的軟體其原始碼未公開,當然您就無法修改它,所以在安裝時只能按照 [公式化] 的步驟去進行。那在 Linux 中又如何呢 ? 還記得 Linux 的一大特色:Open Source 吧 ! 因為大部分的 Linux 軟體其原始碼是公開的,所以可以依照自己的需求去做調整,不論您想修改軟體的原始碼或改變安裝路徑都是可行的。

 底下我們會介紹兩種在 Linux 上頭安裝軟體的方式,一種是下載 tarball 套件來安裝,另一種是利用發行商所提供的 RPM 套件來安裝。

7.3.1 安裝 Tarball

 tarball 這個名稱應該還記得吧 ! 不過網路上提供給我們下載的 tarball,可不是只包含單純的文字檔案而已噢,而是包括程式的原始碼、含括檔、測試工具、安裝說明及其他的說明文件等等。通常提供者會將以上所提及的這些資料給它集中在一個目錄中,然後使用 tar 來把這個目錄打包起來並壓縮,所以當您下載回來後,第一個動作就是把 tarball 解開,然後切換至這個目錄上,爾後所進行的編譯安裝步驟就是在這個目錄下進行的。

 由於 tarball 裡頭含有 C 語言的原始碼,所以免不了要使用編譯器 (compiler) 來對其進行編譯的動作,這樣編譯完成後的 binary file,才能夠在 Linux 系統中被執行。而目前被廣為使用的 compiler,是 GNU 計劃中的 gcc (g++) 程式,它是用來針對 C 及 C++ 進行 compile 的。

原始碼的編譯介紹

 接著來認識一下原始碼編譯的流程:

  1. 先使用 vi 去編輯 C 的原始碼檔案,且必需使用「.c」的附檔名,如 barry.c。
  2. 執行 gcc 來對 xxx.c 進行編譯。
  3. 編譯過程中會產生目標檔 (xxx.o),連結器會將此目標檔與函式庫做個連結。
  4. 最後就會產生可執行的 binary file。

 舉個簡單的例子,首先請您先使用 vi 去編輯 barry.c:

suse:/tmp # vi barry.c

#include <stdio.h>
main(void)
{
  printf("Hello,everybody!\n");
  printf("I am barry.\n");
}

 再來執行 gcc (請確定您 gcc 相關套件有安裝):

suse:/tmp # gcc -c barry.c
suse:/tmp # ls
barry.c barry.o ← 產生目標檔。

suse:/tmp # gcc -o barry barry.o
suse:/tmp # ls
barry.c barry.o barry ← 產生了 binary file。

suse:/tmp # ./barry
Hello,everybody!
I am barry.

 如果您要直接產生 binary file,也可執行「gcc -o barry barry.c」。或許您又會有疑問,既然可以直接產生 binary file,那為何上面的範例不這樣做呢 ? 因為實際上程式設計師所編寫的原始碼檔案,在編譯過程常會使用到其他原始碼檔案所產生的目標檔,所以才會採用範例中的方式來產生 binary file。

 不過 tarball 裡的原始碼檔案往往為數不少,為了簡化我們的操作程序,可以使用 make 指令來執行這項工作,但您需要先去編輯 Makefile 檔案,因為 make 會讀取 Makefile 或 makefile 的內容:

suse:/tmp # vi Makefile

target_first: barry
barry:
    gcc -c barry.c
    gcc -o barry barry.o

install:
    install -m 755 barry /home/mary/bin
uninstall:
    rm -f /home/mary/bin/barry
distclean:
    rm -f barry barry.o

 在 Makefile 裡頭,包含了很多 target,您在「:」左邊所看到的都是屬於 target,至於這個 target 所要執行的程式,則是設定在 target 底下,且必須使用 Tab 鍵來取間格。

 當您執行 make 指令時,會使用 Makefile 裡所定義的第一個 target,以這個範例來說就是 target_first,而 target_first 又指向 barry 這個 target,所以最後會執行 barry target 底下的程式。

 當執行 make install 時,那當然就執行 install target 其下的程式囉 ! 所以 install 程式就會把 barry 這個 binary file 複製到 /home/mary/bin 目錄裡,並指定此 binary file 的權限為 755。最後的 make uninstallmake distclean 應該不用解釋了吧 !

 接著就來做個測試:

suse:/tmp # make
gcc -c barry.c
gcc -o barry barry.o
# 根據 Makefile 內容來開始進行編譯。

suse:/tmp # ls
Makefile barry barry.c barry.o
# 執行 make 指令後,就產生了 barry.o ( object file ) 及 barry ( binary file )。

suse:/tmp # make install
install -m 755 barry /home/mary/bin
# 執行 Makefile 裡 target 為 install 中的指令,也就是把 barry 複製到 /home/mary/bin 裡。

suse:/tmp # ls /home/mary/bin
barry 
# barry 已被複製到 /home/mary/bin 中了。

suse:/tmp # make uninstall
rm -f /home/mary/bin/barry
# 執行 Makefile 裡 target 為 uninstall 中的指令,也就是刪除 /home/mary/bin/barry。

suse:/tmp # make distclean
rm -f barry barry.o
# 執行 Makefile 裡 target 為 distclean 中的指令,也就是刪除 barry 及 barry.o 這兩個檔案。

實作練習

 首先使用 ncftp 程式來連上 FTP 站台 ( ncftp 指令的用法,請參考 [網路組態設定與服務] 那一章 ):

suse:~ # ncftp ftp.proftpd.org
NcFTP 3.1.9 (Mar 24, 2005) by Mike Gleason (http://www.NcFTP.com/contact/).
Connecting to 81.223.20.36...
ProFTPD 1.3.0rc3 Server (proftpd.org Project) [81.223.20.36]
Logging in...
Anonymous access granted, restrictions apply.
Logged in to ftp.proftpd.org.

ncftp / > ls
MIRMON.PROBE   contrib/  distrib/ 
README.MIRRORS  devel/   historic/ 


ncftp / > cd distrib/
ncftp /distrib > ls
packages/  source/

ncftp /distrib > cd source/

ncftp /distrib/source > get proftpd-1.3.0rc2.tar.gz
proftpd-1.3.0rc2.tar.gz:   ETA:  0:05  1.28/  1.76 MB  93.00 kB/s

ncftp /distrib/source > by

You have not saved a bookmark for this site.

Would you like to save a bookmark to:
   ftp://ftp.proftpd.org/distrib/source/

Save? (yes/no) no
Not saved. (If you don't want to be asked this, "set confirm-close no")
# 如果以後不想再看到這個詢問訊息,可於離開 ncftp 前,先執行 "set confirm-close no"。

suse:~ # 

 再來進行解壓縮:

suse:~ # tar -zxvf proftpd-1.3.0rc2.tar.gz
suse:~ # cd proftpd-1.3.0rc2/
suse:~/proftpd-1.3.0rc2 #
# 等一下的編譯、安裝步驟,都是在 proftpd-1.3.0rc2 這個目錄下完成的。

 在 proftpd-1.3.0rc2 這個目錄中,存在著一支很重要的測試工具叫 configure (是一支 script),它是用來偵測您的作業環境,並自動產生 Makefile (或 makefile) 檔案,待會兒不論進行編譯、安裝、移除等工作,可都是靠 Makefile 來作為執行的依據。所以等一下執行 configure script 的過程中,如果有發現任何錯誤訊息報告的話,那麼後面要繼續進行的步驟可就大有問題了。

 另外可以參考目錄中的 README 或 INSTALL 檔案,裡邊有詳細的安裝步驟介紹。最後您可查看一下那些子目錄的內容,包括很多的原始碼檔案及含括檔,這些都是等一下的編譯過程需要用到的。

 接著請開始按照以下步驟進行:

  1. 執行 configure script:

    suse:~/proftpd-1.3.0rc2 # ./configure --prefix=/usr/local/proftpd
    checking build system type... i686-pc-linux-gnu
    checking host system type... i686-pc-linux-gnu
    checking target system type... i686-pc-linux-gnu
    checking for gcc... gcc
    checking for C compiler default output file name... a.out
    checking whether the C compiler works... yes
    checking whether we are cross compiling... no
    checking for suffix of executables...
    checking for suffix of object files... o
    checking whether we are using the GNU C compiler... yes
    checking whether gcc accepts -g... yes
           :略
    config.status: creating utils/ftptop.1
    config.status: creating utils/ftpwho.1
    config.status: creating Makefile
    config.status: creating Make.rules
    config.status: creating config.h
    config.status: executing default commands

    --prefix 是用來指定待會兒進行安裝時候的位置,這裡我是把它集中在 /usr/local/proftpd 目錄中,這樣比較方便管理。如未指定安裝路徑的話,預設是會安裝在 /usr/local 下的相關子目錄中。

    至於可搭配 configure 的其他參數用法,可執行「./configure -h」自行查閱。


  2. 進行編譯:

    suse:~/proftpd-1.3.0rc2 # make
    echo \#define BUILD_STAMP \"`date`\" >include/buildstamp.h
    cd lib/ && make lib
    make[1]: Entering directory `/root/proftpd-1.3.0rc2/lib'
    gcc -DHAVE_CONFIG_H -DLINUX -I.. -I../include -O2 -Wall -c pr_fnmatch.c
    gcc -DHAVE_CONFIG_H -DLINUX -I.. -I../include -O2 -Wall -c sstrncpy.c
    gcc -DHAVE_CONFIG_H -DLINUX -I.. -I../include -O2 -Wall -c strsep.c
    gcc -DHAVE_CONFIG_H -DLINUX -I.. -I../include -O2 -Wall -c vsnprintf.c
                 :略

  3. 執行安裝:

    suse:~/proftpd-1.3.0rc2 # make install
    cd lib/ && make lib
    make[1]: Entering directory `/root/proftpd-1.3.0rc2/lib'
    make[1]: Nothing to be done for `lib'.
    make[1]: Leaving directory `/root/proftpd-1.3.0rc2/lib'
    cd src/ && make src
    make[1]: Entering directory `/root/proftpd-1.3.0rc2/src'
              :略
    /usr/bin/install -c -s -o root -g root -m 0755 ftpcount /usr/local/proftpd/bin/ftpcount
    /usr/bin/install -c -s -o root -g root -m 0755 ftpshut /usr/local/proftpd/sbin/ftpshut
    /usr/bin/install -c -o root -g root -m 0644 ./src/proftpd.8 /usr/local/proftpd/man/man8
    /usr/bin/install -c -o root -g root -m 0644 ./utils/ftpshut.8 /usr/local/proftpd/man/man8

              :略

 整個 tarball 的安裝步驟大致如此。接著您可直接切換到 /usr/local/proftpd 去看看,裡邊是不是包含 bin、sbin、man、etc、var 等目錄。不過為了將來操作上的方便,尚須做一點調整,以方便您直接輸入指令及查看 manpage,實際做法請參考以下:

# 先將環境設定檔複製到家目錄下:
suse:/etc/skel # cp .profile .bashrc ~

# 修改 PATH

suse:~ # vi .profile
PATH="$PATH:/usr/local/proftpd/bin:/usr/local/proftpd/sbin"
export PATH
suse:~ # source .profile

# 修改 MANPATH
suse:~ # vi /etc/profile
MANPATH=`test -x /usr/bin/manpath && /usr/bin/manpath -q`:/usr/local/proftpd/man 
export MANPATH

suse:~ # source /etc/profile

 如果您覺得這樣集中管理的方式不太習慣 ( 因為還要調整路徑 ),那麼當初在執行 configure script 時可以這麼做:

suse:~/proftpd-1.3.0rc2 # ./configure --prefix=/usr --sysconfdir=/etc \
> --mandir=/usr/share/man

 這樣一來,編譯好的程式就會放在 /usr/bin、/usr/sbin 裡邊,設定檔就存放在 /etc 目錄,manpage 當然就在 /usr/share/man 底下啦。

 tarball 基本的安裝方式就是如此,至於其他有關 proftpd 的執行及進一步設定,這裡就不談了。

7.3.2 RPM 套件管理

 RPM 為 RedHat Package Manager 的簡寫,是由 RedHat 公司所發展,它是由發行商事先將檔案、編譯過的執行程式、說明文件及相關函式庫等打包到套件裡頭,且這些檔案的安裝路徑都幫您規劃好了,另外也會記載著套件的相依性。在我們安裝 RPM 套件時,也只不過是把這些相關的檔案直接安裝在指定的位置而已,因此安裝速度會比 tarball 快上許多 ﹔也由於它的方便性,使得一些 distribution 相繼採用。

 RPM 的資料庫是在 /var/lib/rpm 目錄中。今天如果安裝了一個新的套件,那麼這個套件資訊就會記錄在資料庫裡,將來要是想查詢、移除、升級套件時,也都會使用到資料庫內所記載的資訊。

 雖然使用 RPM 來安裝非常方便,但相對的也有一些缺點,其中最為人所詬病的是他的套件相依性問題,比如您下載了套件 A,要安裝時卻出現套件 A 需要相依套件 B 的訊息,所以只好再去下載套件 B,結果好不容易將套件B下載回來了,而在安裝套件 B 時又出現套件 B 需要套件 C 的訊息,進行至此可能會想放棄吧 ! 不過還好有像 apt、yum 等這類工具可以克服這方面的問題,但這不在我們討論範圍內。另外在 SuSE 裡頭,如您要安裝的套件就在光碟裡,那使用 YaST 去安裝時,會自動幫您抓出相依的套件,可以多加利用。

 另外 RPM 還有個 distribution 的問題,由於各家 distribution 所推出的 RPM,是依照他們所發行的那個版本的環境來製作 RPM 的,因此您要是想把 SuSE 的 RPM 安裝在 RedHat 上頭,可能就會有問題囉 ! 即使是同一個 distribution 也未必可行,比如 SuSE 9.3 的 RPM 安裝在 SuSE 8.2 就不一定行得通。所以今天您想安裝的軟體找不到合適的 RPM 套件時,那只好考慮下載 tarball 來安裝囉 !

 以下提供兩個可以找到各版本 RPM 套件的網站:

   http://rpmfind.net/

   http://www.rpmseek.com/index.html 

 接著來認識一下 RPM 套件到底長什麼樣子,以 ncftp-3.1.9-15.2.i586.rpm 套件檔案 (package file) 來說明好了:

   ncftp套件名稱 (package name)。

   3.1.9套件版本 (version)。

   15.2修正版 (release)。

   i586i 是指與 intel 相容的 CPU,586 則是指 CPU 等級。

 如果 RPM 套件檔案為 xxx.i586.rpm 時,那表示這個 RPM 當初是以 586 電腦作為測試的平台,以尋求最佳化的設定。另外還常看到 i386、i686、noarch 這一類的 RPM ﹔ i386 RPM 幾乎可適用在所有 X86 電腦上,但 i686 RPM 就不一定可以適用在 386 或 586 電腦上。至於 noarch RPM 則是不分任何操作平台的。

 可能您還聽過 SRPM,那是什麼東東 ? 就是 Source RPM (xxx.src.rpm) 啦,也就是套件裡頭包含了一些原始碼,所以 SRPM 須先經過編譯打包的動作,等產生了 RPM 之後才能繼續安裝。

 底下就開始來介紹如何管理 RPM 套件。這裡是使用 rpm 指令來對套件進行查詢、安裝、升級、移除等動作。

套件查詢

 如果是查詢已安裝套件的相關資訊,則後面是接 package-name,否則需接 package-file

範例說明

suse:~ # rpm -q quota
quota-3.13-17.2
# -q 同於 --query
# 查詢 quota 套件是否已安裝。

suse:~ # rpm -qa
# -a 同於 --all
# 查詢目前系統上,所有已安裝的套件。

suse:~ # rpm -qa | grep openssh
openssh-askpass-4.2p1-18.2
openssh-4.2p1-18.2
# 查詢套件名稱中含有 openssh 的所有套件。

suse:~ # rpm -ql quota
# -l 同於 --list
# 查詢 quota 套件的內容清單。

suse:~ # rpm -qi quota
# -i 同於 --info
# 查詢套件資訊,如套件名稱、版本、套件大小、發行商、數位簽章及套件的簡單描述等等。

suse:~ # rpm -qR bind
# -R 同於 --requires
# 查詢 bind 套件的相關需求資訊。

suse:~ # rpm -qf /etc/inittab
aaa_base-10-12.8
# -f 同於 --file
# 查詢 /etc/inittab 這個檔案是屬於哪個套件。

suse:~ # rpm -qc openssh
# -c 同於 --configfiles
# 只查詢套件內的相關組態檔。

suse:~ # rpm -qd openssh
# -d 同於 --docfiles
# 只查詢套件內的相關說明文件檔。

suse:~ # rpm -qilp ncftp-3.1.9-15.2.i586.rpm
# -p 同於 --package
# 當您所查詢的套件尚未安裝於系統中時,可加上 -p 參數來查詢此套件檔案的相關資訊。

suse:~ # rpm -q --changelog openssh
# 查詢該套件每個版本的修改紀錄。

suse:~ # rpm -q --whatrequires openssh
openssh-askpass-4.2p1-18.2
# 查詢該套件的相依套件為何。

套件移除

 套件在安裝或移除時,都會有其相依性的問題存在。以移除套件來說,如果所要移除的套件有相依性的問題,那麼需先移除此相依套件後,才能將原本要移除的套件刪除。

範例說明
suse:~ # rpm -e ncftp
# -e 同於 --erase
# 移除 ncftp 套件。

suse:~ # rpm -q ncftp
package ncftp is not installed
# 瞧,資料庫裡頭,已沒有 ncftp 的套件紀錄了。

suse:~ # rpm -e samba
error: Failed dependencies:
samba >= 3.0.21a-4.2 is needed by (installed) nautilus-share-0.6.4-31.8.i586
# 這訊息是提示您,在移除 samba 套件以前,需先移除 nautilus-share 套件。
# 如移除時想排除相依性的問題,可加上 --nodeps 參數。

套件安裝

 顧名思義就是將套件檔案 (package-file) 安裝於系統上,俟安裝完成後,於 RPM 資料庫裡就會有這個套件的紀錄存在。
 
 待會兒練習時,可拿出您手邊的光碟來實作看看:

範例說明
# 先將光碟掛載上來:
suse:~ # mount /dev/cdrom /media
suse:~ # cd /media/suse/i586
suse:/media/suse/i586 #

# 安裝 nmap 套件:
suse:/media/suse/i586 # rpm -ivh nmap-4.00-14.2.i586.rpm
Preparing...   ########################################### [100%]
  1:nmap    ########################################### [100%]

# -i 同於 --install安裝套件時的主要參數。
# -v 同於 --verbose顯示執行過程。
# -h 同於 --hash顯示安裝的進度,像上面那個 "#" 就是 -h 參數的效果。

# 安裝 bind 套件:
suse:/media/suse/i586 # rpm -ivh bind-9.3.2-17.4.i586.rpm
error: Failed dependencies:
    bind-chrootenv is needed by bind-9.3.2-17.4.i586

# 上面訊息是提示您要安裝 bind 套件前,需先裝上其相依套件 bind-chrootenv。
# 而如果欲忽略套件相依性來安裝的話,可加上 --nodeps 參數:
suse:/media/suse/i586 # rpm -ivh bind-9.3.2-17.4.i586.rpm --nodeps
Preparing...   ########################################### [100%]
  1:bind     ########################################### [100%]
# 平常在安裝套件時,盡量勿使用這種方式安裝,畢竟系統會提示您相依性的問題,
# 就表示說這個套件有使用到那些相依套件的某些功能,因此如果硬是把它裝上去,那
# 將來此套件所提供的功能,可能也會無法正常使用。

# 當套件已安裝在系統上,您又想再安裝一次,或者安裝時出現 [confilcting files] 訊息時,
# 則可加上 --force 參數來強迫安裝:
suse:/media/suse/i586 # rpm -ivh nmap-4.00-14.2.i586.rpm --force
Preparing...   ########################################### [100%]
  1:nmap     ########################################### [100%]

# --force 相當於 --replacepkgs、--replacefiles、 --oldpackage,至於這些參數的
# 詳細用法,請 "man rpm"。不過還是老話一句,除非您知道在做什麼,否則盡量勿使用。

套件升級

 RPM 的升級也很容易,只要使用 -U 或 -F 參數,即可完成您升級的任務。不過這兩個參數的功用有點不同,請參考以下的說明:

  -U:同於 --upgrade
    當系統已存在舊版本套件時,直接進行升級,但若不存在,則當成新安裝套件來安裝。如果存在的現有版本與升級版本相同,則會顯示套件已安裝的訊息。
     
  -F:同於 --freshen
    當系統已存在舊版本套件時,直接進行升級,但若不存在,則不會安裝。如果存在的現有版本與升級版本相同,也不會進行安裝。使用這個參數來將所有安裝過的套件進行全系統升級非常方便。例如:
suse:~ # rpm -Fvh *.rpm

 在 SLES10 裡,您還可以利用 YaST2 來進行軟體的線上更新,不過得先至官方網站申請一組帳號密碼,並索取 「啟用碼」,這樣就可以讓您免費享受 60 天的線上升級。至於線上升級的步驟很容易,只要在 YaST2 控制中心畫面裡,從 [軟體] → [Novell Customer Center Configuration] 進入,然後按照指示,一步步往下做就行了﹔這過程中,最重要的就是輸入您正確的「電子郵件地址」以及「啟用碼」,如果未輸入啟用碼,則只能享受 15 天的線上升級。而等您整個步驟都完成後,即可在桌面工作列的右方,看到一個橙色的圖示,點選進去之後,就可以開始進行軟體的升級囉。

套件內容核對

 如想了解某個套件內有哪些檔案異動過,或者檢查尚未安裝套件的完整性,那麼就要學會以下的用法噢:

範例說明

suse:~ # rpm -V vsftpd
S.5 . . . . T c /etc/vsftpd.conf
# -V 同於 --verify。

# 核對套件內的哪些檔案做了哪些異動。至於前面可能出現的字元,其所代表的意義如下:
# S : file Size differs。檔案大小有異動過。
# M : Mode differs (includes permissions and file type)檔案類型或權限有修改過。
# 5 : MD5 sum differs。MD5 檢查碼不同。
# D : Device major/minor number mis-match。主要或次要的裝置代號不符。
# L : readLink(2) path mis-match。連結檔的連結路徑有修改過。
# U : User ownership differs。檔案的擁有者變更過。
# G : Group ownership differs。檔案的擁有群組變更過。
# T : mTime differs。檔案的修改時間異動過。
# 至於最後面那個小寫的 c (configuration file),是代表組態檔的意思。
 
suse:~ # rpm -Va > verifyfile &
#
檢視系統所有已安裝套件中有異動過的檔案,並將結果輸出至 verifyfile。
#
命令列上最後面那個 "&" 是表示要把此程式放到背景去執行的意思。

suse:~ # rpm --checksig ncftp-3.1.9-15.2.i586.rpm
ncftp-3.1.9-15.2.i586.rpm: sha1 md5 gpg OK
#
--checksig 是用來檢查套件檔案的數位簽章,以確保原始套件的完整性。
#
當檢查結果是 ok 時,您就可以很安心的把此套件安裝在系統上了。

# 另外您也可以使用 md5sum 指令來做驗證,像我們不是常常會到 FTP 站台抓取 ISO 檔嗎,
# 那如何確認這個 ISO 檔沒被其他人動過呢,很簡單,只要將對方提供的 MD5SUMS
# 檔案下載回來後,查一下這個 ISO 檔的 md5 檢查碼,接著在本機執行:
suse:~ # md5sum SUSE-9.3-Eval-DVD.iso
04d2ebe4e0b8b00bc83cdc180a79e667
# 然後把列出的這一組檢查碼,拿去跟剛剛 MD5SUMS 檔案內容做比對,看看是否一致。

重建 RPM 資料庫

 由於在安裝、移除、升級套件或修改 RPM 套件內的檔案時,RPM 資料庫都必須做相關的紀錄,因此它可是非常的忙碌,所以時間一拉長,或許資料庫會顯得較無次序,此時您便可以考慮重整一下資料庫。另外有時候您安裝套件時,卻出現一些以前不曾遇過的錯誤訊息 (非相依性的問題),導致您無法正常安裝,這時候也可嘗試先重建 RPM 資料庫後再行安裝。最後就是當您執行全系統升級完畢後,馬上重建 RPM 資料庫,也是個不錯的選擇。講了半天,那到底要怎麼做呢 ? 很簡單的,請執行:

suse:~ # rpm --rebuilddb


7.4 動態連結資料庫:DLL


 在 Linux 系統上所執行的程式都會使用到函式庫,而依照應用程式與函式庫連結的方式,可區分為靜態函式庫 (Static Libraries) 及動態函式庫 (Dynamic Link Libraries、Shared Libraries) ,這兩者其實是很好區別的。靜態函式庫 (通常為 xx.a) 裡的函式原始碼需要被編譯到主程式裡頭,所以主程式會顯得比較臃腫些,但好處是該程式可以獨立執行 ﹔動態函式庫 (通常為 xx.so,如您看到的是 xx.so.2.1 之類的,那個 2.1 就是版本囉 ) 則不需整個被編譯到主程式裡邊,只需在程式的原始碼裡設計去呼叫動態函式庫即可。在 Linux 中所執行的程式幾乎都是使用動態連結資料庫。

 一般傳統的函式庫是安置在 /lib /usr/lib 目錄中,而提供系統來搜尋的函式庫,其所放置的目錄是定義在 /etc/ld.so.conf 裡。當執行 ldconfig 指令時,會先去讀取 /etc/ld.so.conf,以找出函式庫所放置的目錄位置,然後才能將這些函式庫資料寫入 cache 內,並存放一份在 /etc/ld.so.cache 中。而我們在執行一支程式時,就會由 ld.so 這個動態連結器 (dynamic linker) 程式,到 cache 內去尋找執行程式所需的函式,以提供程式做動態連結。

 不過您要是看過 /etc/ld.so.conf,會發現 /lib 及 /usr/lib 並沒有定義在 ld.so.conf 內,因為這兩個目錄是內定值,所以不需要做設定啦 ! 最後如果您有設定 LD_LIBRARY_PATH 這個環境變數的話,其所定義的目錄也會被讀入。

 如果哪天您函式庫所存放的目錄有所異動,請記得修改 /etc/ld.so.conf,然後再執行 ldconfig 指令,這樣才可以更新 cache 內的資料。以下我們稍作整理:

    1. DLL 一般是安置在 /lib 或 /usr/lib 目錄下,而除了這兩個目錄外,DLL 所存放的目錄必須在 /etc/ld.so.conf 或 LD_LIBRARY_PATH 中做定義。

    2. 執行指令 ldconfig 時,會先去讀取 /etc/ld.so.conf,然後將 DLL 讀入 cache,並紀錄一份在 /etc/ld.so.cache。當執行程式在執行時,ld.so 就會根據 cache 來找出並載入程式所需的函式庫,以讓程式能正確的執行。

    3. 欲瀏覽 /etc/ld.so.cache 內的資料,可執行:

      suse:~ # ldconfig -p

    4. 增加、減少、刪除部份 DLL 或 DLL 目錄有異動,就須執行 ldconfig,以更新 cache 的資料。

    5. 系統於開機時,預設就會執行 ldconfig,以確保 cache 內的資料是最新的。

 至於要查詢所執行的程式使用了哪些 DLL,則執行 ldd 指令即可:

# 先查出指令的位置:
suse:~ # which fdisk rpm
/sbin/fdisk
/bin/rpm

#
檢查程式所使用的 DLL:
suse:~ # ldd /sbin/fdisk /bin/rpm
/sbin/fdisk:
   linux-gate.so.1 => (0xffffe000)
   libc.so.6 => /lib/tls/libc.so.6 (0x40025000)
   /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
/bin/rpm:
   linux-gate.so.1 => (0xffffe000)
   librpmbuild-4.1.so => /usr/lib/librpmbuild-4.1.so (0x40025000)
   librpm-4.1.so => /usr/lib/librpm-4.1.so (0x40057000)
   librpmdb-4.1.so => /usr/lib/librpmdb-4.1.so (0x400a5000)
   librpmio-4.1.so => /usr/lib/librpmio-4.1.so (0x40185000)
   libpopt.so.0 => /usr/lib/libpopt.so.0 (0x401d4000)
   librt.so.1 => /lib/tls/librt.so.1 (0x401dd000)
   libpthread.so.0 => /lib/tls/libpthread.so.0 (0x401e5000)
   libz.so.1 => /lib/libz.so.1 (0x401f5000)
   libbz2.so.1 => /usr/lib/libbz2.so.1 (0x40206000)
   libc.so.6 => /lib/tls/libc.so.6 (0x40216000)
   /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

copyright © 2006 by barry ( 柏青哥 )