一、简介
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:
[email protected]:~# 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="" [email protected]:~# opkg --version opkg version 0.1.8 [email protected]:~#
二、命令执行详解
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 下面:
[email protected]:~# 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 [email protected]:~#
其中,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 <[email protected]> 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 目录下的内容(压缩了一些空白符):
[email protected]:~# 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 [email protected]:~#
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 目录看到如下内容:
[email protected]:~# 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 [email protected]:~#
下载完成后,解压到 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 两个软件包的信息,输入:
[email protected]:~# 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字符串:
[email protected]:~# 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 [email protected]:~#
在使用
[email protected]:~# opkg search *ls*
的时候,base-files 就会被打印7次:
[email protected]:~# 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 [email protected]:~#
其他文件不一一说明。读者可以尝试做一个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 <[email protected]> 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的状态,确保没有安装:
[email protected]:~# ./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 命令安装:
[email protected]:~# ./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文件:
[email protected]:~# 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/packageshttp://wiki.openwrt.org/zh-cn/doc/devel/packages
- http://aboutchen.org/blog/package-a-c-program-for-openwrt/