OPKG命令執行過程分析


一、簡介

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
這個文件被解壓到info_dir下面,並以“該軟件包的名字 . control”的方式命名。

除了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 格式文件的處理
    }
    ...
}
所以,為了使opkg暫時支持老式的ipkg,只能對代碼做些修改,找到libopkg/opkg_archive.c里面的open_outer()函數,在調用archive_read_support_format_ar()之前,加上這樣一段代碼:
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;
}
然后將調用archive_read_support_format_ar()改為調用archive_read_support_format_tar()函數:
//r = archive_read_support_format_ar(outer);
r = archive_read_support_format_tar(outer);
完整的diff如下:

重新編譯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.
然后使用 install 命令安裝:
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,官方文檔說明的已經非常詳細,此不贅述。

參考文獻

  1. https://en.wikipedia.org/wiki/Opkg
  2. http://wiki.openwrt.org/doc/techref/opkg
  3. https://code.google.com/p/opkg/
  4. http://git.yoctoproject.org/cgit/cgit.cgi/opkg/
  5. http://downloads.yoctoproject.org/releases/opkg/opkg-0.3.0.tar.gz
  6. http://wiki.openwrt.org/doc/devel/packages
    http://wiki.openwrt.org/zh-cn/doc/devel/packages
  7. http://aboutchen.org/blog/package-a-c-program-for-openwrt/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM