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