Linux daemon, device manager udev

Linux hot plug UDE mechanism
Introduction

udev is a device management tool, udev runs as 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 in 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.


Example: When a mobile phone is plugged in, the kernel is the first to know it, but our application does not know it, so udev needs to create a file (everything in linux is a file), so that our application layer can access the hardware – mobile phone

Daemon
Linux Daemon (daemon process) is a special process running in the background, which is independent of the control terminal and periodically performs certain tasks or waits for certain events to be processed. 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 server sendmail, and the database server mysqld. Daemon names usually end in d

Basic features of the daemon

1. The life cycle is long [not necessary]. Generally, it starts when the operating system starts and shuts down when it is closed, but it does not mean that your process is a daemon process, the operating system knows it, and then starts it when the operating system starts. Artificial development engineers add scripts to the boot script to start the process when the system starts
2. The daemon process is not associated with the terminal, so when the controlling terminal exits, the daemon process will not exit
3. The daemon process is carried out in the background and will not occupy the terminal. The terminal can execute other commands
4. The parent process of a daemon process is the init process, because its real parent process exits before the child process exits after fork, so it is an orphan process inherited by init

You can view all processes by command ps -elf

Use ps -elf |grep udev to retrieve the process

Use ps -elf |grep udev |grep -v grep to skip the retrieval of the grep process

ppid = 0: The kernel process starts with the system startup, and its life cycle runs through the entire system.

The cmd column name with [] is called the kernel daemon process

The ancestor init: It is also a system daemon process, which is responsible for starting specific system services at each operating level; so the PPID of many processes is init, and it is also responsible for adopting orphan processes. Ordinary daemons with names without [] in the cmd column (user set daemons)


Make a daemon yourself

**Create Daemon Process API**

#include <unistd.h>

int daemon(int nochdir, int noclose);

Function role: create a daemon process
nochdir: assigning a value of 0 means changing the working directory of the daemon process to the "/" root directory
noclose: assigning a value of 0 means redirecting standard input, output, and error output to /dev/null
Return value: return 0 on success, return -1 on failure
**Time function API**
#include <time.h>


time_t time(time_t *seconds);
Function: Calculate the current calendar time and encode it into time_t format

seconds: If the parameter is not NULL, the return value is also stored in the parameter

Return value: return the current calendar time (time_t format)

struct tm *localtime(const time_t *timer);
Function: Convert the calendar time (time_t format) pointer to the tm structure pointer

timer: calendar time pointer in time_t format

Return value: tm structure pointer

struct tm {<!-- -->
   int tm_sec; /* seconds, range from 0 to 59 */
   int tm_min; /* minutes, 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, range from 0 to 6 */
   int tm_yday; /* day of the year, ranges from 0 to 365 */
   int tm_isdst; /* daylight saving time */
};


char *asctime(const tm *timeptr);

Function: Convert the tm structure pointer to a string (calendar that people can understand) pointer

timeptr: tm structure pointer

Return value: string pointer (calendar that people can understand)

timedaemon.c

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <signal.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
 
bool flags = true;
 
void handle(int signum, siginfo_t *infomation, void *context)
{<!-- -->
    printf("get signal %d, i am quit\\
", signum);
    flags = false;
}
 
int main()
{<!-- -->
    int fd;
    struct sigaction act;
    time_t t;
    char *buf;
 
    if(daemon(0,0) == -1){<!-- -->
        printf("daemon error!\\
");
        exit(-1);
    }
 
    act.sa_sigaction = handle;
    act.sa_flags = SA_SIGINFO;
    if(sigaction(SIGQUIT, &act,NULL) == -1){<!-- -->
        printf("sigaction error!\\
");
        exit(-2);
    }
 
    while(flags){<!-- -->
        if((fd = open("/home/orangepi/tdaemon.log",O_RDWR|O_CREAT|O_APPEND,0666)) == -1){<!-- -->
            printf("open error!\\
");
            exit(-3);
        }
 
        t = time(NULL);
        buf =asctime(localtime( &t));
 
        write(fd,buf,strlen(buf));
 
        close(fd);
 
        sleep(10);
    }
 
 
    return 0;
}

After compiling the .c file and running the program, it is found that the terminal will not be occupied by the program, and after executing the ps -elf |grep tdaemon command, it is found that the process is already running in the system. At this time, tdaemon is found in the /home/orangepi/ path The .log file has been created. Enter the file and find that the data is exactly what you want, which proves that the daemon process has run perfectly.


At this time, it is necessary to set the daemon process to start automatically after booting. First, obtain the path (including the file name) of the execution file of the daemon process, copy the path to the /etc/rc.local file, and then enter the file command sudo vi /etc/rc.local


Daemon application

Requirement: The program that requires the test to keep running to prevent the application from crashing accidentally
test.c
Here first make a demo program, execute it without exiting, and use it to test the program

#include <stdio.h>
#include <unistd.h>
 
int main()
{<!-- -->
    int i = 0;
    while(1){<!-- -->
        printf("%d\\
",i++);
 
        sleep(1);
    }
    return 0;
}

judge.c
Here the popen function is used to execute the ps command, and then the strstr() function is used to judge whether the process we want is running in the system through its return value and the name of the process to be detected

#include <stdio.h>
#include <string.h>
#include <unistd.h>
 
int main()
{<!-- -->
    while(1){<!-- -->
        char buf[128]={<!-- -->'\0'};
        FILE *file;
        file = popen("ps -elf |grep test |grep -v grep","r");
 
        fread(buf,1,128,file);
 
        if(strstr(buf,"test") != NULL){<!-- -->
            printf("process is existed!\\
");
        }else{<!-- -->
            printf("process is not existed!\\
");
        }
        printf("buf is %s\\
",*buf=='\0'?"NULL":buf);
        sleep(3);
    }
 
    return 0;
}

Combined with the previous knowledge, use the daemon process to detect the program to start the program when it is not executed
testpro.c
This demo is used to test whether the daemon can start the program when the program is executed

#include <stdio.h>
#include <unistd.h>
 
int main()
{<!-- -->
    int i = 0;
    while(1){<!-- -->
        printf("%d\\
",i++);
 
        sleep(1);
    }
    return 0;
}

testdaemon.c
The daemon keeps track of whether testpro is running. If it is not running, it will start testpro. If you want to start this daemon, you need to copy the program path to the **/etc/rc.local** file

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <signal.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
 
bool flags = true;
 
int judge()
{<!-- -->
        char buf[128]={<!-- -->'\0'};
        FILE *file;
        file = popen("ps -elf |grep testpro |grep -v grep","r");
 
        fread(buf,1,128,file);
 
        if(strstr(buf,"test") != NULL){<!-- -->
            return 1;
        }else{<!-- -->
            return 0;
        }
 
}
 
void handle(int signum, siginfo_t *infomation, void *context)
{<!-- -->
    printf("get signal %d, i am quit\\
", signum);
    flags = false;
}
 
int main()
{<!-- -->
    int fd;
    struct sigaction act;
    time_t t;
    char *buf;
 
    if(daemon(0,0) == -1){<!-- -->
        printf("daemon error!\\
");
        exit(-1);
    }
 
    act.sa_sigaction = handle;
    act.sa_flags = SA_SIGINFO;
    if(sigaction(SIGQUIT, &act,NULL) == -1){<!-- -->
        printf("sigaction error!\\
");
        exit(-2);
    }
 
    while(flags){<!-- -->
        if(judge() == 0){<!-- -->
            system("/home/orangepi/code/testpro &");
        }
        sleep(5);
    }
    return 0;
}