xref: /PHP-7.3/sapi/litespeed/lscriu.c (revision 66d72377)
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_perror( 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 
262     if (s_native)
263         return 0;
264     // Numerical signals indicates Apache
265     int error = 1;
266     char *last;
267 
268     if (!(lib_handle = dlopen(last = "liblscapi.so", RTLD_LAZY)) /*||
269         !(pthread_lib_handle = dlopen(last = "libpthread.so", RTLD_LAZY))*/)
270         fprintf(stderr, "LSCRIU (%d): failed to dlopen %s: %s - ignore CRIU\n",
271                 s_pid, last, dlerror());
272     else if (!(s_lscapi_dump_me = dlsym(lib_handle, last = "lscapi_dump_me")) ||
273                 !(s_lscapi_prepare_me = dlsym(lib_handle, last = "lscapi_prepare_me")) ||
274                 !(psem_open = dlsym(pthread_lib_handle, last = "sem_open")) ||
275                 !(psem_post = dlsym(pthread_lib_handle, last = "sem_post")) ||
276                 !(psem_close = dlsym(pthread_lib_handle, last = "sem_close")))
277         fprintf(stderr, "LSCRIU (%d): failed to dlsym %s: %s - ignore CRIU\n",
278                 s_pid, last, dlerror());
279     else
280         error = 0;
281     if (error) {
282         // close the dll handles so we release the resources
283         if (lib_handle)
284             dlclose(lib_handle);
285         if (pthread_lib_handle)
286             dlclose(pthread_lib_handle);
287         return -1;
288     }
289     return 0;
290 }
291 
292 
LSCRIU_Wink_Server_is_Ready(void)293 static void LSCRIU_Wink_Server_is_Ready(void)
294 {
295     char sem_name[60];
296 
297     if (s_native) {
298         // Not used for native
299         return;
300     }
301     if (getenv("LSAPI_UNIQE"))
302         snprintf(sem_name, sizeof sem_name - 1, "lsphp[hash=%s].is_ready",
303                  getenv("LSAPI_UNIQE"));
304     else
305         snprintf(sem_name, sizeof sem_name - 1, "lsphp[euid=0x%x].is_ready",
306                  geteuid());
307 
308     sem_t *is_ready_sem = psem_open(sem_name, O_RDWR);
309     if (is_ready_sem) {
310         if (psem_post(is_ready_sem) < 0)
311             lsapi_perror(sem_name, errno);
312 
313         if (psem_close(is_ready_sem) < 0)
314             lsapi_perror(sem_name, errno);
315     }
316     else if (errno != ENOENT)
317         lsapi_perror(sem_name, errno);
318 }
319 
320 
LSCRIU_Error_File_Name(char * pchFile,int max_len)321 static char *LSCRIU_Error_File_Name(char *pchFile, int max_len)
322 {
323     const char *pchDefaultSocketPath = "/tmp/";
324     const char *pchDefaultLogFileName = "lsws_error.log";
325     snprintf(pchFile, max_len, "%s%s", pchDefaultSocketPath,
326              pchDefaultLogFileName);
327     return pchFile;
328 }
329 
330 
331 #ifdef LSAPILIB_DEBUG_CRIU
LSCRIU_Debugging(void)332 static void LSCRIU_Debugging(void) {
333     char *pchCRIUDebug;
334     pchCRIUDebug = getenv("LSAPI_CRIU_DEBUG");
335     if (!pchCRIUDebug)
336         pchCRIUDebug = getenv("LSCAPI_CRIU_DEBUG");
337     //fprintf(stderr,"(%d) LSCRIU: CRIU debug environment variable: %s\n",
338     //        s_pid, pchCRIUDebug);
339     // I've made it easy to turn on debugging.  CloudLinux Apache sets
340     // LSCAPI_CRIU_DEBUG to nothing to indicate it's on.  Sigh.
341     if ((!pchCRIUDebug) ||
342         ((!*pchCRIUDebug) ||
343          (*pchCRIUDebug == '0') ||
344          (*pchCRIUDebug == 'f') ||
345          (*pchCRIUDebug == 'F') ||
346          (((*pchCRIUDebug == 'O') ||
347             (*pchCRIUDebug == 'o')) &&
348            ((*(pchCRIUDebug + 1)) &&
349             ((*(pchCRIUDebug + 1) == 'F') || (*(pchCRIUDebug + 1) == 'f'))))))
350     {
351         lscriu_dbg("LSCRIU (%d): CRIU Debugging disabled by environment\n", s_pid);
352         s_criu_debug = 0;
353     }
354     else {
355         s_criu_debug = 1;
356         lscriu_dbg("LSCRIU (%d): CRIU Debugging enabled by environment\n", s_pid);
357         fprintf(stderr,"LSCRIU (%d): CRIU debug environment variable: %s\n",
358                 s_pid, pchCRIUDebug);
359     }
360 }
361 
362 
LSCRIU_Restored_Error(int iFatal,char * format,...)363 static void LSCRIU_Restored_Error(int iFatal, char *format, ...) {
364     // This routine deals with the awful situation of trying to get info while the stderr handle is closed on purpose.
365     int iOldUMask;
366     int iFd = -1;
367     char chFile[1024];
368 
369     if (!iFatal) {
370         // LSCRIU_Debugging();
371         if (!s_criu_debug) {
372             // Debugging message and debugging is off
373             return;
374         }
375     }
376     if (!LSCRIU_Error_File_Name(chFile, sizeof(chFile))) {
377         // We're done here...nowhere to write
378         return;
379     }
380     iOldUMask = umask(0);
381     iFd = open( chFile, O_WRONLY | O_APPEND | O_CREAT,
382                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
383     umask(iOldUMask);
384     if (iFd >= 0) {
385         char chFullMessage[0x1000];
386         struct timeb sTimeb;
387         struct tm    sTm;
388         ftime(&sTimeb);
389         localtime_r(&sTimeb.time,&sTm);
390         va_list ap;
391         va_start(ap, format);
392         char buf[0x1000];
393         vsnprintf(buf, sizeof(buf), format, ap);
394         va_end(ap);
395 
396         int n = snprintf(chFullMessage, sizeof(chFullMessage),
397                 "%04d-%02d-%02d %02d:%02d:%02d.%03d: LSCRIU (%d): %s %s\n",
398                 sTm.tm_year + 1900,
399                 sTm.tm_mon + 1,
400                 sTm.tm_mday,
401                 sTm.tm_hour,
402                 sTm.tm_min,
403                 sTm.tm_sec,
404                 sTimeb.millitm,
405                 s_pid,
406                 iFatal ? "FATAL! " : "(debug) ",
407                 buf);
408         if (n > (int)sizeof(chFullMessage))
409             n = sizeof(chFullMessage);
410         write(iFd, chFullMessage, n);
411         close(iFd);
412     }
413 }
414 #else // no debugging
LSCRIU_Debugging(void)415 static void inline LSCRIU_Debugging(void) {}
LSCRIU_Restored_Error(int iFatal,char * format,...)416 static void inline LSCRIU_Restored_Error(int iFatal, char *format, ...) {}
417 #endif
418 
419 
LSCRIU_Native_Dump(pid_t iPid,char * pchImagePath,int iFdNative)420 static int LSCRIU_Native_Dump(pid_t iPid,
421                               char  *pchImagePath,
422                               int   iFdNative) {
423     criu_native_dump_t criu_native_dump;
424     char *pchLastSlash;
425     criu_native_dump_response_t criu_native_dump_response;
426 
427     memset(&criu_native_dump, 0, sizeof(criu_native_dump));
428     criu_native_dump.m_iPidToDump = iPid;
429     strncpy(criu_native_dump.m_chImageDirectory, pchImagePath,
430             sizeof(criu_native_dump.m_chImageDirectory));
431     pchLastSlash = strrchr(criu_native_dump.m_chSocketDir,'/');
432     if (pchLastSlash) {
433         pchLastSlash++;
434         (*pchLastSlash) = 0;
435     }
436     lscriu_dbg("LSCRIU (%d): Sent the dump request to the listener\n", s_pid);
437     if (write(iFdNative,
438               &criu_native_dump,
439               sizeof(criu_native_dump)) == -1) {
440         lscriu_err("LSCRIU (%d): Error sending dump request to the listener: %s\n",
441                    s_pid, strerror(errno));
442         return(-1);
443     }
444     return 0;
445     /* do not wait response.
446     //while (sleep(7200));
447     if (read(iFdNative,
448              &criu_native_dump_response,
449              sizeof(criu_native_dump_response)) == -1) {
450         // The test will actually fail it!
451         //LSCRIU_Restored_Error(1, "Error reading dump socket #%d from parent: %s",
452         //                      iFdNative, strerror(errno));
453         //return(-1);
454     }
455     return(-1);
456     */
457 }
458 
459 
LSCRIU_CloudLinux_Checkpoint(void)460 static void LSCRIU_CloudLinux_Checkpoint(void)
461 {
462     int iRet;
463 
464     if ((!s_native) && (!s_lscapi_dump_me)) {
465         lscriu_dbg("LSCRIU (%d): Not native and unable to dump - abandon one-time "
466                    "dump\n", s_pid);
467         return;
468     }
469 
470     iRet = s_lscapi_dump_me();
471     if (iRet < 0) {
472         lscriu_err("LSCRIU: CloudLinux dump of PID: %d, error: %s\n",
473                    s_pid, strerror(errno));
474     }
475     if (iRet == 0) {
476         // Dumped.  To continue the child must send us the handles back
477         lscriu_err("LSCRIU: Successful CloudLinux dump of PID: %d\n", s_pid);
478     }
479     else {
480         s_restored = 1;
481         LSAPI_reset_server_state();
482         /*
483          Here we have restored the php process, so we should to tell (via
484          semaphore) mod_lsapi that we are started and ready to receive data.
485         */
486         LSCRIU_Wink_Server_is_Ready();
487         lscriu_err("LSCRIU: Successful CloudLinux restore of PID: %d, parent: %d.\n",
488                    getpid(), getppid());
489     }
490     LSCRIU_Set_Initial_Start_Reqs(0);
491 }
492 
493 
LSCRIU_Wait_Dump_Finsh_Or_Restored(int pid_parent)494 static void LSCRIU_Wait_Dump_Finsh_Or_Restored(int pid_parent)
495 {
496     // Now get restored.  We know if we're restored if the ppid changes!
497     // If we're dumped, we're killed (no use worrying about that!).
498     time_t  iTimeStart = 0;
499     time_t  iTimeNow;
500     int     iRestored = 0;
501     do {
502         usleep(1000);
503         time(&iTimeNow);
504         if (!iTimeStart) {
505             iTimeStart = iTimeNow;
506         }
507         else if ((pid_parent != getppid()) ||
508                     (iTimeNow - iTimeStart > 10)) {
509             iRestored = 1;
510         }
511         else if (iTimeNow - iTimeStart > 5) {
512             LSCRIU_Restored_Error(1, "Timed out waiting to be dumped");
513             exit(1);
514         }
515     } while (!iRestored);
516 }
517 
518 
LSCRIU_try_checkpoint(int * forked_pid)519 static void LSCRIU_try_checkpoint(int *forked_pid)
520 {
521     int iRet;
522     pid_t iPid;
523     pid_t iPidDump = getpid();
524 
525     if (s_tried_checkpoint) {
526         lscriu_dbg("LSCRIU (%d): Already tried checkpoint - one time per customer\n",
527                    iPidDump);
528         return;
529     }
530     lscriu_dbg("LSCRIU (%d): Trying checkpoint\n", iPidDump);
531     s_tried_checkpoint = 1;
532     if (!s_native) {
533         LSCRIU_CloudLinux_Checkpoint();
534         return;
535     }
536 
537     lscriu_dbg("LSCRIU (%d): fork!\n", iPidDump);
538     iPid = fork();
539     if (iPid < 0) {
540         lscriu_err("LSCRIU (%d): Can't checkpoint due to a fork error: %s\n",
541                    iPidDump, strerror(errno));
542         return;
543     }
544     if (iPid == 0) {
545         pid_t   iPidParent = getppid();
546 
547         setsid();
548         iRet = LSCRIU_Native_Dump(iPidDump,
549                                   s_criu_image_path,
550                                   s_fd_native);
551         close(s_fd_native);
552 
553         LSCRIU_Wait_Dump_Finsh_Or_Restored(iPidParent);
554         LSCRIU_Restored_Error(0, "Restored!");
555         LSAPI_reset_server_state();
556         s_restored = 1;
557     }
558     else {
559         if (forked_pid)
560             *forked_pid = iPid;
561     }
562     LSCRIU_Set_Initial_Start_Reqs(0);
563 }
564 
565 
init_native_env()566 static int init_native_env()
567 {
568     char *pchFd;
569     pchFd = getenv("LSAPI_CRIU_SYNC_FD");
570     if (!pchFd)
571         pchFd = getenv("LSCAPI_CRIU_SYNC_FD");
572 
573     const char *image_path;
574     image_path = getenv("LSAPI_CRIU_IMAGE_PATH");
575     if (!pchFd) {
576         lscriu_err("LSCRIU (%d): LSAPI_CRIU_SYNC_FD internal environment "
577                    "variable not set - contact Litespeed tech support\n", getpid());
578         return -1;
579     }
580     if (!image_path) {
581         lscriu_err("LSCRIU (%d): LSAPI_CRIU_IMAGE_PATH internal environment "
582                    "variable not set - contact Litespeed tech support\n", getpid());
583         return -1;
584     }
585     lscriu_dbg("LSCRIU (%d): Checkpoint dump.  ImagePath: %s\n",
586                getpid(), image_path);
587 
588     s_fd_native = atoi(pchFd);
589     lscriu_dbg("LSCRIU (%d): Native checkpoint.  Use filepointer %d (%s) to send "
590                "pid %d\n", getpid(), s_fd_native, pchFd, iPidDump);
591     s_criu_image_path  = strdup(image_path);
592     return 0;
593 }
594 
LSCRIU_Init_Env_Parameters(void)595 static int LSCRIU_Init_Env_Parameters(void)
596 {
597     const char *p;
598     int n;
599 
600     p = getenv("LSAPI_INITIAL_START");
601     if (!p)
602         p = getenv("LSAPI_BACKEND_INITIAL_START");
603     if (p) {
604         n = atoi(p);
605 
606         if (n > 0) {
607             lscriu_dbg("LSCRIU (%d): Set start requests based on environment (%d)\n",
608                        getpid(), n);
609             LSCRIU_Set_Initial_Start_Reqs(n);
610         } else {
611             lscriu_dbg("LSCRIU (%d): LSAPI_INITIAL_START set to 0 disabled\n",
612                        getpid());
613             return 0;
614         }
615     } else {
616         lscriu_dbg("LSCRIU (%d): LSAPI_INITIAL_START NOT set - disabled\n",
617                    getpid());
618         return 0;
619     }
620     if (LSAPI_Is_Listen()) {
621         lscriu_dbg("LSCRIU (%d): Listening...\n", getpid());
622         GlobalCounterType_t gc_type = CRIU_GCOUNTER_SHM;
623         char *env;
624         if ((env = getenv("LSAPI_CRIU_USE_SHM"))) {
625             // CloudLinux doc: Off (shared memory) or Signals.
626             // Litespeed doc: On (shared memory) or Signals
627             // So just check the first character for an 'S' and if not, then
628             // use shared memory.  Pipe support is lost (sigh).
629             if ((*env == 'S') || (*env == 's'))
630                 gc_type = CRIU_GCOUNTER_SIG; // Just assume the rest is signals
631             // else use the default of shared memory
632         }
633         else if ((env = getenv("LSAPI_SIGNALS"))) {
634             if ((*env == '1') ||
635                 (*env == 'Y') ||
636                 (*env == 'y') ||
637                 (*env == 'T') ||
638                 (*env == 't') ||
639                 (((*env == 'O') || (*env == 'o')) &&
640                  ((*(env + 1) == 'N') || (*(env + 1) == 'n'))))
641                 gc_type = CRIU_GCOUNTER_SIG;
642             else if (*env == 2)
643                 gc_type = CRIU_GCOUNTER_PIPE; // The only case for pipe
644             //else use the default of shared memory
645         }
646         if (gc_type != CRIU_GCOUNTER_SHM) {
647             lscriu_dbg("LSCRIU (%d): Use %s\n", getpid(),
648                        gc_type == CRIU_GCOUNTER_SIG ? "signals" : "pipe");
649             lsapi_criu_signal(SIGUSR2, lsapi_siguser2);
650         }
651         else
652             lscriu_dbg("LSCRIU (%d): Use shared memory\n", getpid());
653         LSCRIU_Set_Global_Counter_Type(gc_type);
654     }
655     else
656         lscriu_dbg("LSCRIU (%d): NOT Listening\n", getpid());
657 
658     char *criu_mode = NULL;
659     criu_mode = getenv("LSAPI_CRIU");
660     // 0 disabled
661     // 1 cloudlinux
662     // 2 native
663     if (criu_mode) {
664         if (*criu_mode == '0') {
665              lscriu_dbg("LSCRIU (%d): Disabled by environment.\n", getpid());
666              LSCRIU_Set_Initial_Start_Reqs(0);
667         }
668         else if (*criu_mode == '2') {
669             lscriu_dbg("LSCRIU (%d): Disabled by environment.\n", getpid());
670             s_native = 1;
671         }
672     }
673 
674     if (s_native && init_native_env() == -1)
675         LSCRIU_Set_Initial_Start_Reqs(0);
676 
677     //unset_lsapi_envs();
678     return 0;
679 }
680 
681 
LSCRIU_inc_req_procssed()682 void LSCRIU_inc_req_procssed()
683 {
684     if (!LSCRIU_Get_Global_Counter_Type()) {
685         ++s_requests_count;
686     }
687 
688     lscriu_dbg("LSCRIU (%d): s_requests_count %d counter %d\n", getpid(),
689                s_requests_count, s_initial_start_reqs);
690 
691     if (s_initial_start_reqs > 0 && s_requests_count <= s_initial_start_reqs) {
692         if (LSCRIU_Get_Global_Counter_Type() == CRIU_GCOUNTER_SHM) {
693             LSCRIU_Increase_Global_Counter();
694             if (s_requests_count >= s_initial_start_reqs) {
695                 //Maybe this time we can stop to send signal and wait for
696                 //1 second of select timeout
697                 //kill( LSCRIU_Get_ppid(), SIGUSR2 );
698                 lscriu_dbg("LSCRIU (%d): Time to dump main process with semaphore\n",
699                            getpid());
700             }
701         } else {
702             kill(LSAPI_Get_ppid(), SIGUSR2);
703             lscriu_dbg("LSCRIU (%d): Send kill to main process with signals\n",
704                        getpid());
705         }
706     }
707 }
708 
709 
LSCRIU_on_timer(int * forked_pid)710 static void LSCRIU_on_timer(int *forked_pid)
711 {
712     lscriu_dbg("LSCRIU (%d): LSCRIU_on_timer\n", getpid());
713     if (LSCRIU_need_checkpoint()) {
714         LSCRIU_try_checkpoint(forked_pid);
715     }
716 }
717 
718 
LSCRIU_Init(void)719 int LSCRIU_Init(void)
720 {
721     s_pid = getpid();
722     LSCRIU_Debugging();
723     LSCRIU_Init_Env_Parameters();
724     if (s_initial_start_reqs && !s_native) {
725         if (LSCRIU_load_liblscapi() == -1)
726             s_initial_start_reqs = 0;
727     }
728     if (s_initial_start_reqs) {
729         LSCRIU_Wink_Server_is_Ready();
730         lscriu_dbg("LSCRIU (%d): LSAPI_Register_Pgrp_Timer_Callback\n", s_pid);
731         LSAPI_Register_Pgrp_Timer_Callback(LSCRIU_on_timer);
732         LSCRIU_Init_Global_Counter(0);
733     }
734     return s_initial_start_reqs > 0;
735 }
736