Commit ac5cac18 authored by Andrei Vagin's avatar Andrei Vagin Committed by Pavel Emelyanov

crtools: close a signal descriptor after passing a preparation stage

This patch adds the --siganl-fd FD option to specify a file descriptor.
CRIU will write '\0' to this descriptor and close it after passing
a preparation stage.

It is alternative way to demonizing a criu process after a preparation
stage. It's imposiable to get exit code, if a process has daemonized.

The introduced way allows to wait a preparation stage and to get an exit
code. It can be easy used from shell and other script languages.

v3: fix a help message

v4: Here is a sequence of actions how it can be used:
     * open a pipe
     * run a service with the pipe[1] as status_fd
     * read(pipe[0]) to wait a moment when the service will be ready to
       accept connections
     * do a work which requires the service
     * wait the service process to gets its exit status to be sure that
       everything okey

travis-ci: success for crtools: close a signal descriptor after passing a preparation stage (rev6)
Cc: Mike Rapoport <mike.rapoport@gmail.com>
Cc: Kir Kolyshkin <kir@openvz.org>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent 7e815625
...@@ -506,6 +506,12 @@ Launches *criu* in page server mode. ...@@ -506,6 +506,12 @@ Launches *criu* in page server mode.
*--daemon*:: *--daemon*::
Runs page server as a daemon (background process). Runs page server as a daemon (background process).
*--status_fd*::
Write \\0 to the FD and close it once page-server is ready to handle
requests. The status-fd allows to not daemonize a process and get its
exit code at the end.
It isn't supposed to use --daemon and --status-fd together.
*--address* 'address':: *--address* 'address'::
Page server IP address. Page server IP address.
......
...@@ -76,6 +76,7 @@ void init_opts(void) ...@@ -76,6 +76,7 @@ void init_opts(void)
opts.ghost_limit = DEFAULT_GHOST_LIMIT; opts.ghost_limit = DEFAULT_GHOST_LIMIT;
opts.timeout = DEFAULT_TIMEOUT; opts.timeout = DEFAULT_TIMEOUT;
opts.empty_ns = 0; opts.empty_ns = 0;
opts.status_fd = -1;
} }
static int parse_join_ns(const char *ptr) static int parse_join_ns(const char *ptr)
...@@ -285,6 +286,7 @@ int main(int argc, char *argv[], char *envp[]) ...@@ -285,6 +286,7 @@ int main(int argc, char *argv[], char *envp[])
{ "deprecated", no_argument, 0, 1084 }, { "deprecated", no_argument, 0, 1084 },
{ "display-stats", no_argument, 0, 1086 }, { "display-stats", no_argument, 0, 1086 },
{ "weak-sysctls", no_argument, 0, 1087 }, { "weak-sysctls", no_argument, 0, 1087 },
{ "status-fd", required_argument, 0, 1088 },
{ }, { },
}; };
...@@ -604,6 +606,12 @@ int main(int argc, char *argv[], char *envp[]) ...@@ -604,6 +606,12 @@ int main(int argc, char *argv[], char *envp[])
pr_msg("Will skip non-existant sysctls on restore\n"); pr_msg("Will skip non-existant sysctls on restore\n");
opts.weak_sysctls = true; opts.weak_sysctls = true;
break; break;
case 1088:
if (sscanf(optarg, "%d", &opts.status_fd) != 1) {
pr_err("Unable to parse a value of --status-fd\n");
return 1;
}
break;
case 'V': case 'V':
pr_msg("Version: %s\n", CRIU_VERSION); pr_msg("Version: %s\n", CRIU_VERSION);
if (strcmp(CRIU_GITID, "0")) if (strcmp(CRIU_GITID, "0"))
...@@ -940,6 +948,8 @@ usage: ...@@ -940,6 +948,8 @@ usage:
" --address ADDR address of server or service\n" " --address ADDR address of server or service\n"
" --port PORT port of page server\n" " --port PORT port of page server\n"
" -d|--daemon run in the background after creating socket\n" " -d|--daemon run in the background after creating socket\n"
" --status-fd FD write \\0 to the FD and close it once process is ready\n"
" to handle requests\n"
"\n" "\n"
"Other options:\n" "Other options:\n"
" -h|--help show this text\n" " -h|--help show this text\n"
......
...@@ -117,6 +117,7 @@ struct cr_options { ...@@ -117,6 +117,7 @@ struct cr_options {
bool deprecated_ok; bool deprecated_ok;
bool display_stats; bool display_stats;
bool weak_sysctls; bool weak_sysctls;
int status_fd;
}; };
extern struct cr_options opts; extern struct cr_options opts;
......
...@@ -172,6 +172,7 @@ extern int cr_system(int in, int out, int err, char *cmd, char *const argv[], un ...@@ -172,6 +172,7 @@ extern int cr_system(int in, int out, int err, char *cmd, char *const argv[], un
extern int cr_system_userns(int in, int out, int err, char *cmd, extern int cr_system_userns(int in, int out, int err, char *cmd,
char *const argv[], unsigned flags, int userns_pid); char *const argv[], unsigned flags, int userns_pid);
extern int cr_daemon(int nochdir, int noclose, int *keep_fd, int close_fd); extern int cr_daemon(int nochdir, int noclose, int *keep_fd, int close_fd);
extern int close_status_fd(void);
extern int is_root_user(void); extern int is_root_user(void);
static inline bool dir_dots(const struct dirent *de) static inline bool dir_dots(const struct dirent *de)
......
...@@ -690,6 +690,21 @@ out: ...@@ -690,6 +690,21 @@ out:
return ret; return ret;
} }
int close_status_fd(void)
{
char c = 0;
if (opts.status_fd < 0)
return 0;
if (write(opts.status_fd, &c, 1) != 1) {
pr_perror("Unable to write into the status fd");
return -1;
}
return close_safe(&opts.status_fd);
}
int cr_daemon(int nochdir, int noclose, int *keep_fd, int close_fd) int cr_daemon(int nochdir, int noclose, int *keep_fd, int close_fd)
{ {
int pid; int pid;
...@@ -1155,6 +1170,9 @@ int run_tcp_server(bool daemon_mode, int *ask, int cfd, int sk) ...@@ -1155,6 +1170,9 @@ int run_tcp_server(bool daemon_mode, int *ask, int cfd, int sk)
} }
} }
if (close_status_fd())
return -1;
if (sk >= 0) { if (sk >= 0) {
ret = *ask = accept(sk, (struct sockaddr *)&caddr, &clen); ret = *ask = accept(sk, (struct sockaddr *)&caddr, &clen);
if (*ask < 0) if (*ask < 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment