OPKG命令执行过程分析

OPKG命令执行过程分析一、简介Opkg是一个基于ipkg的轻量级的软件包管理系统,主要用于嵌入式系统,目前应用opkg的有OpenWRT和OpenEmbedded。1Opkg的详细使用方法可以参考OpenWRT的WIKI页面2,不再赘述,本文将重点解释opkg的工作原理。Opkg的源代码可以在GoogleCode3或YoctoProject4上找到。Opkg的版本目前到了0.3.05,我使用的

大家好,又见面了,我是你们的朋友全栈君。

转自:http://www.cnblogs.com/zhangbaoqiang/p/4792628.html

一、简介

Opkg 是一个基于 ipkg 的轻量级的软件包管理系统,主要用于嵌入式系统,目前应用opkg的有Open WRT 和 Open Embedded。1

Opkg的详细使用方法可以参考Open WRT的 WIKI页面2,不再赘述,本文将重点解释opkg的工作原理。

Opkg 的源代码可以在Google Code 3或Yocto Project 4上找到。Opkg的版本目前到了0.3.05,我使用的 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/info/*.list
Info Directory var/lib/opkg/info/*.control
Status File Status File
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) 创建临时目录 tmpdir/updateXXXXXX tmp_dir 就是前面提到的 Temp Directory;

(3) 更新dist指定的软件包;

(4) 更新src指定的软件包;
所有命令都保存在 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指定的软件包;

所有命令都保存在 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指定的软件包;

下载完成后,解压到 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, "73", 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
7. http://wiki.openwrt.org/zh-cn/doc/devel/packages
8.http://aboutchen.org/blog/package-a-c-program-for-openwrt/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/134712.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 关于DNS负载均衡技术

    关于DNS负载均衡技术在学习负载均衡技术的时候,我们肯定会学到dns负载均衡的相关内容,因为这个是负载均衡的一个代表应用。那么说到应用,到底是如何进行使用,改善网络问题的呢?那么本文就将为大家详细介绍一下其中的原理。为了建立一个高负载的Web站点,必须使用多服务器的分布式结构?上面提到的使用代理服务器和Web服务器相结合,或者两个Web服务器相互协作的方式也属于多服务器的结构,但在这些多服务器的结构中,每个服务器所

  • JS中promise是什么?

    JS中promise是什么?Promise是异步编程的一中解决方案,最早是由社区提出的,es6中正式的将其纳入,他是一个对象,可以获取到异步的操作,他相比传统的回调函数,更加的强大和合理,避免了回调地狱。所谓的Promise,简单的来说就是一个可以存放未来才能结束的任务或者事件。1.Promise实列有三个状态:-pending(进行中)-resolved(成功)-rejected(失败)当要处理某个任务的时候,promise的状态是pending,任务完成是状态就变成了resolved,任务失败状

  • VBA编程_常用函数总结1[通俗易懂]

    VBA编程_常用函数总结1[通俗易懂]文章目录IsEmptyReplaceAscMidRoundIsEmpty  用于判断单元格是否为空:SubMain()ActiveSheet.Cells(7,3).Value=1IfIsEmpty(ActiveSheet.Cells(7,3))ThenDebug.Print”IsEmpty”ElseDebug.Print”NotEmpty”EndIfEndSubReplace  函数原型如下

  • 常用Anaconda安装错误解决办法Traceback (most recent call last):[通俗易懂]

    常用Anaconda安装错误解决办法Traceback (most recent call last):[通俗易懂]Anaconda安装错误的解决办法异常提示解决办法适用异常提示Traceback(mostrecentcalllast):File"E:\anaconda\lib\site-packages\psutil_pswindows.py",line63…………File"E:\anaconda\lib\site-packages\psutil_pswindows.py",line…

  • 4月份考核:Windows系统基本设置

    4月份考核:Windows系统基本设置

  • Springboot自动装配原理_自动装配原理

    Springboot自动装配原理_自动装配原理springboot自动装配原理详解1)传统ssm整合redis的时候需要在xml的配置文件中进行大量的配置Bean我们在这里使用springboot来代替ssm的整合,只是通过xml的形式来整合redis第一步:加入配置<dependency><groupId>org.springframework.data</grou…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号