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