xref: /php-src/sapi/litespeed/lscriu.c (revision 072e67fd)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: George Wang <gwang@litespeedtech.com>                        |
14    +----------------------------------------------------------------------+
15 */
16 /*
17 Copyright (c) 2002-2018, Lite Speed Technologies Inc.
18 All rights reserved.
19 
20 Redistribution and use in source and binary forms, with or without
21 modification, are permitted provided that the following conditions are
22 met:
23 
24     * Redistributions of source code must retain the above copyright
25       notice, this list of conditions and the following disclaimer.
26     * Redistributions in binary form must reproduce the above
27       copyright notice, this list of conditions and the following
28       disclaimer in the documentation and/or other materials provided
29       with the distribution.
30     * Neither the name of the Lite Speed Technologies Inc nor the
31       names of its contributors may be used to endorse or promote
32       products derived from this software without specific prior
33       written permission.
34 
35 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 */
47 
48 #define HAVE_MSGHDR_MSG_CONTROL
49 #include "lsapilib.h"
50 
51 #include <stdio.h>
52 #include <stdlib.h>
53 
54 #if HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57 
58 #include <sys/wait.h>
59 
60 
61 #include <sys/stat.h>
62 
63 #if HAVE_SYS_TYPES_H
64 
65 #include <sys/types.h>
66 
67 #endif
68 
69 #include <sys/types.h>
70 #include <sys/socket.h>
71 #include <sys/un.h>
72 #include <arpa/inet.h>
73 #include <netinet/in.h>
74 #include <semaphore.h>
75 #include <sys/mman.h>
76 #include <fcntl.h>
77 #include <dlfcn.h>
78 #include <stdlib.h>
79 #include <errno.h>
80 #include <string.h>
81 #include <stdarg.h>
82 
83 #include <signal.h>
84 #include <time.h>
85 #include <sys/timeb.h>
86 #include <unistd.h>
87 #include "lscriu.h"
88 
89 #include <Zend/zend_portability.h>
90 
91 #define  LSCRIU_PATH    256
92 
93 // Begin CRIU inclusion
94 //CRIU inclusion
95 static int s_initial_start_reqs = 0;
96 static int s_requests_count = 0;
97 static int s_restored = 0;
98 static int (*s_lscapi_dump_me)(void) = NULL;
99 static int (*s_lscapi_prepare_me)(void) = NULL;
100 static int s_native = 0;
101 static int s_tried_checkpoint = 0;
102 #ifdef LSAPILIB_DEBUG_CRIU
103 static int s_criu_debug = 0;
104 #endif
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(void);
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 
314 #ifdef LSAPILIB_DEBUG_CRIU
LSCRIU_Error_File_Name(char * pchFile,int max_len)315 static char *LSCRIU_Error_File_Name(char *pchFile, int max_len)
316 {
317     const char *pchDefaultSocketPath = "/tmp/";
318     const char *pchDefaultLogFileName = "lsws_error.log";
319     snprintf(pchFile, max_len, "%s%s", pchDefaultSocketPath,
320              pchDefaultLogFileName);
321     return pchFile;
322 }
323 
324 
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 inline void LSCRIU_Debugging(void) {}
LSCRIU_Restored_Error(int iFatal,char * format,...)409 static inline void 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_Finish_Or_Restored(int pid_parent)474 static void LSCRIU_Wait_Dump_Finish_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     pid_t iPid;
502     pid_t iPidDump = getpid();
503 
504     if (s_tried_checkpoint) {
505         lscriu_dbg("LSCRIU (%d): Already tried checkpoint - one time per customer\n",
506                    iPidDump);
507         return;
508     }
509     lscriu_dbg("LSCRIU (%d): Trying checkpoint\n", iPidDump);
510     s_tried_checkpoint = 1;
511     if (!s_native) {
512         LSCRIU_CloudLinux_Checkpoint();
513         return;
514     }
515 
516     lscriu_dbg("LSCRIU (%d): fork!\n", iPidDump);
517     iPid = fork();
518     if (iPid < 0) {
519         lscriu_err("LSCRIU (%d): Can't checkpoint due to a fork error: %s\n",
520                    iPidDump, strerror(errno));
521         return;
522     }
523     if (iPid == 0) {
524         pid_t   iPidParent = getppid();
525 
526         setsid();
527         (void)LSCRIU_Native_Dump(iPidDump,
528                                   s_criu_image_path,
529                                   s_fd_native);
530         close(s_fd_native);
531 
532         LSCRIU_Wait_Dump_Finish_Or_Restored(iPidParent);
533         LSCRIU_Restored_Error(0, "Restored!");
534         LSAPI_reset_server_state();
535         s_restored = 1;
536     }
537     else {
538         if (forked_pid)
539             *forked_pid = iPid;
540     }
541     LSCRIU_Set_Initial_Start_Reqs(0);
542 }
543 
544 
init_native_env(void)545 static int init_native_env(void)
546 {
547     char *pchFd;
548     pchFd = getenv("LSAPI_CRIU_SYNC_FD");
549     if (!pchFd)
550         pchFd = getenv("LSCAPI_CRIU_SYNC_FD");
551 
552     const char *image_path;
553     image_path = getenv("LSAPI_CRIU_IMAGE_PATH");
554     if (!pchFd) {
555         lscriu_err("LSCRIU (%d): LSAPI_CRIU_SYNC_FD internal environment "
556                    "variable not set - contact Litespeed tech support\n", getpid());
557         return -1;
558     }
559     if (!image_path) {
560         lscriu_err("LSCRIU (%d): LSAPI_CRIU_IMAGE_PATH internal environment "
561                    "variable not set - contact Litespeed tech support\n", getpid());
562         return -1;
563     }
564     lscriu_dbg("LSCRIU (%d): Checkpoint dump.  ImagePath: %s\n",
565                getpid(), image_path);
566 
567     s_fd_native = atoi(pchFd);
568     lscriu_dbg("LSCRIU (%d): Native checkpoint.  Use filepointer %d (%s) to send "
569                "pid %d\n", getpid(), s_fd_native, pchFd, iPidDump);
570     s_criu_image_path  = strdup(image_path);
571     return 0;
572 }
573 
LSCRIU_Init_Env_Parameters(void)574 static int LSCRIU_Init_Env_Parameters(void)
575 {
576     const char *p;
577     int n;
578 
579     p = getenv("LSAPI_INITIAL_START");
580     if (!p)
581         p = getenv("LSAPI_BACKEND_INITIAL_START");
582     if (p) {
583         n = atoi(p);
584 
585         if (n > 0) {
586             lscriu_dbg("LSCRIU (%d): Set start requests based on environment (%d)\n",
587                        getpid(), n);
588             LSCRIU_Set_Initial_Start_Reqs(n);
589         } else {
590             lscriu_dbg("LSCRIU (%d): LSAPI_INITIAL_START set to 0 disabled\n",
591                        getpid());
592             return 0;
593         }
594     } else {
595         lscriu_dbg("LSCRIU (%d): LSAPI_INITIAL_START NOT set - disabled\n",
596                    getpid());
597         return 0;
598     }
599     if (LSAPI_Is_Listen()) {
600         lscriu_dbg("LSCRIU (%d): Listening...\n", getpid());
601         GlobalCounterType_t gc_type = CRIU_GCOUNTER_SHM;
602         char *env;
603         if ((env = getenv("LSAPI_CRIU_USE_SHM"))) {
604             // CloudLinux doc: Off (shared memory) or Signals.
605             // Litespeed doc: On (shared memory) or Signals
606             // So just check the first character for an 'S' and if not, then
607             // use shared memory.  Pipe support is lost (sigh).
608             if ((*env == 'S') || (*env == 's'))
609                 gc_type = CRIU_GCOUNTER_SIG; // Just assume the rest is signals
610             // else use the default of shared memory
611         }
612         else if ((env = getenv("LSAPI_SIGNALS"))) {
613             if ((*env == '1') ||
614                 (*env == 'Y') ||
615                 (*env == 'y') ||
616                 (*env == 'T') ||
617                 (*env == 't') ||
618                 (((*env == 'O') || (*env == 'o')) &&
619                  ((*(env + 1) == 'N') || (*(env + 1) == 'n'))))
620                 gc_type = CRIU_GCOUNTER_SIG;
621             else if (*env == 2)
622                 gc_type = CRIU_GCOUNTER_PIPE; // The only case for pipe
623             //else use the default of shared memory
624         }
625         if (gc_type != CRIU_GCOUNTER_SHM) {
626             lscriu_dbg("LSCRIU (%d): Use %s\n", getpid(),
627                        gc_type == CRIU_GCOUNTER_SIG ? "signals" : "pipe");
628             lsapi_criu_signal(SIGUSR2, lsapi_siguser2);
629         }
630         else {
631             lscriu_dbg("LSCRIU (%d): Use shared memory\n", getpid());
632 	}
633     	LSCRIU_Set_Global_Counter_Type(gc_type);
634     }
635     else {
636         lscriu_dbg("LSCRIU (%d): NOT Listening\n", getpid());
637     }
638 
639     char *criu_mode = NULL;
640     criu_mode = getenv("LSAPI_CRIU");
641     // 0 disabled
642     // 1 cloudlinux
643     // 2 native
644     if (criu_mode) {
645         if (*criu_mode == '0') {
646              lscriu_dbg("LSCRIU (%d): Disabled by environment.\n", getpid());
647              LSCRIU_Set_Initial_Start_Reqs(0);
648         }
649         else if (*criu_mode == '2') {
650             lscriu_dbg("LSCRIU (%d): Disabled by environment.\n", getpid());
651             s_native = 1;
652         }
653     }
654 
655     if (s_native && init_native_env() == -1)
656         LSCRIU_Set_Initial_Start_Reqs(0);
657 
658     //unset_lsapi_envs();
659     return 0;
660 }
661 
662 
LSCRIU_inc_req_processed()663 void LSCRIU_inc_req_processed()
664 {
665     if (!LSCRIU_Get_Global_Counter_Type()) {
666         ++s_requests_count;
667     }
668 
669     lscriu_dbg("LSCRIU (%d): s_requests_count %d counter %d\n", getpid(),
670                s_requests_count, s_initial_start_reqs);
671 
672     if (s_initial_start_reqs > 0 && s_requests_count <= s_initial_start_reqs) {
673         if (LSCRIU_Get_Global_Counter_Type() == CRIU_GCOUNTER_SHM) {
674             LSCRIU_Increase_Global_Counter();
675             if (s_requests_count >= s_initial_start_reqs) {
676                 //Maybe this time we can stop to send signal and wait for
677                 //1 second of select timeout
678                 //kill( LSCRIU_Get_ppid(), SIGUSR2 );
679                 lscriu_dbg("LSCRIU (%d): Time to dump main process with semaphore\n",
680                            getpid());
681             }
682         } else {
683             kill(LSAPI_Get_ppid(), SIGUSR2);
684             lscriu_dbg("LSCRIU (%d): Send kill to main process with signals\n",
685                        getpid());
686         }
687     }
688 }
689 
690 
LSCRIU_on_timer(int * forked_pid)691 static void LSCRIU_on_timer(int *forked_pid)
692 {
693     lscriu_dbg("LSCRIU (%d): LSCRIU_on_timer\n", getpid());
694     if (LSCRIU_need_checkpoint()) {
695         LSCRIU_try_checkpoint(forked_pid);
696     }
697 }
698 
699 
LSCRIU_Init(void)700 int LSCRIU_Init(void)
701 {
702     s_pid = getpid();
703     LSCRIU_Debugging();
704     LSCRIU_Init_Env_Parameters();
705     if (s_initial_start_reqs && !s_native) {
706         if (LSCRIU_load_liblscapi() == -1)
707             s_initial_start_reqs = 0;
708     }
709     if (s_initial_start_reqs) {
710         LSCRIU_Wink_Server_is_Ready();
711         lscriu_dbg("LSCRIU (%d): LSAPI_Register_Pgrp_Timer_Callback\n", s_pid);
712         LSAPI_Register_Pgrp_Timer_Callback(LSCRIU_on_timer);
713         LSCRIU_Init_Global_Counter(0);
714     }
715     return s_initial_start_reqs > 0;
716 }
717