OpenWrt 按键处理逻辑采用 hotplug 事件方式进行管理,reset按键,用来进行重启或者恢复出厂操作。热插拔事件流程:内核具有检测 键盘守护程序,gpio_button_hotplug 模块,源码位于 openwrt/package/kernel/gpio-button-hotplug 文件夹下,系统启动时加载键盘检测模块,就驻留到内核。

内核gpio_button_hotplug 模块检测到键盘后,通过netlink-kobject方式发送到用户空间,用户空间 ubusd 系统获得到事件后,执行键盘响应的回调函数,响应键盘。
本文直接分析用户空间程序处理逻辑,不分析内核键盘模块程序、请读者自行参考netlink框架和gpio_button_hotplug.c文件分析。

RESET按键的操作对应为:
单击 - 重启设备
长按 5秒以上 – 恢复出厂设置
当然,这些操作可以通过配置etc/rc.button/reset脚本处理方法,重新定义按键功能。为什么修改rese脚本就能够重新定义呢?
接下来逐步分析,揭晓 openWRT的按键管理逻辑。

hotplug 事件注册

在 《详解 OpenWRT系统框架基础软件模块之 procd》篇,分析过procd线程启动时,调用 openWRT的state_enter() 状态机函数,此函数中,在系统 early_init 阶段,调用 hotplug() 函数注册RPC服务响应程序。源码如下:

static void state_enter(void)
{char ubus_cmd[] = "/sbin/ubusd";switch (state) {case STATE_EARLY:LOG("- early -\n");watchdog_init(0);hotplug("/etc/hotplug.json");   //热插拔函数初始化,hotplug.json文件内容非常关键procd_coldplug();               //冷插拔函数初始化break;case STATE_UBUS:// try to reopen incase the wdt was not available before coldplugwatchdog_init(0);set_stdio("console");LOG("- ubus -\n");procd_connect_ubus();service_start_early("ubus", ubus_cmd);break;case STATE_INIT:LOG("- init -\n");procd_inittab();procd_inittab_run("respawn");procd_inittab_run("askconsole");procd_inittab_run("askfirst");procd_inittab_run("sysinit");// switch to syslog log channelulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd");break;case STATE_RUNNING:LOG("- init complete -\n");procd_inittab_run("respawnlate");procd_inittab_run("askconsolelate");break;
..... 省略部分源码default:ERROR("Unhandled state %d\n", state);return;};
}

文件 /etc/hotplug.json 内容

[[ "case", "ACTION", {"add": [[ "if",[ "and",[ "has", "MAJOR" ],[ "has", "MINOR" ]],[[ "if",[ "eq", "DEVNAME",[ "null", "full", "ptmx", "zero", "tty", "net", "random", "urandom" ]],[[ "makedev", "/dev/%DEVNAME%", "0666" ],[ "return" ]]],[ "if",[ "regex", "DEVNAME", "^snd" ],[ "makedev", "/dev/%DEVNAME%", "0660", "audio" ]],[ "if",[ "regex", "DEVNAME", "^tty" ],[ "makedev", "/dev/%DEVNAME%", "0660", "dialout" ]],[ "if",[ "has", "DEVNAME" ],[ "makedev", "/dev/%DEVNAME%", "0600" ]]]],[ "if",[ "has", "FIRMWARE" ],[[ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ],[ "load-firmware", "/lib/firmware" ],[ "return" ]]]],"remove" : [[ "if",[ "and",[ "has", "DEVNAME" ],[ "has", "MAJOR" ],[ "has", "MINOR" ]],[ "rm", "/dev/%DEVNAME%" ]]]} ],[ "if",[ "and",                                      //键盘事件[ "has", "BUTTON" ],[ "eq", "SUBSYSTEM", "button" ]],[ "button", "/etc/rc.button/%BUTTON%" ]            // 键盘事件执行的脚本位置],[ "if",[ "and",                                     // usb串口事件[ "eq", "SUBSYSTEM", "usb-serial" ],[ "regex", "DEVNAME",[ "^ttyUSB", "^ttyACM" ]]],[ "exec", "/sbin/hotplug-call", "tty" ],[ "if",[ "isdir", "/etc/hotplug.d/%SUBSYSTEM%" ],[ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ]]]
]

由此文件看到 [ “button”, “/etc/rc.button/%BUTTON%” ] 内容,也就是说键盘热插拔事件发送到用户空间后,会触发程序执行此文件夹下的脚本。

OpenWRT 系统中的按键处理方法如下:

  • 在 etc/rc.button/ 文件夹下有热拔插事件响应脚本
  • 按键热拔插事件、触发etc/rc.button/ 对应的按键响应脚本
    系统按键响应逻辑是,执行响应脚本文件,用户可以直接修改脚本文件,来修订键盘处理响应逻辑。

查看 rc.button/

内容如下

root@LEDE:/# ls /etc/rc.button/
failsafe  power     reset     rfkill

响应脚本内容,分别如下:

  • 电源按键
/# cat etc/rc.button/power       // 电源off执行内容
#!/bin/sh[ "${ACTION}" = "released" ] || exit 0exec /sbin/poweroffreturn 0
  • 安全模式
/# cat etc/rc.button/failsafe    // 进入安全模式
#!/bin/sh[ "${TYPE}" = "switch" ] || echo ${BUTTON} > /tmp/failsafe_buttonreturn 0

重点看 复位按键 的脚本

root@LEDE:/# cat etc/rc.button/reset //复位按键处理
#!/bin/sh
. /lib/functions.sh
OVERLAY="$( grep ' /overlay ' /proc/mounts )"
case "$ACTION" in
pressed)                                // 内核模块gpio_button_hotplug 发送事件类型pressed[ -z "$OVERLAY" ] && return 0return 5
;;
timeout). /etc/diag.shset_state failsafe
;;
released)                               // 内核模块gpio_button_hotplug回发送事件类型released,// 并携带按键时间SEEN变量值,因此脚本判定此变量的时间值if [ "$SEEN" -lt 1 ]                       // 小于 1s , 执行reboot指令thenecho "REBOOT" > /dev/consolesyncreboot                                elif [ "$SEEN" -gt 5 -a -n "$OVERLAY" ]     // 按键超出 5s , 就执行 jffs2reset -y && rebootthenecho "FACTORY RESET" > /dev/consolejffs2reset -y && reboot &           fi
;;
esac
return 0

至此,我们揭开reset按键功能、openWRT系统是处理的全过程。接下来重点分析恢复出厂功能是如何实现的,
下面内容的重点是文件系统知识,特别是 overlay 文件系统相关知识。关于 overlay 文件系统原理,推荐阅读 《深入理解 overlayfs (一、原理)》。

reset 处理逻辑分析

reset 按键超出 5s , 就执行 jffs2reset -y && reboot & 命令,我们进一步分析 jffs2reset 命令。

  • 执行 jffs2reset -y 结果如下
root@ixeRouter:~# jffs2reset -y
/dev/mtdblock6 is mounted as /overlay, only erasing files
  • 查看分区
root@ixeRouter:~# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00030000 00010000 "bootloader"
mtd1: 00010000 00010000 "config"
mtd2: 00010000 00010000 "factory"
mtd3: 01fb0000 00010000 "firmware"
mtd4: 0020670f 00010000 "kernel"
mtd5: 01da98f1 00010000 "rootfs"
mtd6: 00640000 00010000 "rootfs_data"

得知,mtd6中的内容为 rootfs_data, 也就是路由器设备配置相关内容被擦除,
系统启动后、恢复到出厂镜像配置状态。

jffs2reset 源码分析

查看 fstools 文件夹下的 CMakeList.txt文件内容,摘录部分内容如下:

ADD_EXECUTABLE(mount_root mount_root.c) TARGET_LINK_LIBRARIES(mount_root fstools) INSTALL(TARGETS mount_root RUNTIME DESTINATION sbin)
find_library(json NAMES json-c json)ADD_EXECUTABLE(blockd blockd.c) TARGET_LINK_LIBRARIES(blockd fstools ubus blobmsg_json ${json}) INSTALL(TARGETS blockd RUNTIME DESTINATION sbin)
ADD_EXECUTABLE(block block.c probe.c probe-libblkid.c) IF(DEFINED CMAKE_UBIFS_EXTROOT) ADD_DEFINITIONS(-DUBIFS_EXTROOT)TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ubi-utils ${json}) ELSE(DEFINED CMAKE_UBIFS_EXTROOT) TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ${json}) ENDIF(DEFINED CMAKE_UBIFS_EXTROOT) INSTALL(TARGETS block RUNTIME DESTINATION sbin)# jffs2reset 命令内容对应的源码文件
ADD_EXECUTABLE(jffs2reset jffs2reset.c) TARGET_LINK_LIBRARIES(jffs2reset fstools) INSTALL(TARGETS jffs2reset RUNTIME DESTINATION sbin)ADD_EXECUTABLE(snapshot_tool snapshot.c) TARGET_LINK_LIBRARIES(snapshot_tool fstools) INSTALL(TARGETS snapshot_tool RUNTIME DESTINATION sbin)
ADD_EXECUTABLE(ubi ubi.c) TARGET_LINK_LIBRARIES(ubi ubi-utils ubox) INSTALL(TARGETS ubi RUNTIME DESTINATION sbin)

jffs2reset.c 源码文件内容

如下:


int main(int argc, char **argv)
{struct volume *v;int ch, yes = 0, reset = 0;while ((ch = getopt(argc, argv, "yr")) != -1) {switch(ch) {case 'y':yes = 1;break;case 'r':reset = 1;break;}}if (!yes && ask_user())return -1;/** TODO: Currently this only checks if kernel supports OverlayFS. We* should check if there is a mount point using it with rootfs_data* as upperdir.*/if (find_filesystem("overlay")) {ULOG_ERR("overlayfs not supported by kernel\n");return -1;}v = volume_find("rootfs_data");                // 查找分区 rootfs_data if (!v) {ULOG_ERR("MTD partition 'rootfs_data' not found\n");return -1;}volume_init(v);if (!strcmp(*argv, "jffs2mark"))return jffs2_mark(v);return jffs2_reset(v, reset);             // 执行 jffs2_reset
}

jffs2_reset 函数内容

如下


static int jffs2_reset(struct volume *v, int reset)
{char *mp;mp = find_mount_point(v->blk, 1);if (mp) {ULOG_INFO("%s is mounted as %s, only erasing files\n", v->blk, mp);fs_state_set("/overlay", FS_STATE_PENDING);overlay_delete(mp, false);                             //delete overlay分区内容mount(mp, "/", NULL, MS_REMOUNT, 0);} else {ULOG_INFO("%s is not mounted\n", v->blk);return jffs2_mark(v);}if (reset) {sync();sleep(2);reboot(RB_AUTOBOOT);while (1);}return 0;
}
  • 路由器系统文件构成
root@ixeRouter:~# cat /proc/filesystems
nodev   sysfs
nodev   rootfs
nodev   ramfs
nodev   bdev
nodev   proc
nodev   tmpfs
nodev   debugfs
nodev   tracefs
nodev   sockfs
nodev   bpf
nodev   pipefs
// 路由器文件系统构成
nodev   devptssquashfs  //文件系统
nodev   jffs2
nodev   overlay     //文件系统
nodev   ubifs

38 --> 详解 OpenWRT RESET按键、键盘响应逻辑相关推荐

  1. 37 --> 详解 OpenWRT系统框架基础软件模块之 procd

    一.简介 OpenWrt路由操作系统的框架基础软件有很多,大部分是通用的软件模块,如 dhcp .dnsmasq.iproute.cmwp.vpn.ipsec等等:OpenWrt还集成部分具有专属特征 ...

  2. 详解OpneCV的按键值获取函数waitKey()及使用中需要注意的地方

    详解OpneCV的按键值获取函数waitKey()及使用中需要注意的地方 函数waitKey()用于获取键盘输入值,其返回值便是键盘的输入值,可设置等待的时间,在等待的时间内,程序将处于"暂 ...

  3. 32 --> 详解 OpenWRT系统框架基础软件模块之netifd

    一.简介 OpenWrt路由操作系统的框架基础软件有很多,大部分是通用的软件模块,如 dhcp .dnsmasq.iproute.cmwp.vpn.ipsec等等:OpenWrt还集成部分具有专属特征 ...

  4. [OpenWrt] reset按键处理流程(hotplug)

    OpenWrt reset按键处理流程(hotplug) 介绍 本文介绍OpenWrt的reset按键的处理过程.一般的路由器都存在一个reset按键,用来进行重启或者恢复出厂操作. 通常的操作对应为 ...

  5. 电商库存系统设计mysql_详解:电商系统库存逻辑的设计

    原标题:详解:电商系统库存逻辑的设计 本文主要对电商平台的订单系统相关库存逻辑进行了详细的阐述,一起来文中看看~ 一.库存的概念 电商的业务场景中订单的流程常常伴随着库存的变化:对于erp来说,库存可 ...

  6. linux终端机详解,Linux reset设定终端机的状态命令详解

    名称: reset, tset 使用方法: tset [-IQqrs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal] 使用说明: reset ...

  7. HTTP协议详解1----请求状态与响应

    HTTP协议详解1 HTTP协议是一种无状态的协议,无状态是指web浏览器与web服务器之间不需要建立持久的连接,每当客户端发出请求(request),然后web服务返回响应(response),连接 ...

  8. 数字密码锁的详解之梳理F4总结系列逻辑篇(三)

    目录 前言:程序包下载 一.简要的过程 二.涉及的知识点 三.main.c函数 四.矩阵键盘的详解 五.串口屏的详解 前言:程序包下载 下载方式一:CSDN下载:https://download.cs ...

  9. MySQL—运算符详解(算术、比较、逻辑、范围运算符与集合运算符 模糊查询 NULL值运算与null值判断 位运算符)

    MySQL--运算符详解 知识纲要 算术运算符 比较运算符 逻辑运算符 范围运算符与集合运算符 模糊查询 NULL值运算与null值判断 位运算符 1.算术运算符 加 减 乘 除 取余 div 也表示 ...

最新文章

  1. C# 实现对接电信交费易自动缴费 续(winio/winring0 自动填密码)
  2. iOS视图控制对象生命周期-init、viewDidLoad、viewWillAppear、v...
  3. VS2008快捷键大全
  4. SharePoint优秀blog文章汇总
  5. 最全Pycharm教程
  6. XGBoost 重要参数、方法、函数理解及调参思路(附例子)
  7. Kubernetes stateful set讲解以及一个基于postgreSQL的具体例子
  8. ucharts 折线 点_ucharts图表引入的两种方式
  9. treeview 文字垂直方向_word文本排版技巧:改变文字方向的这些方法,你知道吗?...
  10. 苹果为了提升销量真是拼:用你的iPhone做最后一件好事
  11. php.ini 是否设置路由,php – 如何在路由INI文件中为Zend Framework中的子域编写路由链?...
  12. TCP协议无边界的问题
  13. idea 部署 web tomcat
  14. UI自动化测试工具-AirTest
  15. 基于SSM的宠物领养网站
  16. Java数据结构与算法——哈希表
  17. android 脚本模拟点击屏幕,android 脚本模拟点击屏幕,android模拟
  18. 【第三方互联】微博1、注册成为新浪微博(sina)开发者
  19. Labview串口通信中ASCII码和数值相互转换
  20. Oracle sql 按指定顺序产生序列号

热门文章

  1. 程序员如何用技术变现?
  2. make:Windows安装make
  3. Source insight 4.0 显示右边文件
  4. 阿里云 MaxCompute 行业级应用(优酷、斗鱼)及 MaxCompute SQL 调优
  5. 基于Java毕业设计高校教学资源系统源码+系统+mysql+lw文档+部署软件
  6. 微信事件推送原理猜想与小程序接口对接经验之谈(即时配送)
  7. 交易就是练就这五种能力(干货分享)
  8. [机缘参悟-49]:三季人与认知维度
  9. 课程设计项目——网上商城
  10. unity particle system 粒子系统 制作闪电放电效果