RaspberrPi project source code
guowenxue
2023-09-07 13d8a8696ac5b5b505be20f428fe64e22a134016
commit | author | age
13d8a8 1 /*********************************************************************************
G 2  *      Copyright:  (C) 2020 LingYun IoT System Studio
3  *                  All rights reserved.
4  *
5  *       Filename:  proc.c
6  *    Description:  This file is the process API
7  *
8  *        Version:  1.0.0(7/06/2020)
9  *         Author:  Guo Wenxue <guowenxue@gmail.com>
10  *      ChangeLog:  1, Release initial version on "7/06/2020 09:19:02 PM"
11  *
12  ********************************************************************************/
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <libgen.h>
21 #include <pthread.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24
25 #include "proc.h"
26 #include "logger.h"
27
28 proc_signal_t     g_signal={0};
29
30 void proc_default_sighandler(int sig)
31 {
32     switch(sig)
33     {
34         case SIGINT:
35             log_warn("SIGINT - stopping\n");
36             g_signal.stop = 1;
37             break;
38
39         case SIGTERM:
40             log_warn("SIGTERM - stopping\n");
41             g_signal.stop = 1;
42             break;
43
44         case SIGSEGV:
45             log_warn("SIGSEGV - stopping\n");
46 #if 0
47             if(g_signal.stop)
48                 exit(0);
49
50             g_signal.stop = 1;
51 #endif
52             break;
53
54         case SIGPIPE:
55             log_warn("SIGPIPE - warnning\n");
56             break;
57
58         default:
59             break;
60     }
61 }
62
63
64 /* install default signal process functions  */
65 void install_default_signal(void)
66 {
67     struct sigaction sigact, sigign;
68
69     log_info("Install default signal handler.\n");
70
71     /*  Initialize the catch signal structure. */
72     sigemptyset(&sigact.sa_mask);
73     sigact.sa_flags = 0;
74     sigact.sa_handler = proc_default_sighandler;
75
76     /*  Setup the ignore signal. */
77     sigemptyset(&sigign.sa_mask);
78     sigign.sa_flags = 0;
79     sigign.sa_handler = SIG_IGN;
80
81     sigaction(SIGTERM, &sigact, 0); /*  catch terminate signal "kill" command */
82     sigaction(SIGINT,  &sigact, 0); /*  catch interrupt signal CTRL+C */
83     //sigaction(SIGSEGV, &sigact, 0); /*  catch segmentation faults  */
84     sigaction(SIGPIPE, &sigact, 0); /*  catch broken pipe */
85 #if 0
86     sigaction(SIGCHLD, &sigact, 0); /*  catch child process return */
87     sigaction(SIGUSR2, &sigact, 0); /*  catch USER signal */
88 #endif
89 }
90
91
92 /* ****************************************************************************
93  * FunctionName: daemonize
94  * Description : Set the programe runs as daemon in background
95  * Inputs      : nodir: DON'T change the work directory to / :  1:NoChange 0:Change
96  *               noclose: close the opened file descrtipion or not 1:Noclose 0:Close
97  * Output      : NONE
98  * Return      : NONE
99  * *****************************************************************************/
100 void daemonize(int nochdir, int noclose)
101 {
102     int rv, fd;
103     int i;
104
105     /*  already a daemon */
106     if (1 == getppid())
107         return;
108
109     /*  fork error */
110     rv = fork();
111     if (rv < 0) exit(1);
112
113     /*  parent process exit */
114     if (rv > 0)
115         exit(0);
116
117     /*  obtain a new process session group */
118     setsid();
119
120     if (!noclose)
121     {
122         /*  close all descriptors */
123         for (i = getdtablesize(); i >= 0; --i)
124         {
125             //if (i != g_logPtr->fd)
126                 close(i);
127         }
128
129         /*  Redirect Standard input [0] to /dev/null */
130         fd = open("/dev/null", O_RDWR);
131
132         /* Redirect Standard output [1] to /dev/null */
133         dup(fd);
134
135         /* Redirect Standard error [2] to /dev/null */
136         dup(fd);
137     }
138
139     umask(0);
140
141     if (!nochdir)
142         chdir("/");
143
144     return;
145 }
146
147 /* ****************************************************************************
148  * FunctionName: check_set_program_running
149  * Description : check program already running or not, if not then run it and
150  *               record pid into $pidfile
151  * Inputs      : daemon:  set program running in daemon or not
152  *               pid_file:The record PID file path
153  * Output      : NONE
154  * Return      : 0: Record successfully  Else: Failure
155  * *****************************************************************************/
156
157 int check_set_program_running(int daemon, char *pidfile)
158 {
159     if( !pidfile )
160         return 0;
161
162     if( check_daemon_running(pidfile) )
163     {
164         log_error("Program already running, process exit now");
165         return -1;
166     }
167
168     if( daemon )
169     {
170         if( set_daemon_running(pidfile) < 0 )
171         {
172             log_error("set program running as daemon failure\n");
173             return -2;
174         }
175     }
176     else
177     {
178         if( record_daemon_pid(pidfile) < 0 )
179         {
180             log_error("record program running PID failure\n");
181             return -3;
182         }
183     }
184
185     return 0;
186 }
187
188
189
190 /* ****************************************************************************
191  * FunctionName: record_daemon_pid
192  * Description : Record the running daemon program PID to the file "pid_file"
193  * Inputs      : pid_file:The record PID file path
194  * Output      : NONE
195  * Return      : 0: Record successfully  Else: Failure
196  * *****************************************************************************/
197 int record_daemon_pid(const char *pid_file)
198 {
199     struct stat fStatBuf;
200     int fd = -1;
201     int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
202     char ipc_dir[64] = { 0 };
203
204     strncpy(ipc_dir, pid_file, 64);
205
206     /* dirname() will modify ipc_dir and save the result */
207     dirname(ipc_dir);
208
209     /* If folder pid_file PATH doesnot exist, then we will create it" */
210     if (stat(ipc_dir, &fStatBuf) < 0)
211     {
212         if (mkdir(ipc_dir, mode) < 0)
213         {
214             log_error("cannot create %s: %s\n", ipc_dir, strerror(errno));
215             return -1;
216         }
217
218         (void)chmod(ipc_dir, mode);
219     }
220
221     /*  Create the process running PID file */
222     mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
223     if ((fd = open(pid_file, O_RDWR | O_CREAT | O_TRUNC, mode)) >= 0)
224     {
225         char pid[PID_ASCII_SIZE];
226         snprintf(pid, sizeof(pid), "%u\n", (unsigned)getpid());
227         write(fd, pid, strlen(pid));
228         close(fd);
229
230         log_debug("Record PID<%u> to file %s.\n", getpid(), pid_file);
231     }
232     else
233     {
234         log_error("cannot create %s: %s\n", pid_file, strerror(errno));
235         return -1;
236     }
237
238     return 0;
239 }
240
241 /* ****************************************************************************
242  * FunctionName: get_daemon_pid
243  * Description : Get the daemon process PID from the PID record file "pid_file"
244  * Inputs      : pid_file: the PID record file
245  * Output      : NONE
246  * Return      : pid_t: The daemon process PID number
247  * *****************************************************************************/
248 pid_t get_daemon_pid(const char *pid_file)
249 {
250     FILE *f;
251     pid_t pid;
252
253     if ((f = fopen(pid_file, "rb")) != NULL)
254     {
255         char pid_ascii[PID_ASCII_SIZE];
256         (void)fgets(pid_ascii, PID_ASCII_SIZE, f);
257         (void)fclose(f);
258         pid = atoi(pid_ascii);
259     }
260     else
261     {
262         log_error("Can't open PID record file %s: %s\n", pid_file, strerror(errno));
263         return -1;
264     }
265     return pid;
266 }
267
268 /* ****************************************************************************
269  * FunctionName: check_daemon_running
270  * Description : Check the daemon program already running or not
271  * Inputs      : pid_file: The record running daemon program PID
272  * Output      : NONE
273  * Return      : 1: The daemon program alread running   0: Not running
274  * *****************************************************************************/
275 int check_daemon_running(const char *pid_file)
276 {
277     int rv = -1;
278     struct stat fStatBuf;
279
280     rv = stat(pid_file, &fStatBuf);
281     if (0 == rv)
282     {
283         pid_t pid = -1;
284         printf("PID record file \"%s\" exist.\n", pid_file);
285
286         pid = get_daemon_pid(pid_file);
287         if (pid > 0)  /*  Process pid exist */
288         {
289             if ((rv = kill(pid, 0)) == 0)
290             {
291                 printf("Program with PID[%d] seems running.\n", pid);
292                 return 1;
293             }
294             else   /* Send signal to the old process get no reply. */
295             {
296                 printf("Program with PID[%d] seems exit.\n", pid);
297                 remove(pid_file);
298                 return 0;
299             }
300         }
301         else if (0 == pid)
302         {
303             printf("Can not read program PID form record file.\n");
304             remove(pid_file);
305             return 0;
306         }
307         else  /* Read pid from file "pid_file" failure */
308         {
309             printf("Read record file \"%s\" failure, maybe program still running.\n", pid_file);
310             return 1;
311         }
312     }
313
314     return 0;
315 }
316
317 /* ****************************************************************************
318  * FunctionName: stop_daemon_running
319  * Description : Stop the daemon program running
320  * Inputs      : pid_file: The record running daemon program PID
321  * Output      : NONE
322  * Return      : 1: The daemon program alread running   0: Not running
323  * *****************************************************************************/
324 int stop_daemon_running(const char *pid_file)
325 {
326     pid_t            pid = -1;
327     struct stat      fStatBuf;
328
329     if ( stat(pid_file, &fStatBuf) < 0)
330         return 0;
331
332     printf("PID record file \"%s\" exist.\n", pid_file);
333     pid = get_daemon_pid(pid_file);
334     if (pid > 0)  /*  Process pid exist */
335     {
336         while ( (kill(pid, 0) ) == 0)
337         {
338             kill(pid, SIGTERM);
339             sleep(1);
340         }
341
342         remove(pid_file);
343     }
344
345     return 0;
346 }
347
348
349
350 /* ****************************************************************************
351  * FunctionName: set_daemon_running
352  * Description : Set the programe running as daemon if it's not running and record
353  *               its PID to the pid_file.
354  * Inputs      : pid_file: The record running daemon program PID
355  * Output      : NONE
356  * Return      : 0: Successfully. 1: Failure
357  * *****************************************************************************/
358 int set_daemon_running(const char *pid_file)
359 {
360     daemonize(0, 1);
361     log_info("Program running as daemon [PID:%d].\n", getpid());
362
363     if (record_daemon_pid(pid_file) < 0)
364     {
365         log_error("Record PID to file \"%s\" failure.\n", pid_file);
366         return -2;
367     }
368
369     return 0;
370 }
371
372 /* start a new thread to run $thread_workbody point function  */
373 int thread_start(pthread_t *thread_id, thread_body_t thread_workbody, void *thread_arg)
374 {
375     int                rv = 0;
376     pthread_t          tid;
377
378     pthread_attr_t     thread_attr;
379
380     /* Initialize the thread  attribute */
381     rv = pthread_attr_init(&thread_attr);
382     if(rv)
383         return -1;
384
385     /* Set the stack size of the thread */
386     rv = pthread_attr_setstacksize(&thread_attr, 120 * 1024);
387     if(rv)
388         goto CleanUp;
389
390     /* Set thread to detached state:Don`t need pthread_join */
391     rv = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
392     if(rv)
393         goto CleanUp;
394
395     /* Create the thread */
396     rv = pthread_create(&tid, &thread_attr, thread_workbody, thread_arg);
397     if(rv)
398         goto CleanUp;
399
400 CleanUp:
401
402
403     if( thread_id )
404     {
405         if( rv )
406             *thread_id = 0;
407         else
408             *thread_id = tid;
409     }
410
411     /* Destroy the  attributes  of  thread */
412     pthread_attr_destroy(&thread_attr);
413     return rv;
414 }
415
416
417 /* excute a linux command by system() */
418 void exec_system_cmd(const char *format, ...)
419 {
420     char                cmd[256];
421     va_list             args;
422
423     memset(cmd, 0, sizeof(cmd));
424
425     va_start(args, format);
426     vsnprintf(cmd, sizeof(cmd), format, args);
427     va_end(args);
428
429     system(cmd);
430 }
431
432