From 2c25275523d359cac164efe7dc77a26e5f97f2ed Mon Sep 17 00:00:00 2001 From: Alban Crequy Date: Mon, 18 May 2015 14:38:29 +0200 Subject: [PATCH] stage1: remove --pid-file patches from systemd-nspawn Instead of asking systemd-nspawn to write its "pid" file, rkt can write the parent pid "ppid". Then, update getPID() to get the pid file from /proc/$ppid/task/$ppid/children. In this way, we don't need to patch systemd-nspawn. getPID() is able to read both the "pid" file and the "ppid" file, in order to work with alternative stage1s which choose to implement one or the other method. coreos/rkt#910 --- rkt/pods.go | 93 +++++++++++++++++- scripts/debug/stage1_install_busybox.sh | 3 +- stage1/init/init.go | 21 ++-- stage1/rootfs/shim/shim.c | 39 -------- .../master/0001-nspawn-add-pid-file.patch | 95 ------------------ .../v215/0003-nspawn-add-pid-file.patch | 90 ----------------- .../v219/0002-nspawn-add-pid-file.patch | 92 ------------------ .../v220/0001-nspawn-add-pid-file.patch | 96 ------------------- 8 files changed, 107 insertions(+), 422 deletions(-) delete mode 100644 stage1/rootfs/usr_from_src/patches/master/0001-nspawn-add-pid-file.patch delete mode 100644 stage1/rootfs/usr_from_src/patches/v215/0003-nspawn-add-pid-file.patch delete mode 100644 stage1/rootfs/usr_from_src/patches/v219/0002-nspawn-add-pid-file.patch delete mode 100644 stage1/rootfs/usr_from_src/patches/v220/0001-nspawn-add-pid-file.patch diff --git a/rkt/pods.go b/rkt/pods.go index 73687bd..1d5746a 100644 --- a/rkt/pods.go +++ b/rkt/pods.go @@ -19,10 +19,13 @@ package main import ( "encoding/json" "fmt" + "io" "io/ioutil" "os" "path/filepath" "sort" + "strconv" + "strings" "syscall" "time" @@ -731,16 +734,97 @@ func (p *pod) getState() string { return state } +type ErrChildNotReady struct { +} + +func (e ErrChildNotReady) Error() string { + return fmt.Sprintf("Child not ready") +} + +// Returns the pid of the child, or ErrChildNotReady if not ready +func getChildPID(ppid int) (int, error) { + var pid int + + // If possible, get the child in O(1). Fallback on O(n) when the kernel does not have + // either CONFIG_PROC_CHILDREN or CONFIG_CHECKPOINT_RESTORE + _, err := os.Stat("/proc/1/task/1/children") + if err == nil { + b, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/task/%d/children", ppid, ppid)) + if err == nil { + children := strings.SplitN(string(b), " ", 2) + if len(children) == 2 && children[1] != "" { + return -1, fmt.Errorf("too many children of pid %d", ppid) + } + if _, err := fmt.Sscanf(children[0], "%d ", &pid); err == nil { + return pid, nil + } + } + return -1, ErrChildNotReady{} + } + + // Fallback on the slower method + fdir, err := os.Open(`/proc`) + if err != nil { + return -1, err + } + defer fdir.Close() + + for { + fi, err := fdir.Readdir(1) + if err == io.EOF { + break + } + if err != nil { + return -1, err + } + var pid64 int64 + if pid64, err = strconv.ParseInt(fi[0].Name(), 10, 0); err != nil { + continue + } + filename := fmt.Sprintf("/proc/%d/stat", pid64) + statBytes, err := ioutil.ReadFile(filename) + if err != nil { + // The process just died? It's not the one we want then. + continue + } + statFields := strings.SplitN(string(statBytes), " ", 5) + if len(statFields) != 5 { + return -1, fmt.Errorf("incomplete file %q", filename) + } + if statFields[3] == fmt.Sprintf("%d", ppid) { + return int(pid64), nil + } + } + + return -1, ErrChildNotReady{} +} + // getPID returns the pid of the pod. func (p *pod) getPID() (pid int, err error) { + // rkt supports two methods to find the container's PID 1: + // the pid file and the ppid file. + // See Documentation/devel/stage1-implementors-guide.md + for { + var ppid int - // No do { } while() Golang, seriously? - for first := true; first || (os.IsNotExist(err) && p.isRunning()); first = false { pid, err = p.readIntFromFile("pid") if err == nil { return } + ppid, err = p.readIntFromFile("ppid") + if err == nil { + pid, err = getChildPID(ppid) + if err == nil { + return pid, nil + } + if _, ok := err.(ErrChildNotReady); ok { + err = nil + } else { + return -1, err + } + } + // There's a window between a pod transitioning to run and the pid file being created by stage1. // The window shouldn't be large so we just delay and retry here. If stage1 fails to reach the // point of pid file creation, it will exit and p.isRunning() becomes false since we refreshState below. @@ -749,8 +833,11 @@ func (p *pod) getPID() (pid int, err error) { if err := p.refreshState(); err != nil { return -1, err } + + if !os.IsNotExist(err) || !p.isRunning() { + return -1, err + } } - return } // getStage1Hash returns the hash of the stage1 image used in this pod diff --git a/scripts/debug/stage1_install_busybox.sh b/scripts/debug/stage1_install_busybox.sh index 1b16c40..fb336ce 100755 --- a/scripts/debug/stage1_install_busybox.sh +++ b/scripts/debug/stage1_install_busybox.sh @@ -52,5 +52,6 @@ for link in ${BUSYBOX_LINKS}; do done echo "Busybox installed. Use the following command to enter pod's stage1:" -SYSTEMD_PID=$(sudo cat "${RKT_RUN_DIR}/${UUID}/pid") +SYSTEMD_PPID=$(sudo cat "${RKT_RUN_DIR}/${UUID}/ppid") +SYSTEMD_PID=$(sudo cat /proc/$SYSTEMD_PPID/task/$SYSTEMD_PPID/children) echo sudo nsenter -m -u -i -p -t ${SYSTEMD_PID} diff --git a/stage1/init/init.go b/stage1/init/init.go index 4dc00d9..6409513 100644 --- a/stage1/init/init.go +++ b/stage1/init/init.go @@ -192,12 +192,6 @@ func getArgsEnv(p *Pod, flavor string, systemdStage1Version string, debug bool) // before execing init"), fds remain open, so --keep-fd is not needed. } - out, err := os.Getwd() - if err != nil { - return nil, nil, err - } - args = append(args, fmt.Sprintf("--pid-file=%v", filepath.Join(out, "pid"))) - if machinedRegister() { args = append(args, fmt.Sprintf("--register=true")) } else { @@ -381,6 +375,21 @@ func stage1() int { return 3 } + // write ppid file as specified in + // Documentation/devel/stage1-implementors-guide.md + out, err := os.Getwd() + if err != nil { + fmt.Fprintf(os.Stderr, "Cannot get current working directory: %v\n", err) + return 4 + } + // we are the parent of the process that is PID 1 in the container so we write our PID to "ppid" + err = ioutil.WriteFile(filepath.Join(out, "ppid"), + []byte(fmt.Sprintf("%d\n", os.Getpid())), 0644) + if err != nil { + fmt.Fprintf(os.Stderr, "Cannot write ppid file: %v\n", err) + return 4 + } + var execFn func() error if privNet.Any() { diff --git a/stage1/rootfs/shim/shim.c b/stage1/rootfs/shim/shim.c index c376163..e88de1b 100644 --- a/stage1/rootfs/shim/shim.c +++ b/stage1/rootfs/shim/shim.c @@ -28,16 +28,12 @@ /* hack to make systemd-nspawn execute on non-sysd systems: * - intercept lstat() so lstat of /run/systemd/system always succeeds and returns a directory * - intercept close() to prevent nspawn closing the rkt lock, set it to CLOEXEC instead - * - intercept syscall(SYS_clone) to record the pod's pid */ #define ENV_LOCKFD "RKT_LOCK_FD" -#define PIDFILE_TMP "pid.tmp" -#define PIDFILE "pid" static int (*libc_lxstat)(int, const char *, struct stat *); static int (*libc_close)(int); -static long (*libc_syscall)(long number, ...); static int lock_fd = -1; static __attribute__((constructor)) void wrapper_init(void) @@ -47,7 +43,6 @@ static __attribute__((constructor)) void wrapper_init(void) lock_fd = atoi(env); libc_lxstat = dlsym(RTLD_NEXT, "__lxstat"); libc_close = dlsym(RTLD_NEXT, "close"); - libc_syscall = dlsym(RTLD_NEXT, "syscall"); } int __lxstat(int ver, const char *path, struct stat *stat) @@ -69,37 +64,3 @@ int close(int fd) return libc_close(fd); } - -long syscall(long number, ...) -{ - unsigned long clone_flags; - va_list ap; - long ret; - - /* XXX: we're targeting systemd-nspawn with this shim, its only syscall() use is __NR_clone */ - if(number != __NR_clone) - return -1; - - va_start(ap, number); - clone_flags = va_arg(ap, unsigned long); - va_end(ap); - - ret = libc_syscall(number, clone_flags, NULL); - - if(ret > 0) { - int fd; - /* in parent; try record the pod's pid */ - if((fd = open(PIDFILE_TMP, O_CREAT|O_WRONLY|O_SYNC, 0640)) != -1) { - int len; - char buf[20]; - - if((len = snprintf(buf, sizeof(buf), "%li\n", ret)) != -1) - if(write(fd, buf, len) == len) - rename(PIDFILE_TMP, PIDFILE); - - libc_close(fd); - } - } - - return ret; -} diff --git a/stage1/rootfs/usr_from_src/patches/master/0001-nspawn-add-pid-file.patch b/stage1/rootfs/usr_from_src/patches/master/0001-nspawn-add-pid-file.patch deleted file mode 100644 index 2980ce9..0000000 --- a/stage1/rootfs/usr_from_src/patches/master/0001-nspawn-add-pid-file.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 54802a88288c44c098d0cbe884e698cdbd778de2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Iago=20L=C3=B3pez=20Galeiras?= -Date: Thu, 21 May 2015 16:52:48 +0200 -Subject: [PATCH] nspawn: add --pid-file - -Simple mechanism for recording the container's pid independent of any -external daemons/systemd services. - -[patch ported to v219 -alban] -[patch ported to git master 2015-05-20 -alban] -[patch ported to git master 2015-05-21 -iaguis] ---- - src/nspawn/nspawn.c | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c -index d6b24c6..be69172 100644 ---- a/src/nspawn/nspawn.c -+++ b/src/nspawn/nspawn.c -@@ -190,6 +190,7 @@ static bool arg_quiet = false; - static bool arg_share_system = false; - static bool arg_register = true; - static bool arg_keep_unit = false; -+static const char *arg_pid_file = NULL; - static char **arg_network_interfaces = NULL; - static char **arg_network_macvlan = NULL; - static char **arg_network_ipvlan = NULL; -@@ -271,6 +272,7 @@ static void help(void) { - " --keep-unit Do not register a scope for the machine, reuse\n" - " the service unit nspawn is running in\n" - " --volatile[=MODE] Run the system in volatile mode\n" -+ " --pid-file=FILE Write child pid to FILE\n" - , program_invocation_short_name); - } - -@@ -397,6 +399,7 @@ static int parse_argv(int argc, char *argv[]) { - ARG_SHARE_SYSTEM, - ARG_REGISTER, - ARG_KEEP_UNIT, -+ ARG_PID_FILE, - ARG_NETWORK_INTERFACE, - ARG_NETWORK_MACVLAN, - ARG_NETWORK_IPVLAN, -@@ -437,6 +440,7 @@ static int parse_argv(int argc, char *argv[]) { - { "share-system", no_argument, NULL, ARG_SHARE_SYSTEM }, - { "register", required_argument, NULL, ARG_REGISTER }, - { "keep-unit", no_argument, NULL, ARG_KEEP_UNIT }, -+ { "pid-file", required_argument, NULL, ARG_PID_FILE }, - { "network-interface", required_argument, NULL, ARG_NETWORK_INTERFACE }, - { "network-macvlan", required_argument, NULL, ARG_NETWORK_MACVLAN }, - { "network-ipvlan", required_argument, NULL, ARG_NETWORK_IPVLAN }, -@@ -820,6 +824,10 @@ static int parse_argv(int argc, char *argv[]) { - arg_keep_unit = true; - break; - -+ case ARG_PID_FILE: -+ arg_pid_file = optarg; -+ break; -+ - case ARG_PERSONALITY: - - arg_personality = personality_from_string(optarg); -@@ -3920,6 +3928,14 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) { - return r; - } - -+static int write_pid(const char *f, int pid) { -+ char pid_str[13]; /* -2147483646\n\0 */ -+ -+ snprintf(pid_str, sizeof(pid_str), "%i\n", pid); -+ return write_string_file_atomic(f, pid_str); -+} -+ -+ - static void nop_handler(int sig) {} - - static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { -@@ -4875,6 +4891,14 @@ int main(int argc, char *argv[]) { - goto finish; - } - -+ if (arg_pid_file) { -+ r = write_pid(arg_pid_file, pid); -+ if (r < 0) { -+ log_error_errno(r, "Failed to write pid file: %m"); -+ goto finish; -+ } -+ } -+ - sd_notifyf(false, - "READY=1\n" - "STATUS=Container running.\n" --- -2.4.1 - diff --git a/stage1/rootfs/usr_from_src/patches/v215/0003-nspawn-add-pid-file.patch b/stage1/rootfs/usr_from_src/patches/v215/0003-nspawn-add-pid-file.patch deleted file mode 100644 index f753e35..0000000 --- a/stage1/rootfs/usr_from_src/patches/v215/0003-nspawn-add-pid-file.patch +++ /dev/null @@ -1,90 +0,0 @@ -From b7c75246350bd7af55f80dd9ac89c23682765aaf Mon Sep 17 00:00:00 2001 -From: Vito Caputo -Date: Mon, 16 Mar 2015 15:13:49 -0700 -Subject: [PATCH 3/3] nspawn: add --pid-file - -Simple mechanism for recording the container's pid independent of any external -daemons/systemd services. ---- - src/nspawn/nspawn.c | 23 ++++++++++++++++++++++- - 1 file changed, 22 insertions(+), 1 deletion(-) - -diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c -index 0277a12..6650629 100644 ---- a/src/nspawn/nspawn.c -+++ b/src/nspawn/nspawn.c -@@ -154,6 +154,7 @@ static bool arg_share_system = false; - static bool arg_register = true; - static bool arg_keep_unit = false; - static int arg_keep_fd = -1; -+static const char *arg_pid_file = NULL; - static char **arg_network_interfaces = NULL; - static char **arg_network_macvlan = NULL; - static bool arg_network_veth = false; -@@ -209,7 +210,8 @@ static int help(void) { - " --register=BOOLEAN Register container as machine\n" - " --keep-unit Do not register a scope for the machine, reuse\n" - " the service unit nspawn is running in\n" -- " --keep-fd=FDNUM Do not close the specified file descriptor\n", -+ " --keep-fd=FDNUM Do not close the specified file descriptor\n" -+ " --pid-file=FILE Write child pid to FILE\n", - program_invocation_short_name); - - return 0; -@@ -233,6 +235,7 @@ static int parse_argv(int argc, char *argv[]) { - ARG_REGISTER, - ARG_KEEP_UNIT, - ARG_KEEP_FD, -+ ARG_PID_FILE, - ARG_NETWORK_INTERFACE, - ARG_NETWORK_MACVLAN, - ARG_NETWORK_VETH, -@@ -265,6 +268,7 @@ static int parse_argv(int argc, char *argv[]) { - { "register", required_argument, NULL, ARG_REGISTER }, - { "keep-unit", no_argument, NULL, ARG_KEEP_UNIT }, - { "keep-fd", required_argument, NULL, ARG_KEEP_FD }, -+ { "pid-file", required_argument, NULL, ARG_PID_FILE }, - { "network-interface", required_argument, NULL, ARG_NETWORK_INTERFACE }, - { "network-macvlan", required_argument, NULL, ARG_NETWORK_MACVLAN }, - { "network-veth", no_argument, NULL, ARG_NETWORK_VETH }, -@@ -561,6 +565,10 @@ static int parse_argv(int argc, char *argv[]) { - } - break; - -+ case ARG_PID_FILE: -+ arg_pid_file = optarg; -+ break; -+ - case ARG_PERSONALITY: - - arg_personality = personality_from_string(optarg); -@@ -2757,6 +2765,13 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) { - return r; - } - -+static int write_pid(const char *f, int pid) { -+ char pid_str[13]; /* -2147483646\n\0 */ -+ -+ snprintf(pid_str, sizeof(pid_str), "%i\n", pid); -+ return write_string_file_atomic(f, pid_str); -+} -+ - static void nop_handler(int sig) {} - - int main(int argc, char *argv[]) { -@@ -3317,6 +3332,12 @@ int main(int argc, char *argv[]) { - eventfds[1] = safe_close(eventfds[1]); - - if (r >= 0) { -+ if (arg_pid_file) { -+ r = write_pid(arg_pid_file, pid); -+ if (r < 0) -+ goto finish; -+ } -+ - r = register_machine(pid); - if (r < 0) - goto finish; --- -2.1.4 - diff --git a/stage1/rootfs/usr_from_src/patches/v219/0002-nspawn-add-pid-file.patch b/stage1/rootfs/usr_from_src/patches/v219/0002-nspawn-add-pid-file.patch deleted file mode 100644 index cdef4d4..0000000 --- a/stage1/rootfs/usr_from_src/patches/v219/0002-nspawn-add-pid-file.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 30b585a02cfad4c0f420f70146bb6bc4566def85 Mon Sep 17 00:00:00 2001 -From: Vito Caputo -Date: Mon, 16 Mar 2015 15:13:49 -0700 -Subject: [PATCH 2/4] nspawn: add --pid-file - -Simple mechanism for recording the container's pid independent of any external -daemons/systemd services. - -[patch ported to v219 -alban] ---- - src/nspawn/nspawn.c | 23 +++++++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c -index b7c9da5..5ea07c4 100644 ---- a/src/nspawn/nspawn.c -+++ b/src/nspawn/nspawn.c -@@ -179,6 +179,7 @@ static bool arg_share_system = false; - static bool arg_register = true; - static bool arg_keep_unit = false; - static int arg_keep_fd = -1; -+static const char *arg_pid_file = NULL; - static char **arg_network_interfaces = NULL; - static char **arg_network_macvlan = NULL; - static char **arg_network_ipvlan = NULL; -@@ -248,6 +249,7 @@ static void help(void) { - " the service unit nspawn is running in\n" - " --volatile[=MODE] Run the system in volatile mode\n" - " --keep-fd=FDNUM Do not close the specified file descriptor\n" -+ " --pid-file=FILE Write child pid to FILE\n" - , program_invocation_short_name); - } - -@@ -290,6 +292,7 @@ static int parse_argv(int argc, char *argv[]) { - ARG_REGISTER, - ARG_KEEP_UNIT, - ARG_KEEP_FD, -+ ARG_PID_FILE, - ARG_NETWORK_INTERFACE, - ARG_NETWORK_MACVLAN, - ARG_NETWORK_IPVLAN, -@@ -326,6 +329,7 @@ static int parse_argv(int argc, char *argv[]) { - { "register", required_argument, NULL, ARG_REGISTER }, - { "keep-unit", no_argument, NULL, ARG_KEEP_UNIT }, - { "keep-fd", required_argument, NULL, ARG_KEEP_FD }, -+ { "pid-file", required_argument, NULL, ARG_PID_FILE }, - { "network-interface", required_argument, NULL, ARG_NETWORK_INTERFACE }, - { "network-macvlan", required_argument, NULL, ARG_NETWORK_MACVLAN }, - { "network-ipvlan", required_argument, NULL, ARG_NETWORK_IPVLAN }, -@@ -655,6 +659,10 @@ static int parse_argv(int argc, char *argv[]) { - } - break; - -+ case ARG_PID_FILE: -+ arg_pid_file = optarg; -+ break; -+ - case ARG_PERSONALITY: - - arg_personality = personality_from_string(optarg); -@@ -3495,6 +3503,13 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) { - return r; - } - -+static int write_pid(const char *f, int pid) { -+ char pid_str[13]; /* -2147483646\n\0 */ -+ -+ snprintf(pid_str, sizeof(pid_str), "%i\n", pid); -+ return write_string_file_atomic(f, pid_str); -+} -+ - static void nop_handler(int sig) {} - - static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { -@@ -4237,6 +4252,14 @@ int main(int argc, char *argv[]) { - _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; - char last_char = 0; - -+ if (arg_pid_file) { -+ r = write_pid(arg_pid_file, pid); -+ if (r < 0) { -+ log_error_errno(r, "Failed to write pid file: %m"); -+ goto finish; -+ } -+ } -+ - sd_notifyf(false, - "READY=1\n" - "STATUS=Container running.\n" --- -2.1.4 - diff --git a/stage1/rootfs/usr_from_src/patches/v220/0001-nspawn-add-pid-file.patch b/stage1/rootfs/usr_from_src/patches/v220/0001-nspawn-add-pid-file.patch deleted file mode 100644 index 50ccc5d..0000000 --- a/stage1/rootfs/usr_from_src/patches/v220/0001-nspawn-add-pid-file.patch +++ /dev/null @@ -1,96 +0,0 @@ -From a7bfa4b16a833ff5e2b25e28b406c300a8d3e318 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Iago=20L=C3=B3pez=20Galeiras?= -Date: Thu, 21 May 2015 16:52:48 +0200 -Subject: [PATCH] nspawn: add --pid-file - -Simple mechanism for recording the container's pid independent of any -external daemons/systemd services. - -[patch ported to v219 -alban] -[patch ported to git master 2015-05-20 -alban] -[patch ported to git master 2015-05-21 -iaguis] -[patch ported to v220 2015-05-26 -alban] ---- - src/nspawn/nspawn.c | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c -index 5009363..41c034c 100644 ---- a/src/nspawn/nspawn.c -+++ b/src/nspawn/nspawn.c -@@ -190,6 +190,7 @@ static bool arg_quiet = false; - static bool arg_share_system = false; - static bool arg_register = true; - static bool arg_keep_unit = false; -+static const char *arg_pid_file = NULL; - static char **arg_network_interfaces = NULL; - static char **arg_network_macvlan = NULL; - static char **arg_network_ipvlan = NULL; -@@ -271,6 +272,7 @@ static void help(void) { - " --keep-unit Do not register a scope for the machine, reuse\n" - " the service unit nspawn is running in\n" - " --volatile[=MODE] Run the system in volatile mode\n" -+ " --pid-file=FILE Write child pid to FILE\n" - , program_invocation_short_name); - } - -@@ -397,6 +399,7 @@ static int parse_argv(int argc, char *argv[]) { - ARG_SHARE_SYSTEM, - ARG_REGISTER, - ARG_KEEP_UNIT, -+ ARG_PID_FILE, - ARG_NETWORK_INTERFACE, - ARG_NETWORK_MACVLAN, - ARG_NETWORK_IPVLAN, -@@ -437,6 +440,7 @@ static int parse_argv(int argc, char *argv[]) { - { "share-system", no_argument, NULL, ARG_SHARE_SYSTEM }, - { "register", required_argument, NULL, ARG_REGISTER }, - { "keep-unit", no_argument, NULL, ARG_KEEP_UNIT }, -+ { "pid-file", required_argument, NULL, ARG_PID_FILE }, - { "network-interface", required_argument, NULL, ARG_NETWORK_INTERFACE }, - { "network-macvlan", required_argument, NULL, ARG_NETWORK_MACVLAN }, - { "network-ipvlan", required_argument, NULL, ARG_NETWORK_IPVLAN }, -@@ -820,6 +824,10 @@ static int parse_argv(int argc, char *argv[]) { - arg_keep_unit = true; - break; - -+ case ARG_PID_FILE: -+ arg_pid_file = optarg; -+ break; -+ - case ARG_PERSONALITY: - - arg_personality = personality_from_string(optarg); -@@ -3921,6 +3929,14 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) { - return r; - } - -+static int write_pid(const char *f, int pid) { -+ char pid_str[13]; /* -2147483646\n\0 */ -+ -+ snprintf(pid_str, sizeof(pid_str), "%i\n", pid); -+ return write_string_file_atomic(f, pid_str); -+} -+ -+ - static void nop_handler(int sig) {} - - static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { -@@ -4876,6 +4892,14 @@ int main(int argc, char *argv[]) { - goto finish; - } - -+ if (arg_pid_file) { -+ r = write_pid(arg_pid_file, pid); -+ if (r < 0) { -+ log_error_errno(r, "Failed to write pid file: %m"); -+ goto finish; -+ } -+ } -+ - sd_notifyf(false, - "READY=1\n" - "STATUS=Container running.\n" --- -2.1.4 -