1. linux的热拔插udev机制
1.1 热拔插:在开机和运行的状态下,可以安全地安装或者转移硬件,不需要关闭电源或者重启。
1.2 udev
1.3 例子
•例如,在上述的实验中:
•手机刚刚插进去开发板之后,应用程序是不能使用手机的(因为adb(应用层)找不到对应usb设备文件(应用层是没有权限使用这个设备文件)),例如执行adb会不成功。
•一开始,当有usb设备(手机)接入开发板的时候,是内核先知道usb设备的(这里把设备接入开发板,仅仅只是实现了让内核知道而已,可以使用dmesg可以知道设备的信息,但是在应用层是不认识这个设备的,应用层是没法访问到设备的(没权限),怎样才能认识这个设备并为这个设备创建文件 --> udev机制)。
•但是在应用层(应用程序adb)是没法访问到usb设备的,虽然此时在dev目录下还有对应的usb设备文件(找不到对应的手机设备文件),但是在应用层就没法访问到usb设备的(没权限)。怎样可以让应用层认识设备并创建设备文件 -->使用udev规则。
•只有当udev检测到内核中有侦听到有usb设备接入的信息并且添加了对应的udev规则,才会在/dev/bus/usb/001那里动态创建设备文件(并且这这个文件的权限是0666),之后adb程序(应用层)能访问到usb设备(手机)。
•但是前提必须要有下面对应的规则才能配置对应的设备文件,如果没有这条规则,就不会为新接入的设备配置对应的设备文件权限(usb设备)。
•当在/etc/udev/rules.d这个目录下创建vivo-android.rules(赋予usb设备可读可写权限)这个文件给 udev服务和使用之后,应用层可以访问usb设备了(可以使用adb去访问了)。
•简单说:没有udev规则,udev机制就不知道如何管理设备,没有udev机制,规则就只是一堆文本文件。两者紧密结合,共同实现 Linux 的动态设备管理。
2. 守护进程
2.1 概念:
2.2 基本特点
2.3守护进程开发方式
#include <unistd.h> /* int daemon(int nochdir, int noclose); 函数参数: nochdir:为0时表示将当前目录更改至“/”,转换工作目录和脱离终端 noclose:为0时表示将标准输入、标准输出、标准错误重定向至“/dev/null” 返回值:成功则返回0,失败返回-1 */ #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <time.h> #include <stdio.h> //C 库函数 char *asctime(const struct tm *timeptr) 返回一个指向字符串的指针,它代表了结构 //struct timeptr 的日期和时间。 //C 库函数 struct tm *localtime(const time_t *timer) 使用 timer 的值来填充 tm 结构。 //timer 的值被分解为 tm 结构,并用本地时区表示。 /* struct tm { int tm_sec; 秒,范围从 0 到 59 int tm_min; 分,范围从 0 到 59 int tm_hour; 小时,范围从 0 到 23 int tm_mday; 一月中的第几天,范围从 1 到 31 int tm_mon; 月份,范围从 0 到 11 int tm_year; 自 1900 起的年数 int tm_wday; 一周中的第几天,范围从 0 到 6 int tm_yday; 一年中的第几天,范围从 0 到 365 int tm_isdst; 夏令时 }; */ static bool flag = true; void handler(int sig) { printf("I got a signal %d\nI'm quitting.\n", sig); flag = false; } int main() { time_t t; int fd; //创建守护进程 if(-1 == daemon(0, 0)){ printf("daemon error\n"); exit(1); } //设置信号处理函数 struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if(sigaction(SIGQUIT, &act, NULL)){ printf("sigaction error.\n"); exit(0); } //进程工作内容 while(flag){ fd = open("/home/orangepi/daemon.log", O_WRONLY | O_CREAT | O_APPEND,0644); if(fd == -1){ printf("open error\n"); } t = time(0);//获取当前时间戳 char *buf = asctime(localtime(&t)); write(fd, buf, strlen(buf)); close(fd); sleep(10); } return 0; } //sudo vi /etc/rc.local 开机自启动,绝对路径加程序名字,一开机就能启动这个守护进程了。3. 守护进程的应用
3.1守护进程不让控制程序退出
#include <unistd.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <time.h> #include <stdio.h> #include <stdbool.h> static bool flag = true; void handler(int sig){ printf("I got a signal %d\nI'm quitting.\n", sig); flag = false; } int judMent(){ FILE *file; char buffer[128] = {'\0'}; char *cmd = "ps -elf |grep douyinUtils|grep -v grep"; file = popen(cmd, "r"); fgets(buffer, 128, file); if(strstr(buffer, "douyinUtils") != NULL){ return 0; }else{ return -1; } printf("BUFFER:%s\n",buffer); } int main(){ time_t t; int fd; //创建守护进程 if(-1 == daemon(0, 0)){ printf("daemon error\n"); exit(1); } //设置信号处理函数 struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if(sigaction(SIGQUIT, &act, NULL)){ printf("sigaction error.\n"); exit(0); } //进程工作内容 while(flag){ if( judMent() == -1){ system("/home/orangepi/hardwareSoft/douyin/douyinUtils /dev/ttyS5 &"); } sleep(2); } return 0; } //开机启动: // /home/orangepi/hardwareSoft/douyin/douyinUtils /dev/ttyS5 & 添加了&变成后台程序。 // /home/orangepi/hardwareSoft/douyin/shouhuDouyin3.2守护进程和后台进程的区别
4. udev规则的补充
• 规则文件是 udev里最重要的部分,默认是存放在/etc/udev/rule.d/ 下。所有的规则文件必须以 ".rules" 为后缀名。这是一个简单的规则:KERNEL=="sda", NAME="my_root_disk", MODE="0660"
4.1 udev匹配键
ACTION:事件(uevent)的行为,例如:add(添加设备)、remove(删除设备); KERNEL:内核设备名称,例如:sda,cdrom; DEVPATH:设备的 devpath 路径; SUBSYSTEM:设备的子系统名称,例如:sda 的系统为 block; BUS:设备在 devpath 里的总线名称,例如:usb; DRIVER:设备在 devpath 的设备驱动名称,例如:ide-cdrom; ID:设备在 devpath 里的识别号; SYSFS{filename}:设备的 devpath 路径下,设备的属性文件 "filename" 里的内容; ENV{key}:环境变量。在一条规则中,可以设定最多五条环境变量的 匹配键; PROGRAM:调用外部命令; RESULT:外部命令 PROGRAM 的返回结果。