Daemons and UDEV Mechanisms

Mobile phone access to Linux hot-swapping related:

  1. To communicate with Android, command interaction, and data interaction, you need to install adb (Android Debug Bridge)ADB (Android Debug Bridge) is a command-line tool for communicating with Android devices.

  2. sudo apt-get install adb//apt-get automatically searches, installs, upgrades, and uninstalls software or operating systems from Internet software warehouses.

  3. Use adb devices to list all connected devices

  4. If the list shows no permissions, you need to:

  • cd /etc/udev/rules.d//Create a service for udev, after using the file, the system can access the phone

  • Then create a .rules file, sudo vim Redmi-android.rules, enter in the file:
    SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0666"

    5. Use the adb shell to enter the command line interface of the device (mobile phone operating system). In the adb shell, you can execute various commands to interact and debug with the device

Use shell commands to operate the mobile phone screen, simulating manual sliding screen:

  • adb shell input swipe 540 1300 540 500 Swipe down 540 is horizontal, 1300 is vertical, down is 500
  • adb shell input swipe 540 500 540 1300 Swipe up
  • adb shell “seq 3 | while read i;do input tap 350 1050 & amp; input tap 350 1050 & amp; sleep 0.02;done;”
  • adb shell input keyevent 26 lock screen

Realize voice brush vibrato:

#include "UartTool.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "wiringSerial.h"

int fd;
void *srchandler()
{
    char cmd;
    while(1){
    
        cmd = myserialGetchar(fd);
        //printf("GET->%c\
",cmd);
    
        switch(cmd){
            case 'N':
                printf("next\
");
                system("adb shell input swipe 540 1300 540 500");
                break;
            case 'P':
                printf("pre\
");
                system("adb shell input swipe 540 500 540 1300 100");
                break;
            case 'Z':
                printf("zan\
");
                system("adb shell "seq 3 | while read i; do input tap 350 1050 & amp; input tap 350 1050 & amp; sleep 0.02; done;"");
                break;
            case 'Q':
                printf("quit\
");
                system("adb shell input keyevent 26");
                break;
        }
    }
}

int main(int argc, char **argv)
{
 pthread_t src;
    if(argc != 2){
        printf("usage:%s /dev/ttyS?\
", argv[1]);
        exit(-1);
    }
    
    fd = myBaudserialOpen(argv[1],115200);
    if(fd == -1){
        fprintf(stderr,"%s","serial init error\
");
        exit(-1);
    }
    
    pthread_create( & src, NULL, srchandler, NULL);
    
    while(1){sleep(10);}
    return 0;
}

Linux hot-plug UDEV mechanism:

udev is a device management tool, udev runs in the form of a daemon process, and manages the device files in the /dev directory by listening to the uevent sent by the kernel. udev runs in user space, not kernel space. It can dynamically update device files according to the status of hardware devices in the system, including the creation and deletion of device files. Device files are usually placed in the /dev directory. After using udev, only the devices that actually exist in the system are included in the /dev directory.

The main udev configuration file is the /etc/udev/udev.conf file.

udev_root=”/dev/”

udev_rules=”/etc/udev/rules.d/”

udev_log=”err”

udev_root: represents where the device file is added.
udev_rules: represents the directory where udev rules are stored. This directory stores files ending in .rules. Each file handles a set of rules to help udev assign names to device files to be recognized by the kernel.

There may be several udev rule files under your /etc/udev/rules.d, some of these files are installed by the udev package, and the other part may be generated by other hardware or software packages. When there are multiple files in this directory, udev reads the files according to the ASCII alphabetical order of the file names. Once udev finds a rule that matches the newly added device, udev will check the new device according to the measures defined by the rule. The device is configured. At the same time, no subsequent rule files are read.
udev_log: represents the log level of udev, and uses syslog to record error messages.

image-20230731140220611

Linux Daemon (daemon process) is a special process running in the background. It is independent of the controlling terminal and periodically performs some task or waits for some event to occur. It runs without user input and provides a service, either to the system as a whole or to a user program. Most servers of the Linux system are implemented through daemon processes. Common daemon processes include the system log process syslogd, the web server httpd, the mail service sendmail, and the database server mysqld. Daemon names usually end in d (application layer daemon).

Basic features of the daemon:

  • The life cycle is long. Generally, the operating system starts when it is started and shuts down when it is closed;
  • The daemon process is not associated with the terminal, that is, they do not control the terminal, so when the terminal exits, it will not cause the daemon process to exit;
  • The daemon process runs in the background and does not occupy the terminal, and the terminal can execute other commands;
  • The parent process of a daemon process is the init process, because its real parent process exits before the parent process exits after fork out of the child process, so it is an orphan process inherited by init;

Daemon development method:

The first one uses the daemon function for development

int daemon(int nochdir, int noclose);
  • When nochdir is 0, the daemon will change the address of the process to root (“/”).

  • When noclose is 0, the daemon redirects STDIN, STDOUT, and STDERR of the process to /dev/null, that is, no information is output, otherwise it is output as usual. Normally, this parameter is set to 0.

  • Returns 0 on success, -1 on failure

The daemon is usually created in the root directory, because the root directory is a stable location, it exists when the system starts, and it will exist throughout the operation of the system. This ensures that the daemon is properly loaded and running when the system boots.

#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>

//C library function char *asctime(const struct tm *timeptr) returns a pointer to a string, which represents the date and time of the structure struct timeptr.
//The C library function struct tm *localtime(const time_t *timer) fills the tm structure with the value of timer. The value of timer is broken into a tm structure and represented in the local time zone.
/*
struct tm {
int tm_sec; seconds, range from 0 to 59
int tm_min; minute, range from 0 to 59
int tm_hour; hour, range from 0 to 23
int tm_mday; day of the month, range from 1 to 31
int tm_mon; month, range from 0 to 11
int tm_year; year since 1900
int tm_wday; day of the week, ranges from 0 to 6
int tm_yday; day of the year, ranges from 0 to 365
int tm_isdst; daylight saving time
};
*/
static bool flag = true;//The "bool" keyword indicates that the type of the variable is Boolean, and it can only have two values: "true" or "false".
void handler(int sig)
{
printf("I got a signal %d\
I'm quitting.\
", sig);
flag = false;
}
int main()
{
time_t t;
int fd;
//Create daemon process
if(-1 == daemon(0, 0))
{
printf("daemon error\
");
exit(1);
}
//Set signal handler function
struct sigaction act;
act.sa_handler = handler;
sigemptyset( &act.sa_mask);
act.sa_flags = 0;
if(sigaction(SIGQUIT, & act, NULL))
{
printf("sigaction error.\
");
exit(0);
}
//Process work content
while(flag)
{
fd = open("/home/orangepi/daemon.log", O_WRONLY | O_CREAT | O_APPEND,0644);
if(fd == -1){
printf("open error\
");
}
t = time(0);
char *buf = asctime(localtime( &t));
write(fd, buf, strlen(buf));
close(fd);
sleep(10);
}
return 0;
}

int sigemptyset(sigset_t *set);

  • Function description sigemptyset() is used to initialize and clear the parameter set signal set.

  • Return value Returns 0 if the execution is successful, and returns -1 if there is an error.

sigemptyset( & amp;act.sa_mask); & amp;act.sa_mask in this line of code is the sa_mask of the structure variable act The member takes the address and passes it to the sigemptyset function. This member is a signal mask that specifies which signals need to be blocked while the signal is being handled, or which signals need to be blocked during the execution of the signal handler. By calling the sigemptyset function, this mask can be initialized to an empty set, which means that no signal will be blocked.

You can also put the path of the executable program generated by this code (which can be displayed by pwd) into the /etc/rc.local file to realize self-starting at boot.

The second is to use the setsid function:

The role of the setsid() function

1. Let the process get rid of the control of the original session

2. Let the process get rid of the control of the original process group

3. Let the process get rid of the control of the original control terminal

Steps to create a daemon

Step 1: Create a parent process and let it launch

Step 2: Call the setsid() function

Step 3: Change the current directory to the root directory chdir (“/”)

Step 4: Reset the file permission mask umask(0);

Step 5: Close the file descriptor;

Daemon app:

Requirement: The program that requires the voice to swipe the phone is kept running to prevent the accidental crash of the application

Write a program to determine whether a process is running:

#include <stdio.h>
#include <string.h>

int main()
{
    FILE *fp;
    char buffer[128] = {'\0'};

    char *cmd = "ps -elf|grep douyinpro|grep -v grep";
    
    fp = popen(cmd,"r");
    fgets(buffer,128,fp);
    
    if(strstr(buffer,"douyin") != NULL){
    
        printf("douyinpro is running\
");
    }else{
        printf("douprinpro is not running\
");
    
    }
    printf("BUFFER:%s\
",buffer);
    return 0;

}

The daemon does not let the control program exit

#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 signum, siginfo_t *inf, void *context)
{
    printf("signum = %d\
",signum);
    flag = false;
}

int judge()
{
    FILE *fp;
    char buffer[128] = {'\0'};
    char *cmd = "ps -elf|grep douyinpro|grep -v grep";
    
    fp = popen(cmd,"r");
    fgets(buffer,128,fp);
    
    if(strstr(buffer,"douyinpro") != NULL){
        return 0;
    }else{
        return -1;
    }
    
    printf("BUFFER:%s\
",buffer);
    return 0;
}

int main()
{
    time_t t;
    int fd;
if(daemon(0,0) == -1){
   printf("daemon error\
");
    exit(-1);
}
struct sigaction act;
act.sa_flags = SA_SIGINFO;
sigemptyset( &act.sa_mask);
act.sa_sigaction = handler;

if(sigaction(SIGQUIT, &act,NULL) == -1){
   printf("creat sigaction error\
");
    exit(-1);
}
while(flag){

if(judge() == -1){
            system("/home/orangepi/hardwaresoft/douyin/douyinpro /dev/ttyS5 & amp;");
        }
        sleep(2);
    }
    return 0;
}

UDEV configuration file:

The rule file is the most important part in udev, and it is stored under /etc/udev/rule.d/ by default. All rule files must end with “.rules”. Here is a simple rule:

KERNEL==”sda”, NAME=”my_root_disk”, MODE=”0660″

KERNEL is the match key, and NAME and MODE are the assignment keys. The meaning of this rule is: if there is a device whose kernel name is sda, the condition will take effect, and the following assignment will be executed: create a device file named my_root_disk under /dev, and set the permission of the device file to 0660.

You can use the udevadm info –attribute-walk –name=/dev/device name (bus/usb/001/***) command to view the detailed information of the device;

Match keys for udev rules

ACTION: the behavior of the event (uevent), for example: add (add device), remove (delete device);
KERNEL: kernel device name, for example: sda, cdrom; //sad: hard disk
DEVPATH: the devpath path of the device;
SUBSYSTEM: The subsystem name of the device, for example: the system of sda is block;
BUS: the bus name of the device in devpath, for example: usb;
DRIVER: The device driver name of the device in devpath, for example: ide-cdrom;
ID: the identification number of the device in devpath;
SYSFS{filename}: under the devpath path of the device, the content in the property file “filename” of the device; ENV{key}: environment variable. In one rule, you can set up to five matching keys of environment variables;
PROGRAM: call external commands;
RESULT: The return result of the external command PROGRAM.

Automatically mount the U disk:

After inserting the U disk into the h616, you can’t see any data and messages in the U disk using dmesg. If you want to display the U disk data, you need to hang /dev/sda in the root directory of /mnt/

sudo mount /dev/sda /mnt/ //mount This command allows you to mount a storage device (such as a hard drive, partition, CD-ROM, etc.) to a specified directory, allowing you to access files on the device and directories. 

/mnt is a directory in a Linux system to mount additional file systems or devices. It is an agreed place to temporarily mount storage devices such as hard disk partitions, USB devices, CD/DVD drives, etc.

In Linux, the /mnt directory is usually an empty directory and can be mounted with the following command:

 $ sudo mount /dev/sdX /mnt

Among them, /dev/sdX is the path of the device to be mounted, which can be a hard disk partition (such as /dev/sda1) or a USB device (such as /dev/sdb1).

Once mounted, the contents of the device will be visible under the /mnt directory. You can read, write or execute files on the device by accessing the /mnt directory.

 sudo umount /mnt //delete mounted files
<strong>Create a rule file ending with .rules under the /etc/udev/rules.d file, and then put the following paragraph in the file:</strong>
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", RUN{program} + ="/bin/mkdi (use the mkdir command in the /bin directory) (a space is required here) /media /%k (udev variable, indicating the device name of the kernel, such as sda1)" ,RUN{program} + = "/usr/bin/systemd-mount --no-block (non-blocking mode) --collect (indicating mount Collect device information before) $devnode (represents the path of the device node) (a space is required here) /media/%k (mount path)"

Then use tree /media to check whether the mount is successful and display it in the form of a file tree. If the tree is not installed, you need to use sudo apt-get install tree to install it