概述:我們知道使用源代碼進行軟件編譯可以具有定制化的設置,但對于Linux distribution的發行商來說,則有軟件管理不易的問題,畢竟不是每個人對于操作系統都非常的熟悉,不是每個人都會進行源代碼編譯的,因此如果能夠將軟件現在相同的硬件與操作系統上編譯好才發行的話,如果再加上簡易的安裝/刪除/管理等機制,則對于軟件管理會簡單的多,因此有了我們目前最流行的RPM和YUM軟件包管理神器,本節我們先介紹RPM,讓我們一睹為快吧!
一、什么是RPM
RPM全名“RedHat Packgae Manger”簡稱則為RPM。它是以一種數據庫記錄方式將你所需要的軟件安裝到你的Linux系統的一套管理機制。
RPM最大的優點就是將你要安裝的軟件先編譯過,并且打包成為RPM機制的安裝包,通過包裝好的軟件里頭默認數據庫記錄這個軟件要安裝的時候必須具備的依賴關系,當你安裝軟件包時,RPM會先依照軟件里面的數據庫查詢Linux主機的依賴屬性軟件是否滿足,若滿足則予以安裝,不滿足則不予安裝。這樣以來我們可以總結它的優勢在于:
1、RPM內容已經編譯過程序與設置文件等數據,可以讓用戶免除重新編譯的困擾
2、RPM在安裝之前,會先檢查系統的硬盤容量、操作系統的版本等,可以避免文件的錯誤安裝
3、RPM文件本身提供軟件版本信息、依賴屬性軟件名稱、軟件用途說明、軟件所含文件等的信息,便于了解軟件
4、RPM管理的方式使用數據庫記錄RPM文件的相關參數,便于升級、刪除、查詢與驗證
同時我們也會發現這種軟件管理機制的問題:
1、軟件安裝的環境必須與打包的環境需求一致
2、需要滿足軟件的依賴性要求
3、反安裝時需要特別注意,最底層的軟件不可先刪除,否則可能造成整個系統的問題
二、RPM包名詳解
name-VERSION-release.arch.rpm
例: bash-4.2.46-19.el7.x86_64.rpm
VERSION: major.minor.release (軟件版本)
release: release.OS(發布的操作系統)
常見的arch(硬件平臺):
x86: i386, i486, i586, i686(32位)
x86_64: x64, x86_64, amd64(64位)
powerpc: ppc
跟平臺無關: noarch
包:分類和拆包
Application-VERSION-ARCH.rpm: 主包
Application-devel-VERSION-ARCH.rpm 開發子包
Application-utils-VERSION-ARHC.rpm 其它子包
Application-libs-VERSION-ARHC.rpm 其它子包
包之間:可能存在依賴關系,甚至循環依賴
解決依賴包管理工具:
yum: rpm包管理器的前端工具
apt-get: deb包管理器前端工具
zypper: suse上的rpm前端管理工具
dnf: Fedora 18+ rpm包管理器前端管理工具
三、RPM屬性依賴的解決方式:YUM在線升級
我們知道安裝RPM軟件包經常會提醒你,少這個包少那個包,這都是軟件互相的依賴性導致的,這也是RPM最頭疼的事,那么有沒有辦法解決呢?前面不是談到RPM會記錄軟件的依賴屬性的相關數據嗎?那么我們要是能將這些依賴關系屬性軟件先列表,在有軟件需要安裝的時候先到這個列表去查找,同時與系統內已經安裝的軟件相比較,沒有安裝的依賴軟件一口氣全部給安裝了,不就一下解決了所謂的依賴性問題了嗎?那么有沒有這種軟件包管理機制?當然有,這就是YUM機制。
我們先來簡單了解YUM管理機制,后續會加以詳細介紹。Centos會發布軟件到YUM服務器內,然后分析這些軟件的依賴性問題,將軟件的記錄信息寫下來。然后再將這些信息分析后記錄成軟件相關性的清單列表。這些列表數據和軟件所在的位置我們可以稱為YUM倉庫(repository)。當客戶端有軟件安裝需求時,客戶端主機會主動向網絡上的yum服務器的倉庫網址下載清單列表,然后通過清單列表的數據與本機RPM數據庫已存在的軟件數據相比較,就能夠一口氣安裝所有需要具有依賴性的軟件。整個流程我們可以使用下面的示意圖表示:
當客戶端有升級安裝需求時,yum會向yum倉庫要求清單更新,等到清單跟新到本機的/var/cache/yum里面后,接下來更新時就以用到這個本機清單與本機的RPM數據庫進行比較在,這樣就知道該下載哪些軟件。然后yum就會跑到倉庫的服務器下載所需要的軟件,然后再通過RPM機制開始安裝軟件。這就是整個流程,因此YUM最終還是需要RPM的,它是最根本的,因此我們必須得掌握,接下來我們繼續了解RPM。
四、RPM軟件管理程序:rpm
1、RPM默認安裝的路徑
一般來說,RPM類型的文件在安裝的時候,會先讀取文件內記載的設置參數內容,然后將數據用來比較Linux系統的環境,以找出是否有屬性依賴關系的軟件沒有安裝的問題。若環境檢查合格了,那么RPM文件就開始安裝到你的Linux主機上。安裝完畢后,該軟件的相關的信息就會被寫入/var/lib/rpm目錄下面的數據庫文件中。上年這個目錄非常重要。因為我們有任何軟件升級需求,版本之間的比較也就是來自這個數據庫,而如果你想要查詢系統已經安裝的軟件,也是根據這個查詢的。
軟件內的文件到底安裝在哪里呢?當然根據你的文件系統有關了,通常為
下面我們針對每個RPM的相關命令進行說明。
2、RPM安裝(install)
rpm {-i|–install} [install-options] PACKAGE_FILE…
-i:install(安裝)
-v:verbose(查看詳細的安裝信息)
-h:安裝信息欄顯示安裝進度
-vv:更詳細的信息顯示
通常我們使用:rpm -ivh PACKAGE_FILE …
[install-options]
–test: 測試安裝,但不真正執行安裝; dry run模式
–nodeps:忽略依賴關系
–replacepkgs | replacefiles
前者重新安裝后者直接覆蓋安裝
–nosignature: 不檢查來源合法性
–nodigest:不檢查包完整性
–noscipts:不執行程序包腳本片斷
%pre: 安裝前腳本; –nopre
%post: 安裝后腳本; –nopost
%preun: 卸載前腳本; –nopreun
%postun: 卸載后腳本; –nopostun
3、RPM升級(upgrade)
rpm {-U|–upgrade} [install-options] PACKAGE_FILE…
rpm {-F|–freshen} [install-options] PACKAGE_FILE…
upgrade:安裝有舊版程序包,則“升級”如果不存在舊版程序包,則“安裝”
freshen:安裝有舊版程序包,則“升級”如果不存在舊版程序包,則不執行升級操作
rpm -Uvh PACKAGE_FILE …
rpm -Fvh PACKAGE_FILE …
–oldpackage:降級
–force: 強行升級,這個參數相當于–replacepkgs和–replacefiles的結合
升級注意事項:
(1) 不要對內核做升級操作; Linux支持多內核版本并存,因此,對直接安裝新版本內核。
(2) 如果原程序包的配置文件安裝后曾被修改,升級時,新版本的提供的同一個配置文件并不會直接覆蓋老版本的配置文件,而把新版本的文件重命名(FILENAME.rpmnew)后保留。
4、RPM查詢(query)
rpm {-q|–query} [select-options] [query-options]
[select-options]
-a: 所有包
-f: 查看指定的文件由哪個程序包安裝生成
-p rpmfile:針對尚未安裝的程序包文件做查詢操作;
–whatprovides CAPABILITY:查詢指定的CAPABILITY
由哪個包所提供
–whatrequires CAPABILITY:查詢指定的CAPABILITY被
哪個包所依賴
rpm2cpio 包文件|cpio –itv 預覽包內文件
rpm2cpio 包文件|cpio –id “ *.conf” 釋放包內文件
[query-options]
–changelog:查詢rpm包的changelog
-c: 查詢程序的配置文件
-d: 查詢程序的文檔
-i: information
-l: 查看指定的程序包安裝后生成的所有文件;
–scripts:程序包自帶的腳本片斷
-R: 查詢指定的程序包所依賴的CAPABILITY;
–provides: 列出指定程序包所提供的CAPABILITY;
我們經常要使用的組合選項:
-q:僅查詢,后面接軟件名稱查看是否安裝
-qa:列出所有的已經安裝在本機系統上的所有軟件名稱
-qi:后面接軟件名稱,列出該軟件的詳細信息
-ql:后面接軟件名稱,列出該軟件所有的文件與目錄
-qc:后面接軟件名稱,列出該軟件的配置文件
-qd:后面接軟件名稱,列出該軟件的幫助文件
-qR:后面接軟件名稱,列出該軟件所依賴軟件所含的文件
-qf:由后面接文件,找出該文件屬于哪一個已安裝的軟件
-qp:注意用途僅在于找出某個RPM文件內的信息,而非已安裝的軟件!
4、RPM卸載與重建數據庫(erase/rebuilddb)
rpm {-e|–erase} [–allmatches] [–nodeps] [–noscripts] [–notriggers] [–test] PACKAGE_NAME …
通常使用:rpm -e packge_name
由于RPM文件經常會安裝、升級、卸載等操作,某些操作或許會導致RPM數庫/var/lib/rpm的損壞,因此我們使用–rebuilddb這個參數來重建數據庫。
rpm {–initdb|–rebuilddb}
initdb: 初始化,如果事先不存在數據庫,則新建之。否則,不執行任何操作。
rebuilddb:重建,無論當前存在與否,直接重新創建數據庫。
5、RPM驗證與數字證書(Verify/Signature)
rpm {-V|–verify} [select-options] [verify-options]
-V:后面加軟件名稱,若該軟件所含的文件被修改過,則會被檢查出來
-Va:列出系統上面可能被改動過的軟件所包含的文件
-Vp:后面加文件名稱,列出該軟件可能被改動的文件
-Vf:后面接文件名稱,列出某個文件是否被修改過
使用上述參數可以查出來文件名前面會出現一些不熟悉的單個字母或者一些字母,我們來了解下這些字母的含義。
S file Size differs (文件的容量大小是否被修改)
M Mode differs (includes permissions and file type)
文件的類型或者文件的屬性是否被改變
5 digest (formerly MD5 sum) differs
MD5指的是一種指紋碼的內容已經不同
D Device major/minor number mismatch
設備的主次代碼已經改變
L readLink(2) path mismatch(Link路徑已經發生改變)
U User ownership differs(文件所有者發生改變)
G Group ownership differs(文件所屬組發生改變)
T mTime differs(文件的修改時間已經發生改變)
P capabilities differ
至于上面的那個c是什么東西呢?C代表“configure”,也就是文件類型,文件類型有下面幾類:
c:配置文件
d:文檔
g:ghost文件
l:授權文件
r:自述文件
談完了軟件的驗證后,不知道你有沒有發現一個問題,那就是驗證只能驗證軟件內的信息與數據庫里面的信息而已,如果該軟件提供的數據本身就有問題呢?那你使用驗證的手段就無法確定該軟件的正確性,那么怎么解決呢?我們可以用過數字證書來檢驗軟件來源的。
數字證書就像自己的簽名一樣,我們的軟件開發商所推出的軟件會有一個自己證書系統,只是這個證書被數字化了,廠商可以使用數字證書系統產生一個專屬與該軟件的證書,并將該證書的公鑰發布,當你要安裝一個RPM文件是:
a、首先你必須要先安裝原廠發布的公鑰文件
b、實際安裝原廠RPM軟件是,rpm命令會讀取RPM文件的證書信息,與本機系統內的證書信息比較
c、若證書相同則予以安裝,若找不到相關的證書信息,則給予警告且停止安裝。
根據上述說明,我們也會知道首先必須要安裝原廠釋放的GPG數字證書的公鑰文件,Centos7的數字證書位于:/etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
我們也可以使用find命令查找文件名的關鍵詞進行查找
find / -name ‘*GPG-KEY*’
導入所需要公鑰:
rpm -K|checksig rpmfile 檢查包的完整性和簽名
rpm –import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
CentOS 7發行版光盤提供: RPM-GPG-KEY-CentOS-7
rpm -qa gpg-pubkey*
本文僅為Linux的軟件包管理器神器之一&RPM的簡單介紹,其中有不不對的地方請各位老司機予以指正,后續我們還會繼續介紹YUM在線升級以及編譯安裝方法。
五、贈送腳本小練習
1、寫一個服務腳本/root/bin/testsrv.sh,完成如下要求
(1) 腳本可接受參數: start, stop, restart, status
(2) 如果參數非此四者之一,提示使用格式后報錯退出
(3) 如是start:則創建/var/lock/subsys/SCRIPT_NAME, 并顯示“啟動成功”
考慮:如果事先已經啟動過一次,該如何處理?
(4) 如是stop:則刪除/var/lock/subsys/SCRIPT_NAME, 并顯示“停止完成”
考慮:如果事先已然停止過了,該如何處理?
(5) 如是restart,則先stop, 再start
考慮:如果本來沒有start,如何處理?
(6) 如是status, 則如果/var/lock/subsys/SCRIPT_NAME文件存在,則顯示
“ SCRIPT_NAME is running…”
如果/var/lock/subsys/SCRIPT_NAME文件不存在,則顯示“ SCRIPT_NAME
is stopped…”
其中: SCRIPT_NAME為當前腳本名
#!/bin/bash #作者:薛帥 #版本:1.0 #時間:2016-08-21 #腳本功能描述: #寫一個服務腳本/root/bin/testsrv.sh,完成如下要求 #(1) 腳本可接受參數: start, stop, restart, status #(2) 如果參數非此四者之一,提示使用格式后報錯退出 #(3) 如是start:則創建/var/lock/subsys/SCRIPT_NAME, 并顯示“啟動成功” #考慮:如果事先已經啟動過一次,該如何處理? #(4) 如是stop:則刪除/var/lock/subsys/SCRIPT_NAME, 并顯示“停止完成” #考慮:如果事先已然停止過了,該如何處理? #(5) 如是restart,則先stop, 再start #考慮:如果本來沒有start,如何處理? #(6) 如是status, 則如果/var/lock/subsys/SCRIPT_NAME文件存在,則顯示 #“ SCRIPT_NAME is running...” #如果/var/lock/subsys/SCRIPT_NAME文件不存在,則顯示“ SCRIPT_NAME #is stopped...” #其中: SCRIPT_NAME為當前腳本名 #================================================================ script_name=$(basename $0) servicefile=/var/lock/subsys/"$script_name" start() { if [ -f $servicefile ];then echo "服務已經啟動了" else touch $servicefile echo "啟動成功" fi } stop() { if [ -f $servicefile ];then rm -f $servicefile echo "停止完成" else echo "服務已經關閉了" fi } restart() { stop start } status() { if [ -f $servicefile ];then echo " SCRIPT_NAME is running..." else echo "SCRIPT_NAMEis stopped..." fi } #===========主程序================= PS3="根據上述提示,選擇一個數字:" select menu in start stop restart status ;do case $menu in start) start ;; stop) stop ;; restart) restart ;; status) status ;; esac exit 5 done
執行結果如圖所示:
2、編寫一個腳本/root/bin/copycmd.sh
(1) 提示用戶輸入一個可執行命令名稱;
(2) 獲取此命令所依賴到的所有庫文件列表
(3) 復制命令至某目標目錄(例如/mnt/sysroot)下的對應路徑下;
如: /bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd ==> /mnt/sysroot/usr/bin/passwd
(4) 復制此命令依賴到的所有庫文件至目標目錄下的對應路徑下:
如: /lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ldlinux-x86-64.so.2
(5)每次復制完成一個命令后,不要退出,而是提示用戶鍵入新的要復制的命令,并重復完成上述功能;直到用戶輸入quit退出
#!/bin/bash #作者:薛帥 #版本:1.0 #時間:2016-8-21 #腳本功能描述:編寫一個腳本/root/bin/copycmd.sh #(1) 提示用戶輸入一個可執行命令名稱; #(2) 獲取此命令所依賴到的所有庫文件列表 #(3) 復制命令至某目標目錄(例如/mnt/sysroot)下的對應路徑下; #如: /bin/bash ==> /mnt/sysroot/bin/bash #/usr/bin/passwd ==> /mnt/sysroot/usr/bin/passwd #(4) 復制此命令依賴到的所有庫文件至目標目錄下的對應路徑下: #如: /lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ldlinux-x86-64.so.2 #(5)每次復制完成一個命令后,不要退出,而是提示用戶鍵入新的要復制的命 #令,并重復完成上述功能;直到用戶輸入quit退出 #================================================================= copyfile() { local dir=$(dirname $1) #取傳遞參數的目錄名 local destdir=/mnt/sysroot$dir #由于沒有該目錄,因此定義一個目標的目錄,留下面創建目錄用 mkdir -p $destdir #創建以/mnt/sysroot下面是你要傳遞的目錄 cp -a "$1" "$destdir" #復制你傳遞的目錄文件到上面新建的目錄里面 } #=========主函數================ while true;do read -p "請輸入一個命令" mingling if [[ "$mingling" == "quit" ]];then echo "退出啦!" break else dir=$(which $mingling |grep "/.*") liblist=$(ldd $dir |grep -o "/lib64/.*"|cut -d" " -f1) copyfile $dir # 復制命令至某目標目錄(例如/mnt/sysroot)下的對應路徑下 for libdir in $liblist;do #循環將該命令的庫文件一個一個復制到/mnt/sysroot/lib64/路徑下 copyfile $libdir done fi done unset dir unset liblist unset mingling
執行結果如下圖所示:
原創文章,作者:AndyIvanXue,如若轉載,請注明出處:http://www.www58058.com/38773