xref: /PHP-8.2/sapi/litespeed/lscriu.c (revision 8a221e27)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: George Wang <gwang@litespeedtech.com>                        |
14    +----------------------------------------------------------------------+
15 */
16 /*
17 Copyright (c) 2002-2018, Lite Speed Technologies Inc.
18 All rights reserved.
19 
20 Redistribution and use in source and binary forms, with or without
21 modification, are permitted provided that the following conditions are
22 met:
23 
24     * Redistributions of source code must retain the above copyright
25       notice, this list of conditions and the following disclaimer.
26     * Redistributions in binary form must reproduce the above
27       copyright notice, this list of conditions and the following
28       disclaimer in the documentation and/or other materials provided
29       with the distribution.
30     * Neither the name of the Lite Speed Technologies Inc nor the
31       names of its contributors may be used to endorse or promote
32       products derived from this software without specific prior
33       written permission.
34 
35 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 */
47 
48 #define HAVE_MSGHDR_MSG_CONTROL
49 #include "lsapilib.h"
50 
51 #include <stdio.h>
52 #include <stdlib.h>
53 
54 #if HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57 
58 #include <sys/wait.h>
59 
60 
61 #include <sys/stat.h>
62 
63 #if HAVE_SYS_TYPES_H
64 
65 #include <sys/types.h>
66 
67 #endif
68 
69 #include <sys/types.h>
70 #include <sys/socket.h>
71 #include <sys/un.h>
72 #include <arpa/inet.h>
73 #include <netinet/in.h>
74 #include <semaphore.h>
75 #include <sys/mman.h>
76 #include <fcntl.h>
77 #include <dlfcn.h>
78 #include <stdlib.h>
79 #include <errno.h>
80 #include <string.h>
81 #include <stdarg.h>
82 
83 #include <signal.h>
84 #include <time.h>
85 #include <sys/timeb.h>
86 #include <unistd.h>
87 #include "lscriu.h"
88 
89 #include <Zend/zend_portability.h>
90 
91 #define  LSCRIU_PATH    256
92 
93 // Begin CRIU inclusion
94 //CRIU inclusion
95 static int s_initial_start_reqs = 0;
96 static int s_requests_count = 0;
97 static int s_restored = 0;
98 static int (*s_lscapi_dump_me)(void) = NULL;
99 static int (*s_lscapi_prepare_me)(void) = NULL;
100 static int s_native = 0;
101 static int s_tried_checkpoint = 0;
102 static int s_criu_debug = 0;
103 static int s_fd_native = -1;
104 static char *s_criu_image_path = NULL;
105 static int s_pid = 0;
106 
107 typedef enum
108 {
109     CRIU_GCOUNTER_SHM,
110     CRIU_GCOUNTER_SIG,
111     CRIU_GCOUNTER_PIPE
112 } GlobalCounterType_t;
113 static GlobalCounterType_t s_global_counter_type = CRIU_GCOUNTER_SHM;
114 
115 #ifndef sighandler_t
116 typedef void (*sighandler_t)(int);
117 #endif
118 
119 void lsapi_perror( const char * pMessage, int err_no );
120 void LSAPI_reset_server_state( void );
121 int LSAPI_Get_ppid(void);
122 
123 #ifdef LSAPILIB_DEBUG_CRIU
124 #define lscriu_dbg(...) \
125     do { if (s_criu_debug) fprintf(stderr, __VA_ARGS__); } while(0)
126 #else
127 #define lscriu_dbg(...)
128 #endif
129 
130 #define lscriu_err(...) fprintf(stderr, __VA_ARGS__)
131 
132 
133 #define SUN_PATH_MAX   (sizeof(((struct sockaddr_un *)NULL)->sun_path))
134 
135 typedef struct
136 {
137     pid_t m_iPidToDump;
138     char  m_chImageDirectory[1024];
139     char  m_chSocketDir[SUN_PATH_MAX];
140     char  m_chServiceAddress[SUN_PATH_MAX];
141 } criu_native_dump_t;
142 
143 typedef sem_t * (*psem_open_t) (const char *__name, int __oflag, ...);
144 typedef int (*psem_post_t) (sem_t *__sem);
145 typedef int (*psem_close_t) (sem_t *__sem);
146 
147 psem_open_t psem_open = NULL;
148 psem_post_t psem_post = NULL;
149 psem_close_t psem_close = NULL;
150 
lsapi_criu_signal(int signo,sighandler_t handler)151 static void lsapi_criu_signal(int signo, sighandler_t handler)
152 {
153     struct sigaction sa;
154 
155     sigaction(signo, NULL, &sa);
156 
157     if (sa.sa_handler == SIG_DFL) {
158         sigemptyset(&sa.sa_mask);
159         sa.sa_flags = 0;
160         sa.sa_handler = handler;
161         sigaction(signo, &sa, NULL);
162     }
163 }
164 
165 
lsapi_siguser2(int sig)166 static void lsapi_siguser2(int sig)
167 {
168     // child requests counter for master process
169     ++s_requests_count;
170 }
171 
172 
LSCRIU_Set_Initial_Start_Reqs(int reqs)173 static void LSCRIU_Set_Initial_Start_Reqs(int reqs)
174 {
175     s_initial_start_reqs = reqs;
176 }
177 
178 
LSCRIU_Set_Global_Counter_Type(GlobalCounterType_t tp)179 static void LSCRIU_Set_Global_Counter_Type(GlobalCounterType_t tp)
180 {
181     if ((tp == CRIU_GCOUNTER_SHM) || (tp == CRIU_GCOUNTER_SIG)
182         || (tp == CRIU_GCOUNTER_PIPE)) {
183         s_global_counter_type = tp;
184     } else {
185         s_global_counter_type = CRIU_GCOUNTER_SHM;
186     }
187 
188 }
189 
190 
LSCRIU_Get_Global_Counter_Type(void)191 static int LSCRIU_Get_Global_Counter_Type(void)
192 {
193     return s_global_counter_type;
194 }
195 
196 
LSCRIU_Init_Global_Counter(int value)197 static int LSCRIU_Init_Global_Counter(int value)
198 {
199     if (LSCRIU_Get_Global_Counter_Type() != CRIU_GCOUNTER_SHM
200         || !s_initial_start_reqs) {
201         return 0;
202     }
203 
204     return 0;
205 }
206 
207 
LSCRIU_Increase_Global_Counter(void)208 static void LSCRIU_Increase_Global_Counter(void)
209 {
210     if (LSCRIU_Get_Global_Counter_Type() != CRIU_GCOUNTER_SHM
211         || !s_initial_start_reqs) {
212         return;
213     }
214 
215     s_requests_count = LSAPI_Inc_Req_Processed(1);
216 }
217 
218 
LSCRIU_Get_Global_Counter(void)219 static void LSCRIU_Get_Global_Counter(void)
220 {
221     if (!s_initial_start_reqs) {
222         return;
223     }
224     s_requests_count = LSAPI_Inc_Req_Processed(0);
225 
226 }
227 
228 
LSCRIU_need_checkpoint(void)229 static int LSCRIU_need_checkpoint(void)
230 {
231     if (!s_initial_start_reqs) {
232         return 0;
233     }
234 
235     if (LSCRIU_Get_Global_Counter_Type() == CRIU_GCOUNTER_SHM
236         && s_requests_count <= s_initial_start_reqs) {
237         LSCRIU_Get_Global_Counter();
238     }
239     if (s_initial_start_reqs > 0
240         && s_requests_count >= s_initial_start_reqs) {
241         return 1;
242     }
243 
244     return 0;
245 }
246 
247 
LSCRIU_load_liblscapi(void)248 static int LSCRIU_load_liblscapi(void)
249 {
250     void *lib_handle = NULL;
251     void *pthread_lib_handle = NULL;
252 
253     if (s_native)
254         return 0;
255     // Numerical signals indicates Apache
256     int error = 1;
257     char *last;
258 
259     if (!(lib_handle = DL_LOAD(last = "liblscapi.so")) /*||
260         !(pthread_lib_handle = DL_LOAD(last = "libpthread.so"))*/)
261         fprintf(stderr, "LSCRIU (%d): failed to dlopen %s: %s - ignore CRIU\n",
262                 s_pid, last, dlerror());
263     else if (!(s_lscapi_dump_me = dlsym(lib_handle, last = "lscapi_dump_me")) ||
264                 !(s_lscapi_prepare_me = dlsym(lib_handle, last = "lscapi_prepare_me")) ||
265                 !(psem_open = dlsym(pthread_lib_handle, last = "sem_open")) ||
266                 !(psem_post = dlsym(pthread_lib_handle, last = "sem_post")) ||
267                 !(psem_close = dlsym(pthread_lib_handle, last = "sem_close")))
268         fprintf(stderr, "LSCRIU (%d): failed to dlsym %s: %s - ignore CRIU\n",
269                 s_pid, last, dlerror());
270     else
271         error = 0;
272     if (error) {
273         // close the dll handles so we release the resources
274         if (lib_handle)
275             dlclose(lib_handle);
276         if (pthread_lib_handle)
277             dlclose(pthread_lib_handle);
278         return -1;
279     }
280     return 0;
281 }
282 
283 
LSCRIU_Wink_Server_is_Ready(void)284 static void LSCRIU_Wink_Server_is_Ready(void)
285 {
286     char sem_name[60];
287 
288     if (s_native) {
289         // Not used for native
290         return;
291     }
292     if (getenv("LSAPI_UNIQE"))
293         snprintf(sem_name, sizeof sem_name - 1, "lsphp[hash=%s].is_ready",
294                  getenv("LSAPI_UNIQE"));
295     else
296         snprintf(sem_name, sizeof sem_name - 1, "lsphp[euid=0x%x].is_ready",
297                  geteuid());
298 
299     sem_t *is_ready_sem = psem_open(sem_name, O_RDWR);
300     if (is_ready_sem) {
301         if (psem_post(is_ready_sem) < 0)
302             lsapi_perror(sem_name, errno);
303 
304         if (psem_close(is_ready_sem) < 0)
305             lsapi_perror(sem_name, errno);
306     }
307     else if (errno != ENOENT)
308         lsapi_perror(sem_name, errno);
309 }
310 
311 
LSCRIU_Error_File_Name(char * pchFile,int max_len)312 static char *LSCRIU_Error_File_Name(char *pchFile, int max_len)
313 {
314     const char *pchDefaultSocketPath = "/tmp/";
315     const char *pchDefaultLogFileName = "lsws_error.log";
316     snprintf(pchFile, max_len, "%s%s", pchDefaultSocketPath,
317              pchDefaultLogFileName);
318     return pchFile;
319 }
320 
321 
322 #ifdef LSAPILIB_DEBUG_CRIU
LSCRIU_Debugging(void)323 static void LSCRIU_Debugging(void) {
324     char *pchCRIUDebug;
325     pchCRIUDebug = getenv("LSAPI_CRIU_DEBUG");
326     if (!pchCRIUDebug)
327         pchCRIUDebug = getenv("LSCAPI_CRIU_DEBUG");
328     //fprintf(stderr,"(%d) LSCRIU: CRIU debug environment variable: %s\n",
329     //        s_pid, pchCRIUDebug);
330     // I've made it easy to turn on debugging.  CloudLinux Apache sets
331     // LSCAPI_CRIU_DEBUG to nothing to indicate it's on.  Sigh.
332     if ((!pchCRIUDebug) ||
333         ((!*pchCRIUDebug) ||
334          (*pchCRIUDebug == '0') ||
335          (*pchCRIUDebug == 'f') ||
336          (*pchCRIUDebug == 'F') ||
337          (((*pchCRIUDebug == 'O') ||
338             (*pchCRIUDebug == 'o')) &&
339            ((*(pchCRIUDebug + 1)) &&
340             ((*(pchCRIUDebug + 1) == 'F') || (*(pchCRIUDebug + 1) == 'f'))))))
341     {
342         lscriu_dbg("LSCRIU (%d): CRIU Debugging disabled by environment\n", s_pid);
343         s_criu_debug = 0;
344     }
345     else {
346         s_criu_debug = 1;
347         lscriu_dbg("LSCRIU (%d): CRIU Debugging enabled by environment\n", s_pid);
348         fprintf(stderr,"LSCRIU (%d): CRIU debug environment variable: %s\n",
349                 s_pid, pchCRIUDebug);
350     }
351 }
352 
353 
LSCRIU_Restored_Error(int iFatal,char * format,...)354 static void LSCRIU_Restored_Error(int iFatal, char *format, ...) {
355     // This routine deals with the awful situation of trying to get info while the stderr handle is closed on purpose.
356     int iOldUMask;
357     int iFd = -1;
358     char chFile[1024];
359 
360     if (!iFatal) {
361         // LSCRIU_Debugging();
362         if (!s_criu_debug) {
363             // Debugging message and debugging is off
364             return;
365         }
366     }
367     if (!LSCRIU_Error_File_Name(chFile, sizeof(chFile))) {
368         // We're done here...nowhere to write
369         return;
370     }
371     iOldUMask = umask(0);
372     iFd = open( chFile, O_WRONLY | O_APPEND | O_CREAT,
373                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
374     umask(iOldUMask);
375     if (iFd >= 0) {
376         char chFullMessage[0x1000];
377         struct timeb sTimeb;
378         struct tm    sTm;
379         ftime(&sTimeb);
380         localtime_r(&sTimeb.time,&sTm);
381         va_list ap;
382         va_start(ap, format);
383         char buf[0x1000];
384         vsnprintf(buf, sizeof(buf), format, ap);
385         va_end(ap);
386 
387         int n = snprintf(chFullMessage, sizeof(chFullMessage),
388                 "%04d-%02d-%02d %02d:%02d:%02d.%03d: LSCRIU (%d): %s %s\n",
389                 sTm.tm_year + 1900,
390                 sTm.tm_mon + 1,
391                 sTm.tm_mday,
392                 sTm.tm_hour,
393                 sTm.tm_min,
394                 sTm.tm_sec,
395                 sTimeb.millitm,
396                 s_pid,
397                 iFatal ? "FATAL! " : "(debug) ",
398                 buf);
399         if (n > (int)sizeof(chFullMessage))
400             n = sizeof(chFullMessage);
401         write(iFd, chFullMessage, n);
402         close(iFd);
403     }
404 }
405 #else // no debugging
LSCRIU_Debugging(void)406 static inline void LSCRIU_Debugging(void) {}
LSCRIU_Restored_Error(int iFatal,char * format,...)407 static inline void LSCRIU_Restored_Error(int iFatal, char *format, ...) {}
408 #endif
409 
410 
LSCRIU_Native_Dump(pid_t iPid,char * pchImagePath,int iFdNative)411 static int LSCRIU_Native_Dump(pid_t iPid,
412                               char  *pchImagePath,
413                               int   iFdNative) {
414     criu_native_dump_t criu_native_dump;
415     char *pchLastSlash;
416 
417     memset(&criu_native_dump, 0, sizeof(criu_native_dump));
418     criu_native_dump.m_iPidToDump = iPid;
419     strncpy(criu_native_dump.m_chImageDirectory, pchImagePath,
420             sizeof(criu_native_dump.m_chImageDirectory));
421     pchLastSlash = strrchr(criu_native_dump.m_chSocketDir,'/');
422     if (pchLastSlash) {
423         pchLastSlash++;
424         (*pchLastSlash) = 0;
425     }
426     lscriu_dbg("LSCRIU (%d): Sent the dump request to the listener\n", s_pid);
427     if (write(iFdNative,
428               &criu_native_dump,
429               sizeof(criu_native_dump)) == -1) {
430         lscriu_err("LSCRIU (%d): Error sending dump request to the listener: %s\n",
431                    s_pid, strerror(errno));
432         return(-1);
433     }
434     return 0;
435 }
436 
437 
LSCRIU_CloudLinux_Checkpoint(void)438 static void LSCRIU_CloudLinux_Checkpoint(void)
439 {
440     int iRet;
441 
442     if ((!s_native) && (!s_lscapi_dump_me)) {
443         lscriu_dbg("LSCRIU (%d): Not native and unable to dump - abandon one-time "
444                    "dump\n", s_pid);
445         return;
446     }
447 
448     iRet = s_lscapi_dump_me();
449     if (iRet < 0) {
450         lscriu_err("LSCRIU: CloudLinux dump of PID: %d, error: %s\n",
451                    s_pid, strerror(errno));
452     }
453     if (iRet == 0) {
454         // Dumped.  To continue the child must send us the handles back
455         lscriu_err("LSCRIU: Successful CloudLinux dump of PID: %d\n", s_pid);
456     }
457     else {
458         s_restored = 1;
459         LSAPI_reset_server_state();
460         /*
461          Here we have restored the php process, so we should to tell (via
462          semaphore) mod_lsapi that we are started and ready to receive data.
463         */
464         LSCRIU_Wink_Server_is_Ready();
465         lscriu_err("LSCRIU: Successful CloudLinux restore of PID: %d, parent: %d.\n",
466                    getpid(), getppid());
467     }
468     LSCRIU_Set_Initial_Start_Reqs(0);
469 }
470 
471 
LSCRIU_Wait_Dump_Finish_Or_Restored(int pid_parent)472 static void LSCRIU_Wait_Dump_Finish_Or_Restored(int pid_parent)
473 {
474     // Now get restored.  We know if we're restored if the ppid changes!
475     // If we're dumped, we're killed (no use worrying about that!).
476     time_t  iTimeStart = 0;
477     time_t  iTimeNow;
478     int     iRestored = 0;
479     do {
480         usleep(1000);
481         time(&iTimeNow);
482         if (!iTimeStart) {
483             iTimeStart = iTimeNow;
484         }
485         else if ((pid_parent != getppid()) ||
486                     (iTimeNow - iTimeStart > 10)) {
487             iRestored = 1;
488         }
489         else if (iTimeNow - iTimeStart > 5) {
490             LSCRIU_Restored_Error(1, "Timed out waiting to be dumped");
491             exit(1);
492         }
493     } while (!iRestored);
494 }
495 
496 
LSCRIU_try_checkpoint(int * forked_pid)497 static void LSCRIU_try_checkpoint(int *forked_pid)
498 {
499     int iRet;
500     pid_t iPid;
501     pid_t iPidDump = getpid();
502 
503     if (s_tried_checkpoint) {
504         lscriu_dbg("LSCRIU (%d): Already tried checkpoint - one time per customer\n",
505                    iPidDump);
506         return;
507     }
508     lscriu_dbg("LSCRIU (%d): Trying checkpoint\n", iPidDump);
509     s_tried_checkpoint = 1;
510     if (!s_native) {
511         LSCRIU_CloudLinux_Checkpoint();
512         return;
513     }
514 
515     lscriu_dbg("LSCRIU (%d): fork!\n", iPidDump);
516     iPid = fork();
517     if (iPid < 0) {
518         lscriu_err("LSCRIU (%d): Can't checkpoint due to a fork error: %s\n",
519                    iPidDump, strerror(errno));
520         return;
521     }
522     if (iPid == 0) {
523         pid_t   iPidParent = getppid();
524 
525         setsid();
526         iRet = LSCRIU_Native_Dump(iPidDump,
527                                   s_criu_image_path,
528                                   s_fd_native);
529         close(s_fd_native);
530 
531         LSCRIU_Wait_Dump_Finish_Or_Restored(iPidParent);
532         LSCRIU_Restored_Error(0, "Restored!");
533         LSAPI_reset_server_state();
534         s_restored = 1;
535     }
536     else {
537         if (forked_pid)
538             *forked_pid = iPid;
539     }
540     LSCRIU_Set_Initial_Start_Reqs(0);
541 }
542 
543 
init_native_env(void)544 static int init_native_env(void)
545 {
546     char *pchFd;
547     pchFd = getenv("LSAPI_CRIU_SYNC_FD");
548     if (!pchFd)
549         pchFd = getenv("LSCAPI_CRIU_SYNC_FD");
550 
551     const char *image_path;
552     image_path = getenv("LSAPI_CRIU_IMAGE_PATH");
553     if (!pchFd) {
554         lscriu_err("LSCRIU (%d): LSAPI_CRIU_SYNC_FD internal environment "
555                    "variable not set - contact Litespeed tech support\n", getpid());
556         return -1;
557     }
558     if (!image_path) {
559         lscriu_err("LSCRIU (%d): LSAPI_CRIU_IMAGE_PATH internal environment "
560                    "variable not set - contact Litespeed tech support\n", getpid());
561         return -1;
562     }
563     lscriu_dbg("LSCRIU (%d): Checkpoint dump.  ImagePath: %s\n",
564                getpid(), image_path);
565 
566     s_fd_native = atoi(pchFd);
567     lscriu_dbg("LSCRIU (%d): Native checkpoint.  Use filepointer %d (%s) to send "
568                "pid %d\n", getpid(), s_fd_native, pchFd, iPidDump);
569     s_criu_image_path  = strdup(image_path);
570     return 0;
571 }
572 
LSCRIU_Init_Env_Parameters(void)573 static int LSCRIU_Init_Env_Parameters(void)
574 {
575     const char *p;
576     int n;
577 
578     p = getenv("LSAPI_INITIAL_START");
579     if (!p)
580         p = getenv("LSAPI_BACKEND_INITIAL_START");
581     if (p) {
582         n = atoi(p);
583 
584         if (n > 0) {
585             lscriu_dbg("LSCRIU (%d): Set start requests based on environment (%d)\n",
586                        getpid(), n);
587             LSCRIU_Set_Initial_Start_Reqs(n);
588         } else {
589             lscriu_dbg("LSCRIU (%d): LSAPI_INITIAL_START set to 0 disabled\n",
590                        getpid());
591             return 0;
592         }
593     } else {
594         lscriu_dbg("LSCRIU (%d): LSAPI_INITIAL_START NOT set - disabled\n",
595                    getpid());
596         return 0;
597     }
598     if (LSAPI_Is_Listen()) {
599         lscriu_dbg("LSCRIU (%d): Listening...\n", getpid());
600         GlobalCounterType_t gc_type = CRIU_GCOUNTER_SHM;
601         char *env;
602         if ((env = getenv("LSAPI_CRIU_USE_SHM"))) {
603             // CloudLinux doc: Off (shared memory) or Signals.
604             // Litespeed doc: On (shared memory) or Signals
605             // So just check the first character for an 'S' and if not, then
606             // use shared memory.  Pipe support is lost (sigh).
607             if ((*env == 'S') || (*env == 's'))
608                 gc_type = CRIU_GCOUNTER_SIG; // Just assume the rest is signals
609             // else use the default of shared memory
610         }
611         else if ((env = getenv("LSAPI_SIGNALS"))) {
612             if ((*env == '1') ||
613                 (*env == 'Y') ||
614                 (*env == 'y') ||
615                 (*env == 'T') ||
616                 (*env == 't') ||
617                 (((*env == 'O') || (*env == 'o')) &&
618                  ((*(env + 1) == 'N') || (*(env + 1) == 'n'))))
619                 gc_type = CRIU_GCOUNTER_SIG;
620             else if (*env == 2)
621                 gc_type = CRIU_GCOUNTER_PIPE; // The only case for pipe
622             //else use the default of shared memory
623         }
624         if (gc_type != CRIU_GCOUNTER_SHM) {
625             lscriu_dbg("LSCRIU (%d): Use %s\n", getpid(),
626                        gc_type == CRIU_GCOUNTER_SIG ? "signals" : "pipe");
627             lsapi_criu_signal(SIGUSR2, lsapi_siguser2);
628         }
629         else {
630             lscriu_dbg("LSCRIU (%d): Use shared memory\n", getpid());
631 	}
632     	LSCRIU_Set_Global_Counter_Type(gc_type);
633     }
634     else {
635         lscriu_dbg("LSCRIU (%d): NOT Listening\n", getpid());
636     }
637 
638     char *criu_mode = NULL;
639     criu_mode = getenv("LSAPI_CRIU");
640     // 0 disabled
641     // 1 cloudlinux
642     // 2 native
643     if (criu_mode) {
644         if (*criu_mode == '0') {
645              lscriu_dbg("LSCRIU (%d): Disabled by environment.\n", getpid());
646              LSCRIU_Set_Initial_Start_Reqs(0);
647         }
648         else if (*criu_mode == '2') {
649             lscriu_dbg("LSCRIU (%d): Disabled by environment.\n", getpid());
650             s_native = 1;
651         }
652     }
653 
654     if (s_native && init_native_env() == -1)
655         LSCRIU_Set_Initial_Start_Reqs(0);
656 
657     //unset_lsapi_envs();
658     return 0;
659 }
660 
661 
LSCRIU_inc_req_processed()662 void LSCRIU_inc_req_processed()
663 {
664     if (!LSCRIU_Get_Global_Counter_Type()) {
665         ++s_requests_count;
666     }
667 
668     lscriu_dbg("LSCRIU (%d): s_requests_count %d counter %d\n", getpid(),
669                s_requests_count, s_initial_start_reqs);
670 
671     if (s_initial_start_reqs > 0 && s_requests_count <= s_initial_start_reqs) {
672         if (LSCRIU_Get_Global_Counter_Type() == CRIU_GCOUNTER_SHM) {
673             LSCRIU_Increase_Global_Counter();
674             if (s_requests_count >= s_initial_start_reqs) {
675                 //Maybe this time we can stop to send signal and wait for
676                 //1 second of select timeout
677                 //kill( LSCRIU_Get_ppid(), SIGUSR2 );
678                 lscriu_dbg("LSCRIU (%d): Time to dump main process with semaphore\n",
679                            getpid());
680             }
681         } else {
682             kill(LSAPI_Get_ppid(), SIGUSR2);
683             lscriu_dbg("LSCRIU (%d): Send kill to main process with signals\n",
684                        getpid());
685         }
686     }
687 }
688 
689 
LSCRIU_on_timer(int * forked_pid)690 static void LSCRIU_on_timer(int *forked_pid)
691 {
692     lscriu_dbg("LSCRIU (%d): LSCRIU_on_timer\n", getpid());
693     if (LSCRIU_need_checkpoint()) {
694         LSCRIU_try_checkpoint(forked_pid);
695     }
696 }
697 
698 
LSCRIU_Init(void)699 int LSCRIU_Init(void)
700 {
701     s_pid = getpid();
702     LSCRIU_Debugging();
703     LSCRIU_Init_Env_Parameters();
704     if (s_initial_start_reqs && !s_native) {
705         if (LSCRIU_load_liblscapi() == -1)
706             s_initial_start_reqs = 0;
707     }
708     if (s_initial_start_reqs) {
709         LSCRIU_Wink_Server_is_Ready();
710         lscriu_dbg("LSCRIU (%d): LSAPI_Register_Pgrp_Timer_Callback\n", s_pid);
711         LSAPI_Register_Pgrp_Timer_Callback(LSCRIU_on_timer);
712         LSCRIU_Init_Global_Counter(0);
713     }
714     return s_initial_start_reqs > 0;
715 }
716