xref: /php-src/sapi/litespeed/lscriu.c (revision 84a0da15)
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 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57 
58 #include <sys/wait.h>
59 
60 
61 #include <sys/stat.h>
62 
63 #ifdef HAVE_SYS_TYPES_H
64 #include <sys/types.h>
65 #endif
66 
67 #include <sys/types.h>
68 #include <sys/socket.h>
69 #include <sys/un.h>
70 #include <arpa/inet.h>
71 #include <netinet/in.h>
72 #include <semaphore.h>
73 #include <sys/mman.h>
74 #include <fcntl.h>
75 #include <dlfcn.h>
76 #include <stdlib.h>
77 #include <errno.h>
78 #include <string.h>
79 #include <stdarg.h>
80 
81 #include <signal.h>
82 #include <time.h>
83 #include <sys/timeb.h>
84 #include <unistd.h>
85 #include "lscriu.h"
86 
87 #include <Zend/zend_portability.h>
88 
89 #define  LSCRIU_PATH    256
90 
91 // Begin CRIU inclusion
92 //CRIU inclusion
93 static int s_initial_start_reqs = 0;
94 static int s_requests_count = 0;
95 static int s_restored = 0;
96 static int (*s_lscapi_dump_me)(void) = NULL;
97 static int (*s_lscapi_prepare_me)(void) = NULL;
98 static int s_native = 0;
99 static int s_tried_checkpoint = 0;
100 #ifdef LSAPILIB_DEBUG_CRIU
101 static int s_criu_debug = 0;
102 #endif
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 
312 #ifdef LSAPILIB_DEBUG_CRIU
LSCRIU_Error_File_Name(char * pchFile,int max_len)313 static char *LSCRIU_Error_File_Name(char *pchFile, int max_len)
314 {
315     const char *pchDefaultSocketPath = "/tmp/";
316     const char *pchDefaultLogFileName = "lsws_error.log";
317     snprintf(pchFile, max_len, "%s%s", pchDefaultSocketPath,
318              pchDefaultLogFileName);
319     return pchFile;
320 }
321 
322 
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     pid_t iPid;
500     pid_t iPidDump = getpid();
501 
502     if (s_tried_checkpoint) {
503         lscriu_dbg("LSCRIU (%d): Already tried checkpoint - one time per customer\n",
504                    iPidDump);
505         return;
506     }
507     lscriu_dbg("LSCRIU (%d): Trying checkpoint\n", iPidDump);
508     s_tried_checkpoint = 1;
509     if (!s_native) {
510         LSCRIU_CloudLinux_Checkpoint();
511         return;
512     }
513 
514     lscriu_dbg("LSCRIU (%d): fork!\n", iPidDump);
515     iPid = fork();
516     if (iPid < 0) {
517         lscriu_err("LSCRIU (%d): Can't checkpoint due to a fork error: %s\n",
518                    iPidDump, strerror(errno));
519         return;
520     }
521     if (iPid == 0) {
522         pid_t   iPidParent = getppid();
523 
524         setsid();
525         (void)LSCRIU_Native_Dump(iPidDump,
526                                   s_criu_image_path,
527                                   s_fd_native);
528         close(s_fd_native);
529 
530         LSCRIU_Wait_Dump_Finish_Or_Restored(iPidParent);
531         LSCRIU_Restored_Error(0, "Restored!");
532         LSAPI_reset_server_state();
533         s_restored = 1;
534     }
535     else {
536         if (forked_pid)
537             *forked_pid = iPid;
538     }
539     LSCRIU_Set_Initial_Start_Reqs(0);
540 }
541 
542 
init_native_env(void)543 static int init_native_env(void)
544 {
545     char *pchFd;
546     pchFd = getenv("LSAPI_CRIU_SYNC_FD");
547     if (!pchFd)
548         pchFd = getenv("LSCAPI_CRIU_SYNC_FD");
549 
550     const char *image_path;
551     image_path = getenv("LSAPI_CRIU_IMAGE_PATH");
552     if (!pchFd) {
553         lscriu_err("LSCRIU (%d): LSAPI_CRIU_SYNC_FD internal environment "
554                    "variable not set - contact Litespeed tech support\n", getpid());
555         return -1;
556     }
557     if (!image_path) {
558         lscriu_err("LSCRIU (%d): LSAPI_CRIU_IMAGE_PATH internal environment "
559                    "variable not set - contact Litespeed tech support\n", getpid());
560         return -1;
561     }
562     lscriu_dbg("LSCRIU (%d): Checkpoint dump.  ImagePath: %s\n",
563                getpid(), image_path);
564 
565     s_fd_native = atoi(pchFd);
566     lscriu_dbg("LSCRIU (%d): Native checkpoint.  Use filepointer %d (%s) to send "
567                "pid %d\n", getpid(), s_fd_native, pchFd, iPidDump);
568     s_criu_image_path  = strdup(image_path);
569     return 0;
570 }
571 
LSCRIU_Init_Env_Parameters(void)572 static int LSCRIU_Init_Env_Parameters(void)
573 {
574     const char *p;
575     int n;
576 
577     p = getenv("LSAPI_INITIAL_START");
578     if (!p)
579         p = getenv("LSAPI_BACKEND_INITIAL_START");
580     if (p) {
581         n = atoi(p);
582 
583         if (n > 0) {
584             lscriu_dbg("LSCRIU (%d): Set start requests based on environment (%d)\n",
585                        getpid(), n);
586             LSCRIU_Set_Initial_Start_Reqs(n);
587         } else {
588             lscriu_dbg("LSCRIU (%d): LSAPI_INITIAL_START set to 0 disabled\n",
589                        getpid());
590             return 0;
591         }
592     } else {
593         lscriu_dbg("LSCRIU (%d): LSAPI_INITIAL_START NOT set - disabled\n",
594                    getpid());
595         return 0;
596     }
597     if (LSAPI_Is_Listen()) {
598         lscriu_dbg("LSCRIU (%d): Listening...\n", getpid());
599         GlobalCounterType_t gc_type = CRIU_GCOUNTER_SHM;
600         char *env;
601         if ((env = getenv("LSAPI_CRIU_USE_SHM"))) {
602             // CloudLinux doc: Off (shared memory) or Signals.
603             // Litespeed doc: On (shared memory) or Signals
604             // So just check the first character for an 'S' and if not, then
605             // use shared memory.  Pipe support is lost (sigh).
606             if ((*env == 'S') || (*env == 's'))
607                 gc_type = CRIU_GCOUNTER_SIG; // Just assume the rest is signals
608             // else use the default of shared memory
609         }
610         else if ((env = getenv("LSAPI_SIGNALS"))) {
611             if ((*env == '1') ||
612                 (*env == 'Y') ||
613                 (*env == 'y') ||
614                 (*env == 'T') ||
615                 (*env == 't') ||
616                 (((*env == 'O') || (*env == 'o')) &&
617                  ((*(env + 1) == 'N') || (*(env + 1) == 'n'))))
618                 gc_type = CRIU_GCOUNTER_SIG;
619             else if (*env == 2)
620                 gc_type = CRIU_GCOUNTER_PIPE; // The only case for pipe
621             //else use the default of shared memory
622         }
623         if (gc_type != CRIU_GCOUNTER_SHM) {
624             lscriu_dbg("LSCRIU (%d): Use %s\n", getpid(),
625                        gc_type == CRIU_GCOUNTER_SIG ? "signals" : "pipe");
626             lsapi_criu_signal(SIGUSR2, lsapi_siguser2);
627         }
628         else {
629             lscriu_dbg("LSCRIU (%d): Use shared memory\n", getpid());
630 	}
631     	LSCRIU_Set_Global_Counter_Type(gc_type);
632     }
633     else {
634         lscriu_dbg("LSCRIU (%d): NOT Listening\n", getpid());
635     }
636 
637     char *criu_mode = NULL;
638     criu_mode = getenv("LSAPI_CRIU");
639     // 0 disabled
640     // 1 cloudlinux
641     // 2 native
642     if (criu_mode) {
643         if (*criu_mode == '0') {
644              lscriu_dbg("LSCRIU (%d): Disabled by environment.\n", getpid());
645              LSCRIU_Set_Initial_Start_Reqs(0);
646         }
647         else if (*criu_mode == '2') {
648             lscriu_dbg("LSCRIU (%d): Disabled by environment.\n", getpid());
649             s_native = 1;
650         }
651     }
652 
653     if (s_native && init_native_env() == -1)
654         LSCRIU_Set_Initial_Start_Reqs(0);
655 
656     //unset_lsapi_envs();
657     return 0;
658 }
659 
660 
LSCRIU_inc_req_processed()661 void LSCRIU_inc_req_processed()
662 {
663     if (!LSCRIU_Get_Global_Counter_Type()) {
664         ++s_requests_count;
665     }
666 
667     lscriu_dbg("LSCRIU (%d): s_requests_count %d counter %d\n", getpid(),
668                s_requests_count, s_initial_start_reqs);
669 
670     if (s_initial_start_reqs > 0 && s_requests_count <= s_initial_start_reqs) {
671         if (LSCRIU_Get_Global_Counter_Type() == CRIU_GCOUNTER_SHM) {
672             LSCRIU_Increase_Global_Counter();
673             if (s_requests_count >= s_initial_start_reqs) {
674                 //Maybe this time we can stop to send signal and wait for
675                 //1 second of select timeout
676                 //kill( LSCRIU_Get_ppid(), SIGUSR2 );
677                 lscriu_dbg("LSCRIU (%d): Time to dump main process with semaphore\n",
678                            getpid());
679             }
680         } else {
681             kill(LSAPI_Get_ppid(), SIGUSR2);
682             lscriu_dbg("LSCRIU (%d): Send kill to main process with signals\n",
683                        getpid());
684         }
685     }
686 }
687 
688 
LSCRIU_on_timer(int * forked_pid)689 static void LSCRIU_on_timer(int *forked_pid)
690 {
691     lscriu_dbg("LSCRIU (%d): LSCRIU_on_timer\n", getpid());
692     if (LSCRIU_need_checkpoint()) {
693         LSCRIU_try_checkpoint(forked_pid);
694     }
695 }
696 
697 
LSCRIU_Init(void)698 int LSCRIU_Init(void)
699 {
700     s_pid = getpid();
701     LSCRIU_Debugging();
702     LSCRIU_Init_Env_Parameters();
703     if (s_initial_start_reqs && !s_native) {
704         if (LSCRIU_load_liblscapi() == -1)
705             s_initial_start_reqs = 0;
706     }
707     if (s_initial_start_reqs) {
708         LSCRIU_Wink_Server_is_Ready();
709         lscriu_dbg("LSCRIU (%d): LSAPI_Register_Pgrp_Timer_Callback\n", s_pid);
710         LSAPI_Register_Pgrp_Timer_Callback(LSCRIU_on_timer);
711         LSCRIU_Init_Global_Counter(0);
712     }
713     return s_initial_start_reqs > 0;
714 }
715