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