一、簡介
Opkg 是一個基於 ipkg 的輕量級的軟件包管理系統,主要用於嵌入式系統,目前應用opkg的有Open WRT 和 Open Embedded。1
Opkg的詳細使用方法可以參考Open WRT的 WIKI頁面2,不再贅述,本文將重點解釋opkg的工作原理。
Opkg 的源代碼可以在Google Code 3或Yocto Project 4上找到。Opkg的版本目前到了0.3.0 5,我使用的 Open WRT Barrier Breaker 14.07 系統上是0.1.8:
root@OpenWrt:~# cat /etc/openwrt_release DISTRIB_ID="OpenWrt" DISTRIB_RELEASE="14.07" DISTRIB_REVISION="r42625" DISTRIB_CODENAME="barrier_breaker" DISTRIB_TARGET="x86/generic" DISTRIB_DESCRIPTION="OpenWrt Barrier Breaker 14.07" DISTRIB_TAINTS="" root@OpenWrt:~# opkg --version opkg version 0.1.8 root@OpenWrt:~#
二、命令執行詳解
0. 加載基本配置
這是執行所有命令之前的准備工作。加載配置的函數是 opkg_conf_load(). Opkg 有一個命令行參數 -f / --conf 可以明確指定配置文件,如果沒有指定,那么 Opkg 使用默認的配置文件。
在 v0.1.8 版本上,Opkg 在args_parse() 函數解析完畢命令行參數后,如果沒有 -f / --conf 參數,那么會默認使用 /etc/opkg.conf 作為配置文件:
if(!conf->conf_file && !conf->offline_root) conf->conf_file = xstrdup("/etc/opkg.conf");
v0.3.0 的版本去掉了這個默認值。以下說明都是基於 v0.3.0 的代碼,其他版本可以參考對應的代碼,應該大同小異。查找配置文件的步驟:
(1) 使用命令行參數指定的配置文件,如果沒有,轉(2);
(2) 使用命令行指定的 offline-root 路徑下面的 *.conf,如果沒有,轉(3);
(3) 如果設置了環境變量 OFFLINE_ROOT,使用該路徑下面的 *.conf,如果沒有,轉(4);
(4) 如果設置了環境變量 OPKG_CONF_DIR,使用該路徑下面的 *.conf,如果沒有,轉(5);
(5) 使用默認的OPKG_CONF_DEFAULT_CONF_FILE_DIR(宏,代碼中默認為 /etc/opkg),使用該路徑下面的 *.conf,如果該路徑不存在,則無法解析任何配置文件。
在准備過程中,配置文件是最重要的一個環節。除了配置文件,opkg 還需要初始化一些其他的變量(路徑):
變量 |
默認值 |
Temp Directory |
/tmp |
Hash List |
|
Lists Directory |
/var/lib/opkg/lists |
Info Directory |
/var/lib/opkg/info |
Status File |
/var/lib/opkg/status |
Signature File |
|
Arch List |
all, noarch, HOST_CPU_STR |
Dest List |
|
Cache Directory |
/var/cache/opkg |
注:HOST_CPU_STR為編譯opkg時由configure指定的 --host 的值,可以在config.log 或者生成的 Makefile 中查看。
以上變量都有各自重要的用處,在后面的說明中會逐一涉及。
注:由於我是在 OpenWrt Barrier Breaker 14.07 上進行測試,所以在命令行上必須手動加上參數:
-f /etc/opkg.conf
否則opkg無法找到配置文件(目前最新版的Chaos Calmer 15.05-rc3也是同樣的情況)。
解析完配置文件后,把配置文件中的 dest 指定的目錄,加到 Dest List 中,例如:
dest root /
dest ram /tmp
然后,連接這個路徑分別和以下幾個路徑連接:
(1) 和 Info Directory 連接作為該 dest 的 Info Directory;
(2) 和 Status File 連接作為該 dest 的 Status File;
(3) 和 Lists Directory 連接作為該 dest 的 Lists Directory。
以 / 為例:
//var/lib/opkg/info/ //var/lib/opkg/lists/ //var/lib/opkg/status
對比v0.1.8,這些目錄是放在了 /usr/lib/opkg 下面:
root@OpenWrt:~# ls /usr/lib/opkg -l drwxr-xr-x 2 root root 8192 Oct 1 2014 info drwxr-xr-x 2 root root 4096 Oct 1 2014 lists -rw-r--r-- 1 root root 15932 Oct 1 2014 status root@OpenWrt:~#
其中,status 文件為所有軟件包的基本信息,包括名稱、版本、依賴、狀態、初始安裝日期等,以 libc 為例:
Package: libc Version: 0.9.33.2-1 Depends: libgcc Status: install hold installed Essential: yes Architecture: x86 Installed-Time: 1412176159 Auto-Installed: yes
Lists 文件夾下面是根據配置文件中的src/gz指定的URL下載下來的文件,例如:
src/gz barrier_breaker_base http://downloads.openwrt.org/barrier_breaker/14.07/x86/generic/packages/base
在執行 update 后,會使用下面的URL下載一個文件:
http://downloads.openwrt.org/barrier_breaker/14.07/x86/generic/packages/base/Packages.gz
文件下載后,將解壓的文件放到 Lists 目錄下面,並把第二個字段(如上面的barrier_breaker_base)作為文件名,這個文件里面包含了該Package里面所有的軟件包的信息,舉一為例:
Package: 6in4 Version: 17-1 Depends: libc, kmod-ipv6, kmod-sit Source: package/network/ipv6/6in4 Section: net Maintainer: Jo-Philipp Wich <xm@subsignal.org> Architecture: all Installed-Size: 1194 Filename: 6in4_17-1_all.ipk Size: 1832 MD5Sum: 6758bb49b2a828301bdac956481ec6c1 SHA256sum: 1ad5794959c8435c7ab4c261ab86d2974d65527f7b8ffa99eee370409993976c Description: Provides support for 6in4 tunnels in /etc/config/network. Refer to http://wiki.openwrt.org/doc/uci/network for configuration details.
查看 Lists 目錄下的內容(壓縮了一些空白符):
root@OpenWrt:~# ls /var/lib/opkg/lists/ -l -rw-r--r-- 1 root root 485307 Jul 18 14:44 barrier_breaker_base -rw-r--r-- 1 root root 43348 Jul 18 14:44 barrier_breaker_luci -rw-r--r-- 1 root root 4634 Jul 18 14:44 barrier_breaker_management -rw-r--r-- 1 root root 715082 Jul 18 14:44 barrier_breaker_oldpackages -rw-r--r-- 1 root root 455216 Jul 18 14:44 barrier_breaker_packages -rw-r--r-- 1 root root 34987 Jul 18 14:44 barrier_breaker_routing -rw-r--r-- 1 root root 260681 Jul 18 14:44 barrier_breaker_telephony root@OpenWrt:~#
0.1 配置文件的格式
配置文件中有下面
類型(type) |
說明 |
option |
配置某些參數,可供配置的參數可以在libopkg/opkg_conf.c里面的options[]數組中找到 |
dist |
可供更新的發行版(存疑) |
dist/gz |
可供更新的發行版(存疑),gzip格式 |
src |
可供更新的軟件源 |
src/gz |
可供更新的軟件源,gzip格式 |
dest |
本地目標路徑 |
1. 更新 update
Opkg里用結構體 opkg_cmd 來表示一個命令,對應命令行的command參數。該結構體定義如下:
struct opkg_cmd { const char *name; int requires_args; opkg_cmd_fun_t fun; unsigned int pfm; /* package field mask */ }; typedef struct opkg_cmd opkg_cmd_t;
所有命令都保存在 libopkg/opkg_cmd.c 文件的 cmds[] 數組中,這里就不列出這個數組的值了。更新update使用的函數是opkg_update_cmd(),update后面無需參數。
更新時執行的步驟:
(1) 檢查 Lists 文件夾是否存在,如果不存在,則創建該文件夾;
(2) 創建臨時目錄 $tmp_dir/update-XXXXXX,其中 $tmp_dir 就是前面提到的 Temp Directory;
(3) 更新dist指定的軟件包;
(4) 更新src指定的軟件包;
(5) 刪除(2)中創建的臨時目錄。
下載過程是這樣的:
(1) 構造下載地址:如果指定為gzip格式,那么用 $URL/Packages.gz 下載,否則用 $URL/Packages 下載;
(2) 對於gzip格式的文件,下載到 cache 目錄下,文件名是把URL中的 / 替換為下划線 _ ,因此可以在 cache 目錄看到如下內容:
root@OpenWrt:~# ls /var/cache/opkg/ http:__downloads.openwrt.org_barrier_breaker_14.07_x86_generic_packages_base_Packages.gz http:__downloads.openwrt.org_barrier_breaker_14.07_x86_generic_packages_luci_Packages.gz http:__downloads.openwrt.org_barrier_breaker_14.07_x86_generic_packages_management_Packages.gz http:__downloads.openwrt.org_barrier_breaker_14.07_x86_generic_packages_oldpackages_Packages.gz http:__downloads.openwrt.org_barrier_breaker_14.07_x86_generic_packages_packages_Packages.gz http:__downloads.openwrt.org_barrier_breaker_14.07_x86_generic_packages_routing_Packages.gz http:__downloads.openwrt.org_barrier_breaker_14.07_x86_generic_packages_telephony_Packages.gz root@OpenWrt:~#
下載完成后,解壓到 lists 目錄下,並命名為配置文件中設置的名字;
(3) 對於非gzip格式的文件,則直接下載到 lists 目錄下面,並命名為配置文件中設置的名字。
2. 列出軟件包 list/list-installed
列出軟件包命令list和更新upgrade稍有不同,在開始執行命令之前的准備工作,會讀取lists 目錄下的文件,這個文件的格式前面提到了。將所有文件內的每個軟件包的信息都加載到內存中, 在讀取文件的過程中,opkg會分析每個軟件包的Architecture 字段,只有當該字段的值在 Arch List 中時,才會將該軟件包加到 hash table 里面(opkg_config->file_hash)。
下面的事情就比較簡單了,list 就是將 file_hash 里面所有的軟件包打印出來。
列出安裝的軟件包list-installed命令,並不會讀取 lists 目錄下的文件,而是讀取 Status List 包含的每個文件,系統已安裝的軟件包會放到這個文件里面,然后將Status包含installed的軟件包打印出來。
3. 查看軟件包狀態 status/info
Status和info這兩個命令使用同一個函數opkg_info_status_cmd(),這個函數的原型如下:
int opkg_info_status_cmd(int argc, char **argv, int installed_only)
使用status命令時,第三個參數 installed_only 為1,只查找已安裝的軟件包;使用info命令時,installed_only為0,查找所有軟件包:
if (installed_only) pkg_hash_fetch_all_installed(available); else pkg_hash_fetch_available(available);
接下來就是在設定的范圍內順序查找,如果status/info 后面有參數,那么只打印與參數名匹配的軟件包的狀態,否則打印全部的狀態。
在這里發現opkg的一個微小的不足:當info/status后面跟的參數有多個,比如我想看 lua和 libc 兩個軟件包的信息,輸入:
root@OpenWrt:~# opkg status lua libc
只打印出lua的信息,沒有libc的信息。這是因為opkg在查找時,如果有參數,那么只搜索第一個參數的軟件包,后面的參數都被忽略了。讀者有興趣可以嘗試做一個patch改進此問題。
4. 列出和搜索文件 files/search
files命令用於列出一個軟件包所包含的全部文件,這些文件包括可執行文件、配置文件等。對於已安裝過的軟件包,則打開 $lists_dir 下面的軟件包對應的 list 文件,例如軟件包 busybox,對應的list文件為
/var/lib/opkg/info/busybox.list
這個文件包含了該軟件包所包含的文件,每行一個。
對於未安裝的軟件包,打印軟件包尚未安裝的錯誤信息:
pkg = pkg_hash_fetch_installed_by_name(argv[0]); if (pkg == NULL) { opkg_msg(ERROR, "Package %s not installed.\n", argv[0]); return 0; }
Search 命令則用於查找某個文件屬於哪個軟件包,可以使用通配符(使用fnmatch函數來進行模式匹配)。對應的函數為 opkg_search_cmd(),這個過程也比較簡單:獲取全部安裝的軟件包,依次查找每個軟件包所包含的文件,如果包含要查找的文件,那么就打印出該軟件包。
這個函數也有一些缺陷,如果一個軟件包所包含的文件,有多個可以匹配搜索的文件,那么結果該軟件包就會被打印多次。以搜索ls為例,在base-files中有以下7個文件包含ls字符串:
root@OpenWrt:~# cat /var/lib/opkg/info/base-files.list | grep ls /etc/shells /etc/protocols /lib/preinit/10_indicate_failsafe /etc/rc.button/failsafe /lib/preinit/40_run_failsafe_hook /lib/preinit/30_failsafe_wait /lib/preinit/99_10_failsafe_login root@OpenWrt:~#
在使用
root@OpenWrt:~# opkg search *ls*
的時候,base-files 就會被打印7次:
root@OpenWrt:~# opkg search *ls* base-files - 156-r42625 base-files - 156-r42625 base-files - 156-r42625 base-files - 156-r42625 base-files - 156-r42625 base-files - 156-r42625 base-files - 156-r42625 busybox - 1.22.1-2 busybox - 1.22.1-2 fstools - 2014-06-22-e0430f5c62f367e5a8e02755412977b02c3fc45e luci-app-firewall - 0.12+svn-r10530-1 luci-app-firewall - 0.12+svn-r10530-1 luci-app-firewall - 0.12+svn-r10530-1 luci-app-firewall - 0.12+svn-r10530-1 luci-base - 0.12+svn-r10530-1 luci-base - 0.12+svn-r10530-1 luci-base - 0.12+svn-r10530-1 luci-base - 0.12+svn-r10530-1 luci-base - 0.12+svn-r10530-1 luci-base - 0.12+svn-r10530-1 netifd - 2014-09-08-46c569989f984226916fec28dd8ef152a664043e ubox - 2014-09-16-5c45b560bc8c9e13682269ed963a8a4a65959518 root@OpenWrt:~#
其他文件不一一說明。讀者可以嘗試做一個patch,使得每個軟件包最多打印一次。
5. 安裝 install
安裝 install 后面可以跟多種類型的參數:
(1) URL: opkg 嘗試直接使用此URL下載一個軟件包;
(2) Package: 軟件包名稱,opkg會獲取該軟件包的名稱(Filename字段),構造下載地址,例如 base 軟件包里面的 6in4 ,Filename 字段為6in4_17-1_all.ipk,base的src為
http://downloads.openwrt.org/barrier_breaker/14.07/x86/generic/packages/base
所以 6in4 的下載地址為
http://downloads.openwrt.org/barrier_breaker/14.07/x86/generic/packages/base/6in4_17-1_all.ipk;
(3) File: opkg會把這個名字當作一個文件名,文件的格式必須如 Lists 目錄下的文件,或者如 control 文件(/var/lib/opkg/info/*.control),opkg從中解析出所有軟件包的信息,並進行下載。
(4) File: opkg會把這個名字作為一個准備好的軟件包(ipk)文件,直接進行安裝,並標記為手動。
在進行實際的下載、安裝動作之前,opkg 會做幾件事:
檢查軟件狀態(是否安裝):在pkg_hash_load_feeds() (也就是opkg_conf_load()之后,執行install command之前),Opkg會從Lists文件(/var/lib/opkg/lists目錄下)獲取所有軟件包的信息,如果一個軟件的名字有有多個軟件庫提供,則把所有提供該軟件包的 軟件庫放到provided_by 中,在檢查是否安裝軟件時,將檢查每個provided_by,如果有任何一個已安裝,那么就會認為該軟件已安裝;
(1) 檢查是否已安裝舊版本的軟件包;
(2) 查找要安裝的軟件包信息,如果該軟件包有多個軟件庫提供,那么pkg_hash_fetch_best_installation_candidate() 函數會選擇一個最佳的匹配(最佳匹配的規則是,手動最高,然后按照architecture的優先級排序);
(3) 檢查舊、新軟件包的版本:如果舊的版本較高,並且標記強制降級(命令行參數--force-downgrade),則不做任何事情;如果新舊版本一樣,表示已安裝位最新版本,不做任何事;否則進行升級(或者強制降級)。
以上所有准備工作就緒,開始真正安裝軟件包,這個動作是在opkg_install_pkg() 函數中完成的,這個函數的原型如下:
int opkg_install_pkg(pkg_t * pkg, int from_upgrade)
第二個參數為是否升級,使用 install 命令時,即使有舊版本的軟件,這個參數也為0;當使用 upgrade 命令時,該參數才為1. 這個標記有兩個影響:
(1) 是否打印安裝軟件包時的信息:只有升級upgrade時打印;
(2) 如果已安裝好最新版本的軟件,或者沒有強制降級,那么install會直接退出(無需做任何事情),而升級upgrade則強制把所有安裝軟件包的流程執行完(不明白意義在哪里?)。
安裝過程如下:
(1) 檢查軟件包沖突:沖突是通過lists文件內的Conflicts字段表示的;
(2) 檢查磁盤剩余空間是否足夠:軟件包占用的空間通過lists文件內的Installed-Size字段指定,磁盤空間通過statvfs()函數獲取;
(3) 檢查簽名文件: 當 check_signature為非0 時,才會檢查簽名文件,可以在配置文件中加入“check_signature”來設置;
(4) 下載軟件包:如果為手動模式,則無需下載;
(5) 更新文件所有者:將該軟件包含的全部文件的所有者設為該軟件包,並加入到opkg_config->file_hash中;
(6) 檢查依賴:可以通過opkg命令行參數--nodeps忽略檢查;
(7) 如果存在舊軟件包,更新新、舊軟件依賴:如果舊軟件的某個依賴,新的軟件不再依賴,檢查該依賴是否還有其他軟件依賴,如果沒有,則可以安全刪除該依賴;如果新軟件的某個依賴,舊的軟件沒有,那么需要安裝新的依賴(有點繞);
(8) 安裝維護腳本:老式的ipk文件(*)是一個gz格式的壓縮包,里面有3個文件:
~ $ tar -tvf binutils_2.24-2_x86.ipk -rw-r--r-- bb/bb 4 2014-09-21 19:05 ./debian-binary -rw-r--r-- bb/bb 838861 2014-09-21 19:05 ./data.tar.gz -rw-r--r-- bb/bb 359 2014-09-21 19:05 ./control.tar.gz
其中 control.tar.gz 里面包含一個control文件:
~ $ tar -tvf control.tar.gz drwxr-xr-x root/root 0 2014-09-21 19:05 ./ -rw-r--r-- root/root 298 2014-09-21 19:05 ./control
這個文件就是維護腳本(maintainer script),解壓出來查看其內容:
~ $ tar xf control.tar.gz ~ $ cat control Package: binutils Version: 2.24-2 Depends: libc, objdump Source: package/devel/binutils Section: devel Maintainer: Felix Fietkau <nbd@openwrt.org> Architecture: x86 Installed-Size: 838861 Description: The Binutils package contains a linker, an assembler, and other tools for handling object files
除了control文件,有些軟件包還包含配置文件,這個配置文件是交給UCI來管理的,其格式同UCI配置文件的格式,如果有配置文件,那么在control.tar.gz里面還會包含一個文件conffiles,比如以transmission-daemon為例,這個軟件的control.tar.gz壓縮包內有兩個文件:
~ $ tar xvf control.tar.gz ./ ./control ./conffiles
Conffiles這個文件里面包含了該軟件所包含的配置文件,transmission-daemon只有一個配置文件,conffiles內容如下:
~ $ cat conffiles /etc/config/transmission
在軟件安裝完成后,會根據這個配置文件進行某些設置。
注:這里使用了一個詞“老式的ipk文件”,在v0.3.0版本的opkg上,軟件包的格式是ar,並且不再支持gz格式,由於暫時找不到新式的軟件包,所以暫時無法使用新的opkg安裝老式的ipk軟件。(非常郁悶!!)而v0.1.8版本的代碼上支持兩種格式,在libbb/unarchive.c的deb_extract()函數中:
char * deb_extract(const char *package_filename, FILE *out_stream, const int extract_function, const char *prefix, const char *filename, int *err) { if (strncmp(ar_magic,"!<arch>",7) == 0) { ... // 對 ar 格式文件的處理 } else if (strncmp(ar_magic, "\037\213", 2) == 0) { ... // 對 gz 格式文件的處理 } ... }
r = archive_read_support_filter_gzip(outer); if (r != ARCHIVE_OK) { opkg_msg(ERROR, "GZ filter not supported: %s\n", archive_error_string(outer)); goto err_cleanup; }
//r = archive_read_support_format_ar(outer); r = archive_read_support_format_tar(outer);
重新編譯opkg之后放到虛擬機里面運行,以安裝 libpolarssl (這個軟件包依賴較少,是個可供選擇的測試軟件)為例:
首先查看libpolarssl的狀態,確保沒有安裝:
root@OpenWrt:~# ./opkg info libpolarssl -f /etc/opkg.conf Package: libpolarssl Version: 1.3.9-2 Depends: libc Status: unknown ok not-installed Section: libs Architecture: x86 MD5Sum: 1b6f66f94eb1f5a47959be09ccefbf2c Size: 140082 Filename: libpolarssl_1.3.9-2_x86.ipk Source: package/libs/polarssl Description: The aim of the PolarSSL project is to provide a quality, open-source cryptographic library written in C and targeted at embedded systems. This package contains the PolarSSL library.
root@OpenWrt:~# ./opkg install libpolarssl -f /etc/opkg.conf Installing libpolarssl (1.3.9-2) on root. Downloading http://downloads.openwrt.org/barrier_breaker/14.07/x86/generic/packages/base/libpolarssl_1.3.9-2_x86.ipk. Configuring libpolarssl.
可以查看該軟件的control文件:
root@OpenWrt:~# cat /var/lib/opkg/info/libpolarssl.control Package: libpolarssl Version: 1.3.9-2 Depends: libc Source: /home/jow/relman/.cache/feeds/base/package/libs/polarssl License: GPL-2.0+ Section: libs Architecture: x86 Installed-Size: 140583 Description: The aim of the PolarSSL project is to provide a quality, open-source cryptographic library written in C and targeted at embedded systems. This package contains the PolarSSL library.
成功。
(9) 安裝數據文件:在第(8)步中已看到,ipk文件中除了control.tar.gz還有一個data.tar.gz,這個就是該軟件包的所有文件(可執行程序、配置文件等),這一步就是把data.tar.gz內的文件解壓到 root_dir 下面。解壓完成后,還有兩件事:a. 設置內存中該軟件包的Essential字段;b. 將該軟件包含的文件寫到 info_dir 下面的 list文件中。所以在 info_dir 下面可以看到每個軟件包都有兩個文件:control文件和list文件。
(10) 檢查沖突文件:主要是處理replace類型的軟件包,函數為:
check_data_file_clashes_change() 。
(11) 設置配置文件:在安裝軟件的時候,用戶如果之前安裝過該軟件的其他版本,那么可能對配置文件做過修改,因此這一步會進行適當的設置,當發現新舊配置文件有所不同時,除非用戶明確指定強制、或忽略維護者設置(即新軟件默認的設置),否則opkg會檢查是否存在備份配置文件,如果存在,則默認使用備份的設置。備份的文件配置通常為“配置文件名稱 -opkg.backup”,例如dhcp的配置文件為/etc/config/dhcp,那么它的備份文件命名為/etc/config/dhcp-opkg.backup。使用--force-maintainer來強制使用新配置,實用--ignore-maintainer來忽略新配置。
安裝完成后,需要對軟件進行配置,這個動作與opkg configure命令是一樣的。配置動作只針對標記為UNPACKED的軟件包,而新安裝的軟件包總是包含這個標記。軟件包的配置,是通過運行postinst腳本,這個腳本位於info_dir下面,以“軟件包名稱 . postinst”命名,如果存在這個文件,opkg通過 system() 函數,執行命令:
sh -c $postinst configure
由於暫時沒有發現包含postinst腳本的軟件,所以這個過程暫時不知。
6. 升級 upgrade
更新操作基本上與安裝相同,前面也已經提到了更新操作的一些不同之處,例如如果升級、強制降級的問題等。更新upgrade命令后面可以有參數,表示升級指定的軟件包,如果軟件包尚未安裝,則不會執行安裝動作;如果upgrade沒有參數,那么opkg將嘗試升級所有軟件包(類似apt-get upgrade)。安裝完成后,同樣執行配置動作。如果有必要,更新status文件中該軟件的狀態。
7. 刪除 remove
刪除軟件包的過程如下:
(1) 檢查Essential 標記:如果該軟件包為Essential的,除非用戶強制刪除(使用--force-removal-of-essential-packages參數),否則opkg拒絕刪除該軟件;
(2) 檢查依賴:檢查系統中有哪些其他的軟件包依賴於要刪除的軟件包,如果有,那么打印出依賴於該軟件包的其他軟件包,然后結束刪除動作;如果用戶希望強制刪除該軟件以及依賴於該軟件的所有其他軟件,可以使用--force-removal-of-dependent-packages參數,opkg將首先刪除依賴於該軟件的其他軟件;
(3) 執行刪除前腳本:如果軟件在刪除前需要做一些動作,比如結束正在運行的進程等等,那么在info_dir下面會有一個“軟件包名稱 . prerm”的腳本,opkg首先執行:
sh -c $prerm remove
(4) 刪除文件:該軟件包含的全部文件保存在list_dir下面的“軟件包名稱 . list”文件中,每行一個,opkg會刪除該軟件所包含的全部文件,然后將 .list 文件一並刪除;
(5) 執行刪除后腳本:如果軟件在刪除后需要做一些清理動作,比如某些臨時文件等等,那么在info_dir下面會有一個“軟件包名稱 . postrm”的腳本,opkg會執行:
sh -c $postrm remove
(6) 刪除維護者腳本:刪除在info_dir下面的control文件;
(7) 自動刪除其他軟件:如果用戶在remove命令后加了--autoremove參數,opkg會嘗試刪除安裝此軟件包時自動安裝的其他軟件包(如果有)。
刪除動作完成后,更新status文件中軟件包的狀態。
8. 清理 clean
清理就是刪除cache文件夾下面的文件。
三、其他
1. 加鎖
在opkg加載配置文件(函數opkg_conf_load())中,讀取所有配置之前,會創建一個 /var/run/opkg.lock 的文件,並對該文件進行加鎖(lockf()),在配置文件讀取完畢后,釋放鎖,並刪除這個文件。但不知為什么執行其他的操作,比如安裝、刪除等動作時,opkg反而不加鎖了。
2. 生成軟件包
生成Opkg格式的軟件包,只需按照固定的格式填寫一份Makefile即可6 7,官方文檔說明的已經非常詳細,此不贅述。
參考文獻
- https://en.wikipedia.org/wiki/Opkg
- http://wiki.openwrt.org/doc/techref/opkg
- https://code.google.com/p/opkg/
- http://git.yoctoproject.org/cgit/cgit.cgi/opkg/
- http://downloads.yoctoproject.org/releases/opkg/opkg-0.3.0.tar.gz
- http://wiki.openwrt.org/doc/devel/packages
http://wiki.openwrt.org/zh-cn/doc/devel/packages - http://aboutchen.org/blog/package-a-c-program-for-openwrt/