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