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