init.rc脚本的特性和dhcpcd的程序特性导致内存耗尽

探讨了由于dhcpcd程序特性与init.rc脚本交互导致的内存耗尽问题。详细介绍了问题产生的原因在于dhcpcd使用fork后关闭父进程,而init周期性检查并重启已消失PID的服务,造成dhcpcd不断被重复创建。
init.rc脚本的特性和dhcpcd的程序特性导致内存耗尽

init进程会周期性检查所有由init启动的service服务进程, 当init通过PID发现由init创建的该服务进程的PID不存在之后(被手工kill掉或者程序fork()之后,关闭了父进程),那么init进程会再次启动[luther.gliethttp].

原init.rc脚本
...
service dhcpcd /system/bin/dhcpcd eth0
disabled
...
运行一段时间之后,通过ps发现dhcpcd一直在增加,最后耗尽了所有内存,使得系统运行缓慢.

原因:在于dhcpcd程序使用了fork(),然后关闭掉父进程,子进程进入daemon,但是android的init程序周期性检查所有 service发现,被init创建出来的service的PID消失了,于是将再次start service启动dhcpcd,其实这时dhcpcd是以子进程的身份运行在daemon后台,所以导致dhcpcd程序一直持续不断的被init进程创建.

临时解决方案:
修改后脚本
...
service dhcpcd /system/bin/dhcpcd eth0
disabled
oneshot //表示init进程仅对该service启动一次[luther.gliethttp]
...
转:[url]http://blog.chinaunix.net/u1/38994/showart_1209634.html[/url]
<think>我们正在处理一个RK3506设备上启动dhcpcd时出现"Bad system call"错误的问题。根据用户提供的错误信息: ``` /etc/init.d/S41dhcpcd: line 12: 456 Bad system call ``` 我们需要分析可能的原因解决方案。 ### 问题分析 1. **Bad system call (系统调用错误)**:这通常表示程序尝试执行了一个操作系统不允许的系统调用。在嵌入式Linux环境中,这可能是由于: - 内核配置中未启用某些必要的系统调用或功能。 - 程序dhcpcd)使用的系统调用被seccomp过滤器或安全模块(如SELinux)阻止(但在嵌入式设备中较少见)。 - 内核版本与用户空间程序不兼容(dhcpcd可能需要较新的内核支持,而当前内核版本过低)。 - 编译dhcpcd时使用的内核头文件版本与运行时的内核版本不一致。 2. **启动脚本位置**:错误发生在`/etc/init.d/S41dhcpcd`的第12行。我们需要检查该脚本的内容,特别是第12行是什么命令。 3. **RK3506平台特性**:RK3506采用的是Cortex-A35内核,通常运行Linux系统。在Buildroot或类似嵌入式Linux构建系统中,dhcpcd作为网络配置工具被包含。 ### 解决方案步骤 #### 步骤1:检查启动脚本内容 查看`/etc/init.d/S41dhcpcd`脚本的第12行是什么命令。可以使用以下命令: ```bash cat /etc/init.d/S41dhcpcd | head -n 12 | tail -n 1 ``` 或者直接打开文件查看。 常见的dhcpcd启动脚本内容可能如下(不同系统可能有差异): ```bash #!/bin/sh # Start dhcpcd case "$1" in start) echo "Starting dhcpcd..." start-stop-daemon --start --quiet --exec /sbin/dhcpcd -- -b -q -t 30 ;; stop) echo "Stopping dhcpcd..." start-stop-daemon --stop --quiet --exec /sbin/dhcpcd ;; restart|reload) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 esac exit 0 ``` 如果第12行是启动`dhcpcd`的命令(例如上面的`start-stop-daemon`那一行),则问题出在`dhcpcd`程序本身。 #### 步骤2:检查内核配置 由于是系统调用错误,我们需要确认内核是否支持`dhcpcd`所需的所有系统调用。`dhcpcd`是一个网络管理工具,它需要的基本系统调用包括socket相关的调用(如`socket`, `bind`, `connect`等)、网络接口操作(如`ioctl`的SIOCGIFADDR等)、以及一些进程操作(如`fork`, `exec`)等。 通常,嵌入式内核配置可能为了精简而裁剪掉一些功能。请检查以下内核配置选项是否启用(需要重新编译内核): - `CONFIG_NET` (网络支持) - `CONFIG_INET` (IPv4支持) - `CONFIG_UNIX` (Unix域套接字,部分程序依赖) - `CONFIG_POSIX_TIMERS` (POSIX定时器) - `CONFIG_EPOLL` (epoll系统调用) - `CONFIG_SIGNALFD` (signalfd系统调用,dhcpcd可能使用) - `CONFIG_EVENTFD` (eventfd系统调用) 特别注意:`dhcpcd`可能会使用一些相对较新的系统调用,例如`getrandom`(用于获取随机数)。如果内核版本低于3.17且没有启用`CONFIG_GETRANDOM`,则可能导致问题。 #### 步骤3:检查内核版本与dhcpcd的兼容性 运行以下命令查看内核版本: ```bash uname -a ``` 然后检查当前使用的`dhcpcd`版本。在Buildroot中,dhcpcd的版本可以在构建配置中看到。如果内核版本过旧(例如低于3.10),而dhcpcd版本较新(如9.x以上),则可能出现不兼容。 #### 步骤4:使用strace跟踪系统调用 如果设备支持`strace`工具,可以尝试使用它来跟踪dhcpcd的系统调用,以确定是哪个系统调用导致了错误。命令如下: ```bash strace -o /tmp/dhcpcd.log /sbin/dhcpcd ``` 然后检查日志文件`/tmp/dhcpcd.log`,找到出错的地方(日志中会显示系统调用名称错误号,错误号对应EINVAL或ENOSYS等,表明系统调用不可用)。 #### 步骤5:临时解决方案 - 使用其他网络配置工具 如果问题无法快速解决,可以考虑替换dhcpcd为其他网络配置工具,例如`udhcpc`(BusyBox自带)或`dhclient`(如果可用)。在Buildroot中,可以配置BusyBox启用`udhcpc`,然后创建启动脚本调用`udhcpc`。 #### 步骤6:修复dhcpcd启动脚本 如果发现脚本本身有问题(例如使用了不兼容的命令或选项),可以修改脚本。例如,简化启动命令,避免使用`start-stop-daemon`(嵌入式系统可能没有这个命令),直接调用`dhcpcd`: ```bash /sbin/dhcpcd -b -q -t 30 ``` ### 具体操作建议 1. **检查脚本并简化**:修改`/etc/init.d/S41dhcpcd`脚本,将启动命令改为直接运行`dhcpcd`(假设设备上路径为`/sbin/dhcpcd`): ```bash #!/bin/sh # Start dhcpcd case "$1" in start) echo "Starting dhcpcd..." /sbin/dhcpcd -b -q -t 30 ;; ... # 其他部分不变 esac ``` 然后重启或重新运行该脚本。 2. **使用udhcpc替代**: - 确保Busybox编译时启用了`udhcpc`(在Buildroot的busybox配置中,选择`Networking Utilities -> udhcpc`)。 - 创建或修改启动脚本(例如`/etc/init.d/S40network`)来启动udhcpc: ```bash #!/bin/sh # Start udhcpc for eth0 case "$1" in start) echo "Starting udhcpc..." udhcpc -i eth0 -p /var/run/udhcpc.pid -b -q ;; ... # 其他部分 esac ``` - 删除或禁用一个已有的dhcpcd启动脚本(将其从`/etc/init.d/`移走或改名,使其不以S开头)。 3. **内核配置修正**(需要重新构建内核): - 在Buildroot配置中,进入`Kernel`配置菜单,检查并确保上述提到的内核选项已启用。 - 特别是随机数相关的系统调用(`getrandom`)网络相关选项。 4. **更新软件包**:如果dhcpcd版本过旧,可能有已知bug,尝试在Buildroot中更新dhcpcd到最新版本(或相反,降低版本以适配旧内核)。 ### 结论 由于错误信息是“Bad system call”,最可能的原因是内核缺少dhcpcd需要的某个系统调用支持。因此,重点检查内核配置,特别是与网络随机数生成相关的系统调用。另外,简化启动脚本并跟踪系统调用也是有效的调试手段。 如果时间紧迫,使用BusyBox自带的udhcpc作为替代方案是最快捷的解决方法。 ### §§相关问题§§ 1. RK3506设备上如何配置使用udhcpc代替dhcpcd? 2. 如何检查Linux内核是否支持特定的系统调用? 3. 在Buildroot中如何重新配置内核以启用缺失的系统调用? </think>好的,我针对RK3506设备上启动dhcpcd时出现"Bad system call"错误进行分析并提供解决方案: ### 问题分析 根据错误信息 `/etc/init.d/S41dhcpcd: line 12: 456 Bad system call`,该问题通常由以下原因引起: 1. **内核兼容性问题**:dhcpd二进制文件使用了当前内核不支持的系统调用[^4] 2. **工具链不匹配**:dhcpd使用不同工具链编译(如glibc vs musl)[^2] 3. **内核配置缺失**:缺少必要的内核功能(如NETFILTER、CGROUP等)[^1] 4. **内存保护机制**:内核启用了CONFIG_SECCOMP等安全特性[^5] ### 解决方案 #### 1. 检查启动脚本内容(关键步骤) 查看`/etc/init.d/S41dhcpcd`第12行的具体命令: ```bash sed -n '12p' /etc/init.d/S41dhcpcd ``` 典型问题行示例: ```bash start-stop-daemon --start --quiet --exec /sbin/dhcpcd -- -b -q -t 30 ``` #### 2. 替换启动命令(快速解决方案) 修改脚本第12行,改用直接执行方式: ```bash # 原始问题行(可能导致Bad system call) # start-stop-daemon --start --quiet --exec /sbin/dhcpcd -- -b -q -t 30 # 替换为 /sbin/dhcpcd -b -q -t 30 ``` 修改后重启服务: ```bash /etc/init.d/S41dhcpcd restart ``` #### 3. 验证二进制文件兼容性 检查dhcpcd的编译环境: ```bash # 查看二进制文件类型 file /sbin/dhcpcd # 检查动态链接库 ldd /sbin/dhcpcd ``` 若输出显示`musl libc`但系统使用`glibc`(或反之),需重新编译[^2][^4] #### 4. 重新编译dhcpcd(推荐方案) 在Buildroot环境中执行: ```bash # 进入Buildroot目录 make menuconfig # 定位到 Target packages → Networking applications → dhcpcd # 开启[*] dhcpcd # 关闭[ ] Enable privilege separation (可能导致问题) # 保存配置后重新编译 make dhcpcd-rebuild ``` #### 5. 内核配置优化 在内核配置中确保启用: ``` [*] Networking support → [*] Networking options → [*] Packet socket [*] Unix domain sockets [*] General setup → [*] Control Group support [*] Security options → [ ] Enable seccomp to safely compute untrusted bytecode (临时关闭) ``` ### 调试命令 ```bash # 使用strace跟踪系统调用 strace -o /tmp/dhcpcd.log /sbin/dhcpcd # 检查日志中失败的syscall grep -i "ENOSYS" /tmp/dhcpcd.log ``` ### 替代方案 若问题持续,可改用`udhcpc`(BusyBox自带): ```bash # 修改启动脚本 echo "udhcpc -i eth0 -p /var/run/udhcp.pid" > /etc/init.d/S41network chmod +x /etc/init.d/S41network ``` ### 最终验证 ```mermaid sequenceDiagram participant User participant InitScript participant Dhcpcd participant Kernel User->>+InitScript: /etc/init.d/S41dhcpcd start InitScript->>+Dhcpcd: 执行简化命令 Dhcpcd->>+Kernel: 系统调用请求 alt 系统调用支持 Kernel-->>-Dhcpcd: 成功响应 Dhcpcd-->>-InitScript: 返回0 InitScript-->>-User: 启动成功 else 系统调用不支持 Kernel-->>-Dhcpcd: ENOSYS错误 Dhcpcd-->>-InitScript: 返回错误码 InitScript-->>-User: Bad system call end ``` > **注意**:如采用关闭seccomp等安全特性,在产品发布前应重新评估安全策略[^5]。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值