From 9a9b50f96875f84e449a3570ab1a0d0e627b547d Mon Sep 17 00:00:00 2001 From: unclejack Date: Thu, 30 Oct 2014 14:48:30 +0200 Subject: [PATCH 01/37] pkg/reexec: move reexec code to a new package Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) --- reexec/MAINTAINERS | 1 + reexec/README.md | 5 +++++ reexec/reexec.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 reexec/MAINTAINERS create mode 100644 reexec/README.md create mode 100644 reexec/reexec.go diff --git a/reexec/MAINTAINERS b/reexec/MAINTAINERS new file mode 100644 index 0000000..e48a0c7 --- /dev/null +++ b/reexec/MAINTAINERS @@ -0,0 +1 @@ +Michael Crosby (@crosbymichael) diff --git a/reexec/README.md b/reexec/README.md new file mode 100644 index 0000000..45592ce --- /dev/null +++ b/reexec/README.md @@ -0,0 +1,5 @@ +## reexec + +The `reexec` package facilitates the busybox style reexec of the docker binary that we require because +of the forking limitations of using Go. Handlers can be registered with a name and the argv 0 of +the exec of the binary will be used to find and execute custom init paths. diff --git a/reexec/reexec.go b/reexec/reexec.go new file mode 100644 index 0000000..136b905 --- /dev/null +++ b/reexec/reexec.go @@ -0,0 +1,45 @@ +package reexec + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" +) + +var registeredInitializers = make(map[string]func()) + +// Register adds an initialization func under the specified name +func Register(name string, initializer func()) { + if _, exists := registeredInitializers[name]; exists { + panic(fmt.Sprintf("reexec func already registred under name %q", name)) + } + + registeredInitializers[name] = initializer +} + +// Init is called as the first part of the exec process and returns true if an +// initialization function was called. +func Init() bool { + initializer, exists := registeredInitializers[os.Args[0]] + if exists { + initializer() + + return true + } + + return false +} + +// Self returns the path to the current processes binary +func Self() string { + name := os.Args[0] + + if filepath.Base(name) == name { + if lp, err := exec.LookPath(name); err == nil { + name = lp + } + } + + return name +} From 27509ffbe451ea3a76e43b5c26aa3ba46bf11318 Mon Sep 17 00:00:00 2001 From: unclejack Date: Thu, 30 Oct 2014 14:48:30 +0200 Subject: [PATCH 02/37] pkg/reexec: move reexec code to a new package Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) Conflicts: integration/runtime_test.go fixed imports --- reexec/MAINTAINERS | 1 + reexec/README.md | 5 +++++ reexec/reexec.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 reexec/MAINTAINERS create mode 100644 reexec/README.md create mode 100644 reexec/reexec.go diff --git a/reexec/MAINTAINERS b/reexec/MAINTAINERS new file mode 100644 index 0000000..e48a0c7 --- /dev/null +++ b/reexec/MAINTAINERS @@ -0,0 +1 @@ +Michael Crosby (@crosbymichael) diff --git a/reexec/README.md b/reexec/README.md new file mode 100644 index 0000000..45592ce --- /dev/null +++ b/reexec/README.md @@ -0,0 +1,5 @@ +## reexec + +The `reexec` package facilitates the busybox style reexec of the docker binary that we require because +of the forking limitations of using Go. Handlers can be registered with a name and the argv 0 of +the exec of the binary will be used to find and execute custom init paths. diff --git a/reexec/reexec.go b/reexec/reexec.go new file mode 100644 index 0000000..136b905 --- /dev/null +++ b/reexec/reexec.go @@ -0,0 +1,45 @@ +package reexec + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" +) + +var registeredInitializers = make(map[string]func()) + +// Register adds an initialization func under the specified name +func Register(name string, initializer func()) { + if _, exists := registeredInitializers[name]; exists { + panic(fmt.Sprintf("reexec func already registred under name %q", name)) + } + + registeredInitializers[name] = initializer +} + +// Init is called as the first part of the exec process and returns true if an +// initialization function was called. +func Init() bool { + initializer, exists := registeredInitializers[os.Args[0]] + if exists { + initializer() + + return true + } + + return false +} + +// Self returns the path to the current processes binary +func Self() string { + name := os.Args[0] + + if filepath.Base(name) == name { + if lp, err := exec.LookPath(name); err == nil { + name = lp + } + } + + return name +} From c4bd5c1015e0ab7bc75e3f085f8d3e5cd98d75cb Mon Sep 17 00:00:00 2001 From: unclejack Date: Wed, 29 Oct 2014 21:06:51 +0200 Subject: [PATCH 03/37] add pkg/chrootarchive and use it on the daemon Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) --- reexec/command_linux.go | 18 ++++++++++++++++++ reexec/command_unsupported.go | 11 +++++++++++ reexec/reexec.go | 3 --- 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 reexec/command_linux.go create mode 100644 reexec/command_unsupported.go diff --git a/reexec/command_linux.go b/reexec/command_linux.go new file mode 100644 index 0000000..8dc3f3a --- /dev/null +++ b/reexec/command_linux.go @@ -0,0 +1,18 @@ +// +build linux + +package reexec + +import ( + "os/exec" + "syscall" +) + +func Command(args ...string) *exec.Cmd { + return &exec.Cmd{ + Path: Self(), + Args: args, + SysProcAttr: &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGTERM, + }, + } +} diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go new file mode 100644 index 0000000..a579318 --- /dev/null +++ b/reexec/command_unsupported.go @@ -0,0 +1,11 @@ +// +build !linux + +package reexec + +import ( + "os/exec" +) + +func Command(args ...string) *exec.Cmd { + return nil +} diff --git a/reexec/reexec.go b/reexec/reexec.go index 136b905..774e71c 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -27,19 +27,16 @@ func Init() bool { return true } - return false } // Self returns the path to the current processes binary func Self() string { name := os.Args[0] - if filepath.Base(name) == name { if lp, err := exec.LookPath(name); err == nil { name = lp } } - return name } From 3223844c2830465c8517faa947f994a1e66cc0b1 Mon Sep 17 00:00:00 2001 From: unclejack Date: Wed, 29 Oct 2014 21:06:51 +0200 Subject: [PATCH 04/37] add pkg/chrootarchive and use it on the daemon Docker-DCO-1.1-Signed-off-by: Cristian Staretu (github: unclejack) Conflicts: builder/internals.go daemon/graphdriver/aufs/aufs.go daemon/volumes.go fixed conflicts in imports --- reexec/command_linux.go | 18 ++++++++++++++++++ reexec/command_unsupported.go | 11 +++++++++++ reexec/reexec.go | 3 --- 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 reexec/command_linux.go create mode 100644 reexec/command_unsupported.go diff --git a/reexec/command_linux.go b/reexec/command_linux.go new file mode 100644 index 0000000..8dc3f3a --- /dev/null +++ b/reexec/command_linux.go @@ -0,0 +1,18 @@ +// +build linux + +package reexec + +import ( + "os/exec" + "syscall" +) + +func Command(args ...string) *exec.Cmd { + return &exec.Cmd{ + Path: Self(), + Args: args, + SysProcAttr: &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGTERM, + }, + } +} diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go new file mode 100644 index 0000000..a579318 --- /dev/null +++ b/reexec/command_unsupported.go @@ -0,0 +1,11 @@ +// +build !linux + +package reexec + +import ( + "os/exec" +) + +func Command(args ...string) *exec.Cmd { + return nil +} diff --git a/reexec/reexec.go b/reexec/reexec.go index 136b905..774e71c 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -27,19 +27,16 @@ func Init() bool { return true } - return false } // Self returns the path to the current processes binary func Self() string { name := os.Args[0] - if filepath.Base(name) == name { if lp, err := exec.LookPath(name); err == nil { name = lp } } - return name } From afb82c667074d707fd0e9f561703b88055efb641 Mon Sep 17 00:00:00 2001 From: Arnaud Porterie Date: Fri, 6 Mar 2015 17:39:32 -0800 Subject: [PATCH 05/37] Remove subdirectories MAINTAINERS files Signed-off-by: Arnaud Porterie --- reexec/MAINTAINERS | 1 - 1 file changed, 1 deletion(-) delete mode 100644 reexec/MAINTAINERS diff --git a/reexec/MAINTAINERS b/reexec/MAINTAINERS deleted file mode 100644 index e48a0c7..0000000 --- a/reexec/MAINTAINERS +++ /dev/null @@ -1 +0,0 @@ -Michael Crosby (@crosbymichael) From 55f55ca439e54fdfdb20a7a073c603a1fb6d4c5c Mon Sep 17 00:00:00 2001 From: Phil Estes Date: Mon, 16 Mar 2015 15:54:35 -0400 Subject: [PATCH 06/37] Fix relative path execution of docker daemon in reexec.Self() After the new libcontainer API, the reexec.Self() output of the daemon binary is used as the libcontainer factory InitPath. If it is relative, it can't be found at container start time. This patch solves the problem by making sure that we return a rooted/absolute path if a relative path is used. Docker-DCO-1.1-Signed-off-by: Phil Estes (github: estesp) --- reexec/reexec.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/reexec/reexec.go b/reexec/reexec.go index 774e71c..a5f01a2 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -35,8 +35,14 @@ func Self() string { name := os.Args[0] if filepath.Base(name) == name { if lp, err := exec.LookPath(name); err == nil { - name = lp + return lp } } + // handle conversion of relative paths to absolute + if absName, err := filepath.Abs(name); err == nil { + return absName + } + // if we coudn't get absolute name, return original + // (NOTE: Go only errors on Abs() if os.Getwd fails) return name } From 1d39072914274b1a5b0496e7ed4f637dd416c222 Mon Sep 17 00:00:00 2001 From: John Howard Date: Fri, 8 May 2015 14:15:53 -0700 Subject: [PATCH 07/37] Windows: reexec pkg supported Signed-off-by: John Howard --- reexec/command_unsupported.go | 2 +- reexec/command_windows.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 reexec/command_windows.go diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index a579318..4adcd8f 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux,!windows package reexec diff --git a/reexec/command_windows.go b/reexec/command_windows.go new file mode 100644 index 0000000..124d42f --- /dev/null +++ b/reexec/command_windows.go @@ -0,0 +1,14 @@ +// +build windows + +package reexec + +import ( + "os/exec" +) + +func Command(args ...string) *exec.Cmd { + return &exec.Cmd{ + Path: Self(), + Args: args, + } +} From df6d9346ab5f8f517475db72151cdb2c70188a65 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Mon, 20 Jul 2015 10:16:37 -0700 Subject: [PATCH 08/37] Add docstring to reexec.Command Signed-off-by: Alexander Morozov --- reexec/command_linux.go | 4 ++++ reexec/command_unsupported.go | 1 + reexec/command_windows.go | 3 +++ 3 files changed, 8 insertions(+) diff --git a/reexec/command_linux.go b/reexec/command_linux.go index 8dc3f3a..e22a023 100644 --- a/reexec/command_linux.go +++ b/reexec/command_linux.go @@ -7,6 +7,10 @@ import ( "syscall" ) +// Command returns *exec.Cmd which have Path as current binary. Also it setting +// SysProcAttr.Pdeathsig to SIGTERM. +// For example if current binary is "docker" at "/usr/bin", then cmd.Path will +// be set to "/usr/bin/docker". func Command(args ...string) *exec.Cmd { return &exec.Cmd{ Path: Self(), diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index 4adcd8f..630eecb 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -6,6 +6,7 @@ import ( "os/exec" ) +// Command is unsupported on operating systems apart from Linux and Windows. func Command(args ...string) *exec.Cmd { return nil } diff --git a/reexec/command_windows.go b/reexec/command_windows.go index 124d42f..a2a7aa9 100644 --- a/reexec/command_windows.go +++ b/reexec/command_windows.go @@ -6,6 +6,9 @@ import ( "os/exec" ) +// Command returns *exec.Cmd which have Path as current binary. +// For example if current binary is "docker.exe" at "C:\", then cmd.Path will +// be set to "C:\docker.exe". func Command(args ...string) *exec.Cmd { return &exec.Cmd{ Path: Self(), From 33dc5c6b6cdd80265b34dc1d00c7dfa0ba719db9 Mon Sep 17 00:00:00 2001 From: Tibor Vass Date: Fri, 24 Jul 2015 13:51:51 -0400 Subject: [PATCH 09/37] reexec: Use in-memory binary on linux instead of os.Args[0] This keeps reexec working properly even if the on-disk binary was replaced. Signed-off-by: Tibor Vass --- reexec/command_linux.go | 10 ++++++++-- reexec/command_windows.go | 6 ++++++ reexec/reexec.go | 3 +-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/reexec/command_linux.go b/reexec/command_linux.go index e22a023..3c3a73a 100644 --- a/reexec/command_linux.go +++ b/reexec/command_linux.go @@ -7,10 +7,16 @@ import ( "syscall" ) +// Self returns the path to the current process's binary. +// Returns "/proc/self/exe". +func Self() string { + return "/proc/self/exe" +} + // Command returns *exec.Cmd which have Path as current binary. Also it setting // SysProcAttr.Pdeathsig to SIGTERM. -// For example if current binary is "docker" at "/usr/bin", then cmd.Path will -// be set to "/usr/bin/docker". +// This will use the in-memory version (/proc/self/exe) of the current binary, +// it is thus safe to delete or replace the on-disk binary (os.Args[0]). func Command(args ...string) *exec.Cmd { return &exec.Cmd{ Path: Self(), diff --git a/reexec/command_windows.go b/reexec/command_windows.go index a2a7aa9..8d65e0a 100644 --- a/reexec/command_windows.go +++ b/reexec/command_windows.go @@ -6,6 +6,12 @@ import ( "os/exec" ) +// Self returns the path to the current process's binary. +// Uses os.Args[0]. +func Self() string { + return naiveSelf() +} + // Command returns *exec.Cmd which have Path as current binary. // For example if current binary is "docker.exe" at "C:\", then cmd.Path will // be set to "C:\docker.exe". diff --git a/reexec/reexec.go b/reexec/reexec.go index a5f01a2..20491e0 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -30,8 +30,7 @@ func Init() bool { return false } -// Self returns the path to the current processes binary -func Self() string { +func naiveSelf() string { name := os.Args[0] if filepath.Base(name) == name { if lp, err := exec.LookPath(name); err == nil { From 38dfb8e5789aac4fa2177ba0629c6be70e592418 Mon Sep 17 00:00:00 2001 From: Alexey Guskov Date: Wed, 29 Jul 2015 21:25:56 +0300 Subject: [PATCH 10/37] make docker compile on freebsd Signed-off-by: Alexey Guskov --- reexec/command_freebsd.go | 23 +++++++++++++++++++++++ reexec/command_unsupported.go | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 reexec/command_freebsd.go diff --git a/reexec/command_freebsd.go b/reexec/command_freebsd.go new file mode 100644 index 0000000..c7f797a --- /dev/null +++ b/reexec/command_freebsd.go @@ -0,0 +1,23 @@ +// +build freebsd + +package reexec + +import ( + "os/exec" +) + +// Self returns the path to the current process's binary. +// Uses os.Args[0]. +func Self() string { + return naiveSelf() +} + +// Command returns *exec.Cmd which have Path as current binary. +// For example if current binary is "docker" at "/usr/bin/", then cmd.Path will +// be set to "/usr/bin/docker". +func Command(args ...string) *exec.Cmd { + return &exec.Cmd{ + Path: Self(), + Args: args, + } +} diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index 630eecb..ad4ea38 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows +// +build !linux,!windows,!freebsd package reexec From fcaaf3ca14ef0382c5192fdba118df1d0e9275e8 Mon Sep 17 00:00:00 2001 From: Justas Brazauskas Date: Sun, 13 Dec 2015 18:00:39 +0200 Subject: [PATCH 11/37] Fix typos found across repository Signed-off-by: Justas Brazauskas --- reexec/reexec.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reexec/reexec.go b/reexec/reexec.go index 20491e0..ceb98d2 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -41,7 +41,7 @@ func naiveSelf() string { if absName, err := filepath.Abs(name); err == nil { return absName } - // if we coudn't get absolute name, return original + // if we couldn't get absolute name, return original // (NOTE: Go only errors on Abs() if os.Getwd fails) return name } From 134408b70f00be58cd89c3d43ed30751e0024a77 Mon Sep 17 00:00:00 2001 From: allencloud Date: Sat, 9 Apr 2016 21:18:15 +0800 Subject: [PATCH 12/37] fix typos in pkg Signed-off-by: allencloud --- reexec/reexec.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reexec/reexec.go b/reexec/reexec.go index ceb98d2..c56671d 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -12,7 +12,7 @@ var registeredInitializers = make(map[string]func()) // Register adds an initialization func under the specified name func Register(name string, initializer func()) { if _, exists := registeredInitializers[name]; exists { - panic(fmt.Sprintf("reexec func already registred under name %q", name)) + panic(fmt.Sprintf("reexec func already registered under name %q", name)) } registeredInitializers[name] = initializer From 77f98aaa2ccf9135542bdc748c6e21679c703cd5 Mon Sep 17 00:00:00 2001 From: Amit Krishnan Date: Fri, 25 Mar 2016 16:38:00 -0700 Subject: [PATCH 13/37] Get the Docker Engine to build clean on Solaris Signed-off-by: Amit Krishnan --- reexec/{command_freebsd.go => command_unix.go} | 2 +- reexec/command_unsupported.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename reexec/{command_freebsd.go => command_unix.go} (94%) diff --git a/reexec/command_freebsd.go b/reexec/command_unix.go similarity index 94% rename from reexec/command_freebsd.go rename to reexec/command_unix.go index c7f797a..b70edcb 100644 --- a/reexec/command_freebsd.go +++ b/reexec/command_unix.go @@ -1,4 +1,4 @@ -// +build freebsd +// +build freebsd solaris package reexec diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index ad4ea38..9aed004 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows,!freebsd +// +build !linux,!windows,!freebsd,!solaris package reexec From 7bec6e99f689886b582c3c86f2bc500221af50a4 Mon Sep 17 00:00:00 2001 From: allencloud Date: Tue, 2 Aug 2016 10:06:38 +0800 Subject: [PATCH 14/37] make more pkgs support darwin Signed-off-by: allencloud --- reexec/command_linux.go | 2 +- reexec/command_unix.go | 4 ++-- reexec/command_unsupported.go | 4 ++-- reexec/command_windows.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/reexec/command_linux.go b/reexec/command_linux.go index 3c3a73a..34ae2a9 100644 --- a/reexec/command_linux.go +++ b/reexec/command_linux.go @@ -13,7 +13,7 @@ func Self() string { return "/proc/self/exe" } -// Command returns *exec.Cmd which have Path as current binary. Also it setting +// Command returns *exec.Cmd which has Path as current binary. Also it setting // SysProcAttr.Pdeathsig to SIGTERM. // This will use the in-memory version (/proc/self/exe) of the current binary, // it is thus safe to delete or replace the on-disk binary (os.Args[0]). diff --git a/reexec/command_unix.go b/reexec/command_unix.go index b70edcb..778a720 100644 --- a/reexec/command_unix.go +++ b/reexec/command_unix.go @@ -1,4 +1,4 @@ -// +build freebsd solaris +// +build freebsd solaris darwin package reexec @@ -12,7 +12,7 @@ func Self() string { return naiveSelf() } -// Command returns *exec.Cmd which have Path as current binary. +// Command returns *exec.Cmd which has Path as current binary. // For example if current binary is "docker" at "/usr/bin/", then cmd.Path will // be set to "/usr/bin/docker". func Command(args ...string) *exec.Cmd { diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index 9aed004..76edd82 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows,!freebsd,!solaris +// +build !linux,!windows,!freebsd,!solaris,!darwin package reexec @@ -6,7 +6,7 @@ import ( "os/exec" ) -// Command is unsupported on operating systems apart from Linux and Windows. +// Command is unsupported on operating systems apart from Linux, Windows, Solaris and Darwin. func Command(args ...string) *exec.Cmd { return nil } diff --git a/reexec/command_windows.go b/reexec/command_windows.go index 8d65e0a..ca871c4 100644 --- a/reexec/command_windows.go +++ b/reexec/command_windows.go @@ -12,7 +12,7 @@ func Self() string { return naiveSelf() } -// Command returns *exec.Cmd which have Path as current binary. +// Command returns *exec.Cmd which has Path as current binary. // For example if current binary is "docker.exe" at "C:\", then cmd.Path will // be set to "C:\docker.exe". func Command(args ...string) *exec.Cmd { From facc73ba2a05e267034a9953e266db0b15e6cd24 Mon Sep 17 00:00:00 2001 From: yupeng Date: Mon, 21 Nov 2016 17:08:28 +0800 Subject: [PATCH 15/37] First header should be a top level header Signed-off-by: yupeng --- reexec/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reexec/README.md b/reexec/README.md index 45592ce..6658f69 100644 --- a/reexec/README.md +++ b/reexec/README.md @@ -1,4 +1,4 @@ -## reexec +# reexec The `reexec` package facilitates the busybox style reexec of the docker binary that we require because of the forking limitations of using Go. Handlers can be registered with a name and the argv 0 of From 3e89381b30af739e6ac019e176318b11522cb39f Mon Sep 17 00:00:00 2001 From: Naveed Jamil Date: Thu, 1 Jun 2017 16:58:10 +0500 Subject: [PATCH 16/37] Added Test Case Coverage for PKG/REEXEC Signed-off-by: Naveed Jamil --- reexec/reexec_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 reexec/reexec_test.go diff --git a/reexec/reexec_test.go b/reexec/reexec_test.go new file mode 100644 index 0000000..39e87a4 --- /dev/null +++ b/reexec/reexec_test.go @@ -0,0 +1,53 @@ +package reexec + +import ( + "os" + "os/exec" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func init() { + Register("reexec", func() { + panic("Return Error") + }) + Init() +} + +func TestRegister(t *testing.T) { + defer func() { + if r := recover(); r != nil { + require.Equal(t, `reexec func already registered under name "reexec"`, r) + } + }() + Register("reexec", func() {}) +} + +func TestCommand(t *testing.T) { + cmd := Command("reexec") + w, err := cmd.StdinPipe() + require.NoError(t, err, "Error on pipe creation: %v", err) + defer w.Close() + + err = cmd.Start() + require.NoError(t, err, "Error on re-exec cmd: %v", err) + err = cmd.Wait() + require.EqualError(t, err, "exit status 2") +} + +func TestNaiveSelf(t *testing.T) { + if os.Getenv("TEST_CHECK") == "1" { + os.Exit(2) + } + cmd := exec.Command(naiveSelf(), "-test.run=TestNaiveSelf") + cmd.Env = append(os.Environ(), "TEST_CHECK=1") + err := cmd.Start() + require.NoError(t, err, "Unable to start command") + err = cmd.Wait() + require.EqualError(t, err, "exit status 2") + + os.Args[0] = "mkdir" + assert.NotEqual(t, naiveSelf(), os.Args[0]) +} From e8e1ff459c98c757365241d1f3bed9ee91188621 Mon Sep 17 00:00:00 2001 From: Christopher Jones Date: Tue, 23 May 2017 10:22:32 -0400 Subject: [PATCH 17/37] [project] change syscall to /x/sys/unix|windows Changes most references of syscall to golang.org/x/sys/ Ones aren't changes include, Errno, Signal and SysProcAttr as they haven't been implemented in /x/sys/. Signed-off-by: Christopher Jones [s390x] switch utsname from unsigned to signed per https://github.com/golang/sys/commit/33267e036fd93fcd26ea95b7bdaf2d8306cb743c char in s390x in the /x/sys/unix package is now signed, so change the buildtags Signed-off-by: Christopher Jones --- reexec/command_linux.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/reexec/command_linux.go b/reexec/command_linux.go index 34ae2a9..05319ea 100644 --- a/reexec/command_linux.go +++ b/reexec/command_linux.go @@ -5,6 +5,8 @@ package reexec import ( "os/exec" "syscall" + + "golang.org/x/sys/unix" ) // Self returns the path to the current process's binary. @@ -22,7 +24,7 @@ func Command(args ...string) *exec.Cmd { Path: Self(), Args: args, SysProcAttr: &syscall.SysProcAttr{ - Pdeathsig: syscall.SIGTERM, + Pdeathsig: unix.SIGTERM, }, } } From 6da380e3339ed959413719e25528f777be6ee054 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Wed, 1 Nov 2017 23:37:53 +0000 Subject: [PATCH 18/37] Remove solaris build tag and `contrib/mkimage/solaris Signed-off-by: Yong Tang --- reexec/command_unix.go | 2 +- reexec/command_unsupported.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/reexec/command_unix.go b/reexec/command_unix.go index 778a720..55c0c97 100644 --- a/reexec/command_unix.go +++ b/reexec/command_unix.go @@ -1,4 +1,4 @@ -// +build freebsd solaris darwin +// +build freebsd darwin package reexec diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index 76edd82..6f5e55d 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!windows,!freebsd,!solaris,!darwin +// +build !linux,!windows,!freebsd,!darwin package reexec @@ -6,7 +6,7 @@ import ( "os/exec" ) -// Command is unsupported on operating systems apart from Linux, Windows, Solaris and Darwin. +// Command is unsupported on operating systems apart from Linux, Windows, and Darwin. func Command(args ...string) *exec.Cmd { return nil } From 0671a46319b92253ce00d3d37b462d8c72b8f691 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 18 Dec 2017 17:41:53 +0100 Subject: [PATCH 19/37] Remove redundant build-tags Files that are suffixed with `_linux.go` or `_windows.go` are already only built on Linux / Windows, so these build-tags were redundant. Signed-off-by: Sebastiaan van Stijn --- reexec/command_linux.go | 2 -- reexec/command_windows.go | 2 -- 2 files changed, 4 deletions(-) diff --git a/reexec/command_linux.go b/reexec/command_linux.go index 05319ea..d3f1061 100644 --- a/reexec/command_linux.go +++ b/reexec/command_linux.go @@ -1,5 +1,3 @@ -// +build linux - package reexec import ( diff --git a/reexec/command_windows.go b/reexec/command_windows.go index ca871c4..c320876 100644 --- a/reexec/command_windows.go +++ b/reexec/command_windows.go @@ -1,5 +1,3 @@ -// +build windows - package reexec import ( From 511eeb3253131c0291453e31c645bc2ed9249690 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 5 Feb 2018 16:05:59 -0500 Subject: [PATCH 20/37] Add canonical import comment Signed-off-by: Daniel Nephin --- reexec/command_linux.go | 2 +- reexec/command_unix.go | 2 +- reexec/command_unsupported.go | 2 +- reexec/command_windows.go | 2 +- reexec/reexec.go | 2 +- reexec/reexec_test.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/reexec/command_linux.go b/reexec/command_linux.go index d3f1061..efea717 100644 --- a/reexec/command_linux.go +++ b/reexec/command_linux.go @@ -1,4 +1,4 @@ -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "os/exec" diff --git a/reexec/command_unix.go b/reexec/command_unix.go index 55c0c97..ceaabbd 100644 --- a/reexec/command_unix.go +++ b/reexec/command_unix.go @@ -1,6 +1,6 @@ // +build freebsd darwin -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "os/exec" diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index 6f5e55d..09fb4b2 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -1,6 +1,6 @@ // +build !linux,!windows,!freebsd,!darwin -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "os/exec" diff --git a/reexec/command_windows.go b/reexec/command_windows.go index c320876..4382268 100644 --- a/reexec/command_windows.go +++ b/reexec/command_windows.go @@ -1,4 +1,4 @@ -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "os/exec" diff --git a/reexec/reexec.go b/reexec/reexec.go index c56671d..f8ccddd 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -1,4 +1,4 @@ -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "fmt" diff --git a/reexec/reexec_test.go b/reexec/reexec_test.go index 39e87a4..e6bbe9f 100644 --- a/reexec/reexec_test.go +++ b/reexec/reexec_test.go @@ -1,4 +1,4 @@ -package reexec +package reexec // import "github.com/docker/docker/pkg/reexec" import ( "os" From 2b5c7fd61563562f86a987bed4f571e43baf44c3 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 13 Mar 2018 15:28:34 -0400 Subject: [PATCH 21/37] Automated migration using gty-migrate-from-testify --ignore-build-tags Signed-off-by: Daniel Nephin --- reexec/reexec_test.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/reexec/reexec_test.go b/reexec/reexec_test.go index e6bbe9f..90aa01a 100644 --- a/reexec/reexec_test.go +++ b/reexec/reexec_test.go @@ -5,8 +5,7 @@ import ( "os/exec" "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/gotestyourself/gotestyourself/assert" ) func init() { @@ -19,7 +18,7 @@ func init() { func TestRegister(t *testing.T) { defer func() { if r := recover(); r != nil { - require.Equal(t, `reexec func already registered under name "reexec"`, r) + assert.Equal(t, `reexec func already registered under name "reexec"`, r) } }() Register("reexec", func() {}) @@ -28,13 +27,13 @@ func TestRegister(t *testing.T) { func TestCommand(t *testing.T) { cmd := Command("reexec") w, err := cmd.StdinPipe() - require.NoError(t, err, "Error on pipe creation: %v", err) + assert.NilError(t, err, "Error on pipe creation: %v", err) defer w.Close() err = cmd.Start() - require.NoError(t, err, "Error on re-exec cmd: %v", err) + assert.NilError(t, err, "Error on re-exec cmd: %v", err) err = cmd.Wait() - require.EqualError(t, err, "exit status 2") + assert.Error(t, err, "exit status 2") } func TestNaiveSelf(t *testing.T) { @@ -44,10 +43,10 @@ func TestNaiveSelf(t *testing.T) { cmd := exec.Command(naiveSelf(), "-test.run=TestNaiveSelf") cmd.Env = append(os.Environ(), "TEST_CHECK=1") err := cmd.Start() - require.NoError(t, err, "Unable to start command") + assert.NilError(t, err, "Unable to start command") err = cmd.Wait() - require.EqualError(t, err, "exit status 2") + assert.Error(t, err, "exit status 2") os.Args[0] = "mkdir" - assert.NotEqual(t, naiveSelf(), os.Args[0]) + assert.Check(t, naiveSelf() != os.Args[0]) } From 65fcb8a841a53d7e4d32b453cc48e4b80d050ba5 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Mon, 11 Jun 2018 15:32:11 +0200 Subject: [PATCH 22/37] =?UTF-8?q?Update=20tests=20to=20use=20gotest.tools?= =?UTF-8?q?=20=F0=9F=91=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Vincent Demeester --- reexec/reexec_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reexec/reexec_test.go b/reexec/reexec_test.go index 90aa01a..44675e7 100644 --- a/reexec/reexec_test.go +++ b/reexec/reexec_test.go @@ -5,7 +5,7 @@ import ( "os/exec" "testing" - "github.com/gotestyourself/gotestyourself/assert" + "gotest.tools/assert" ) func init() { From 69ab52c9964adbbd8f1767f40c4d1d4bd4246217 Mon Sep 17 00:00:00 2001 From: Fabian Raetz Date: Sat, 16 Jun 2018 17:53:50 +0200 Subject: [PATCH 23/37] fix build on OpenBSD by defining Self() Signed-off-by: Fabian Raetz --- reexec/command_unsupported.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index 09fb4b2..e7eed24 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -6,6 +6,10 @@ import ( "os/exec" ) +func Self() string { + return "" +} + // Command is unsupported on operating systems apart from Linux, Windows, and Darwin. func Command(args ...string) *exec.Cmd { return nil From 56c7fa4bc110d7313b10c217fe4130f3460a98cf Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 7 Feb 2020 14:39:24 +0100 Subject: [PATCH 24/37] bump gotest.tools v3.0.1 for compatibility with Go 1.14 full diff: https://github.com/gotestyourself/gotest.tools/compare/v2.3.0...v3.0.1 Signed-off-by: Sebastiaan van Stijn --- reexec/reexec_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reexec/reexec_test.go b/reexec/reexec_test.go index 44675e7..8aea043 100644 --- a/reexec/reexec_test.go +++ b/reexec/reexec_test.go @@ -5,7 +5,7 @@ import ( "os/exec" "testing" - "gotest.tools/assert" + "gotest.tools/v3/assert" ) func init() { From 1d352c3922590f573a543ab02f1ac46ef3c5f468 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 23 Aug 2021 15:14:53 +0200 Subject: [PATCH 25/37] Update to Go 1.17.0, and gofmt with Go 1.17 Signed-off-by: Sebastiaan van Stijn --- reexec/command_unix.go | 1 + reexec/command_unsupported.go | 1 + 2 files changed, 2 insertions(+) diff --git a/reexec/command_unix.go b/reexec/command_unix.go index ceaabbd..b900430 100644 --- a/reexec/command_unix.go +++ b/reexec/command_unix.go @@ -1,3 +1,4 @@ +//go:build freebsd || darwin // +build freebsd darwin package reexec // import "github.com/docker/docker/pkg/reexec" diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index e7eed24..7175853 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux && !windows && !freebsd && !darwin // +build !linux,!windows,!freebsd,!darwin package reexec // import "github.com/docker/docker/pkg/reexec" From cbbb71345f5e1b8da8dabd1b903c609a21f32cb5 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 30 Sep 2022 17:11:37 +0200 Subject: [PATCH 26/37] pkg: replace some README's with GoDoc package descriptions Signed-off-by: Sebastiaan van Stijn --- reexec/README.md | 5 ----- reexec/reexec.go | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 reexec/README.md diff --git a/reexec/README.md b/reexec/README.md deleted file mode 100644 index 6658f69..0000000 --- a/reexec/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# reexec - -The `reexec` package facilitates the busybox style reexec of the docker binary that we require because -of the forking limitations of using Go. Handlers can be registered with a name and the argv 0 of -the exec of the binary will be used to find and execute custom init paths. diff --git a/reexec/reexec.go b/reexec/reexec.go index f8ccddd..54e934c 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -1,3 +1,7 @@ +// Package reexec facilitates the busybox style reexec of the docker binary that +// we require because of the forking limitations of using Go. Handlers can be +// registered with a name and the argv 0 of the exec of the binary will be used +// to find and execute custom init paths. package reexec // import "github.com/docker/docker/pkg/reexec" import ( From f8c97e7783115f9182b23d626b94273a60393dbe Mon Sep 17 00:00:00 2001 From: Cory Snider Date: Wed, 28 Sep 2022 13:33:53 -0400 Subject: [PATCH 27/37] Lock OS threads when exec'ing with Pdeathsig On Linux, when (os/exec.Cmd).SysProcAttr.Pdeathsig is set, the signal will be sent to the process when the OS thread on which cmd.Start() was executed dies. The runtime terminates an OS thread when a goroutine exits after being wired to the thread with runtime.LockOSThread(). If other goroutines are allowed to be scheduled onto a thread which called cmd.Start(), an unrelated goroutine could cause the thread to be terminated and prematurely signal the command. See https://github.com/golang/go/issues/27505 for more information. Prevent started subprocesses with Pdeathsig from getting signaled prematurely by wiring the starting goroutine to the OS thread until the subprocess has exited. No other goroutines can be scheduled onto a locked thread so it will remain alive until unlocked or the daemon process exits. Signed-off-by: Cory Snider --- reexec/command_linux.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/reexec/command_linux.go b/reexec/command_linux.go index efea717..d7ec3d6 100644 --- a/reexec/command_linux.go +++ b/reexec/command_linux.go @@ -17,6 +17,11 @@ func Self() string { // SysProcAttr.Pdeathsig to SIGTERM. // This will use the in-memory version (/proc/self/exe) of the current binary, // it is thus safe to delete or replace the on-disk binary (os.Args[0]). +// +// As SysProcAttr.Pdeathsig is set, the signal will be sent to the process when +// the OS thread which created the process dies. It is the caller's +// responsibility to ensure that the creating thread is not terminated +// prematurely. See https://go.dev/issue/27505 for more details. func Command(args ...string) *exec.Cmd { return &exec.Cmd{ Path: Self(), From 9a84e50e6304dff9bbd98d6cbd2d2191d4b1e1af Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 5 May 2023 17:59:39 +0200 Subject: [PATCH 28/37] remove pre-go1.17 build-tags Removed pre-go1.17 build-tags with go fix; go mod init go fix -mod=readonly ./... rm go.mod Signed-off-by: Sebastiaan van Stijn --- reexec/command_unix.go | 1 - reexec/command_unsupported.go | 1 - 2 files changed, 2 deletions(-) diff --git a/reexec/command_unix.go b/reexec/command_unix.go index b900430..0df5195 100644 --- a/reexec/command_unix.go +++ b/reexec/command_unix.go @@ -1,5 +1,4 @@ //go:build freebsd || darwin -// +build freebsd darwin package reexec // import "github.com/docker/docker/pkg/reexec" diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index 7175853..bec9761 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -1,5 +1,4 @@ //go:build !linux && !windows && !freebsd && !darwin -// +build !linux,!windows,!freebsd,!darwin package reexec // import "github.com/docker/docker/pkg/reexec" From 8cdd031c70e6f0b5d1a061e9e773dec9b3f3c8c9 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sat, 8 Jun 2024 12:24:57 +0200 Subject: [PATCH 29/37] pkg/reexec: don't mix syscall and golang.org/x/sys package commit e8e1ff459c98c757365241d1f3bed9ee91188621 changed most uses of the syscall package to switch utsname from unsigned to signed (see e8e1ff459c98c757365241d1f3bed9ee91188621). Those don't seem to be impacting the code used here, so either stdlib or golang.org/x/sys/unix should work for this case. I chose stdlib's syscall package for this case, in case we'd decide to move this package to a separate module (and want to limit its dependencies). Signed-off-by: Sebastiaan van Stijn --- reexec/command_linux.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/reexec/command_linux.go b/reexec/command_linux.go index d7ec3d6..833f8c6 100644 --- a/reexec/command_linux.go +++ b/reexec/command_linux.go @@ -3,8 +3,6 @@ package reexec // import "github.com/docker/docker/pkg/reexec" import ( "os/exec" "syscall" - - "golang.org/x/sys/unix" ) // Self returns the path to the current process's binary. @@ -27,7 +25,7 @@ func Command(args ...string) *exec.Cmd { Path: Self(), Args: args, SysProcAttr: &syscall.SysProcAttr{ - Pdeathsig: unix.SIGTERM, + Pdeathsig: syscall.SIGTERM, }, } } From b537da6cf46d1b0d073c44a87b242e97baf73129 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sat, 8 Jun 2024 12:59:10 +0200 Subject: [PATCH 30/37] pkg/reexec: unify implementation of Self() and remove stub This combines the implementations of the Self function, to allow having a single GoDoc to document the behavior. The naiveSelf function is kept, because it's used in unit-tests. There is a minor change in behavior, as this patch removes the stub for unsupported platforms (non-linux, windows, freebsd or darwin), which will now use `os.Args[0]`. The stub was added in 69ab52c9964adbbd8f1767f40c4d1d4bd4246217 to fix compilation of https://github.com/ethereum/go-ethereum on OpenBSD, which had docker/docker as dependency. It looks like that repository no longer has this dependency, and as this was only to make the code compilable, is unlikely to be a problem. Signed-off-by: Sebastiaan van Stijn --- reexec/command_linux.go | 6 ------ reexec/command_unix.go | 6 ------ reexec/command_unsupported.go | 4 ---- reexec/command_windows.go | 6 ------ reexec/reexec.go | 12 ++++++++++++ 5 files changed, 12 insertions(+), 22 deletions(-) diff --git a/reexec/command_linux.go b/reexec/command_linux.go index 833f8c6..791d14c 100644 --- a/reexec/command_linux.go +++ b/reexec/command_linux.go @@ -5,12 +5,6 @@ import ( "syscall" ) -// Self returns the path to the current process's binary. -// Returns "/proc/self/exe". -func Self() string { - return "/proc/self/exe" -} - // Command returns *exec.Cmd which has Path as current binary. Also it setting // SysProcAttr.Pdeathsig to SIGTERM. // This will use the in-memory version (/proc/self/exe) of the current binary, diff --git a/reexec/command_unix.go b/reexec/command_unix.go index 0df5195..39386bc 100644 --- a/reexec/command_unix.go +++ b/reexec/command_unix.go @@ -6,12 +6,6 @@ import ( "os/exec" ) -// Self returns the path to the current process's binary. -// Uses os.Args[0]. -func Self() string { - return naiveSelf() -} - // Command returns *exec.Cmd which has Path as current binary. // For example if current binary is "docker" at "/usr/bin/", then cmd.Path will // be set to "/usr/bin/docker". diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index bec9761..49ef0b1 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -6,10 +6,6 @@ import ( "os/exec" ) -func Self() string { - return "" -} - // Command is unsupported on operating systems apart from Linux, Windows, and Darwin. func Command(args ...string) *exec.Cmd { return nil diff --git a/reexec/command_windows.go b/reexec/command_windows.go index 4382268..e071bef 100644 --- a/reexec/command_windows.go +++ b/reexec/command_windows.go @@ -4,12 +4,6 @@ import ( "os/exec" ) -// Self returns the path to the current process's binary. -// Uses os.Args[0]. -func Self() string { - return naiveSelf() -} - // Command returns *exec.Cmd which has Path as current binary. // For example if current binary is "docker.exe" at "C:\", then cmd.Path will // be set to "C:\docker.exe". diff --git a/reexec/reexec.go b/reexec/reexec.go index 54e934c..d5b1e2f 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -9,6 +9,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" ) var registeredInitializers = make(map[string]func()) @@ -34,6 +35,17 @@ func Init() bool { return false } +// Self returns the path to the current process's binary. On Linux, it +// returns "/proc/self/exe", which provides the in-memory version of the +// current binary, whereas on other platforms it attempts to looks up the +// absolute path for os.Args[0], or otherwise returns os.Args[0] as-is. +func Self() string { + if runtime.GOOS == "linux" { + return "/proc/self/exe" + } + return naiveSelf() +} + func naiveSelf() string { name := os.Args[0] if filepath.Base(name) == name { From f56c8ff65dc45681cadcb34616364cd560d3ca94 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sat, 8 Jun 2024 13:19:48 +0200 Subject: [PATCH 31/37] pkg/reexec: unify non-Linux implementation of Command The Windows, Darwin, and FreeBSD implementations were identical, other than their GoDoc to be different. Unify them so that we don't have to maintain separate GoDoc for each. It's worth noting that FreeBSD also supports Pdeathsig, so could be using the same implementation as Linux. However, we don't test/maintain the FreeBSD implementation, and it would require updating to GoDoc to be more specific about the use of `/proc/self/exe`, so keeping the status quo for now. Signed-off-by: Sebastiaan van Stijn --- reexec/command_other.go | 19 +++++++++++++++++++ reexec/command_unix.go | 17 ----------------- reexec/command_windows.go | 15 --------------- 3 files changed, 19 insertions(+), 32 deletions(-) create mode 100644 reexec/command_other.go delete mode 100644 reexec/command_unix.go delete mode 100644 reexec/command_windows.go diff --git a/reexec/command_other.go b/reexec/command_other.go new file mode 100644 index 0000000..b458ef2 --- /dev/null +++ b/reexec/command_other.go @@ -0,0 +1,19 @@ +//go:build freebsd || darwin || windows + +package reexec + +import ( + "os/exec" +) + +// Command returns *exec.Cmd with its Path set to the path of the current +// binary using the result of [Self]. For example if current binary is +// "my-binary" at "/usr/bin/" (or "my-binary.exe" at "C:\" on Windows), +// then cmd.Path is set to "/usr/bin/my-binary" and "C:\my-binary.exe" +// respectively. +func Command(args ...string) *exec.Cmd { + return &exec.Cmd{ + Path: Self(), + Args: args, + } +} diff --git a/reexec/command_unix.go b/reexec/command_unix.go deleted file mode 100644 index 39386bc..0000000 --- a/reexec/command_unix.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build freebsd || darwin - -package reexec // import "github.com/docker/docker/pkg/reexec" - -import ( - "os/exec" -) - -// Command returns *exec.Cmd which has Path as current binary. -// For example if current binary is "docker" at "/usr/bin/", then cmd.Path will -// be set to "/usr/bin/docker". -func Command(args ...string) *exec.Cmd { - return &exec.Cmd{ - Path: Self(), - Args: args, - } -} diff --git a/reexec/command_windows.go b/reexec/command_windows.go deleted file mode 100644 index e071bef..0000000 --- a/reexec/command_windows.go +++ /dev/null @@ -1,15 +0,0 @@ -package reexec // import "github.com/docker/docker/pkg/reexec" - -import ( - "os/exec" -) - -// Command returns *exec.Cmd which has Path as current binary. -// For example if current binary is "docker.exe" at "C:\", then cmd.Path will -// be set to "C:\docker.exe". -func Command(args ...string) *exec.Cmd { - return &exec.Cmd{ - Path: Self(), - Args: args, - } -} From 3779b01b07bd5179f53aec7d8aae809b599041b5 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sat, 8 Jun 2024 13:57:42 +0200 Subject: [PATCH 32/37] pkg/reexec: remove gotest.tools from tests This package is used in BuildKit, and could be a potential candidate for moving to a separate module. While it's not too problematic to have this dependency, the tests only used basic assertions from gotest.tools, which could be easily re-implemented without the dependency. Signed-off-by: Sebastiaan van Stijn --- reexec/reexec_test.go | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/reexec/reexec_test.go b/reexec/reexec_test.go index 8aea043..c250239 100644 --- a/reexec/reexec_test.go +++ b/reexec/reexec_test.go @@ -4,8 +4,6 @@ import ( "os" "os/exec" "testing" - - "gotest.tools/v3/assert" ) func init() { @@ -18,7 +16,10 @@ func init() { func TestRegister(t *testing.T) { defer func() { if r := recover(); r != nil { - assert.Equal(t, `reexec func already registered under name "reexec"`, r) + const expected = `reexec func already registered under name "reexec"` + if r != expected { + t.Errorf("got %q, want %q", r, expected) + } } }() Register("reexec", func() {}) @@ -27,13 +28,20 @@ func TestRegister(t *testing.T) { func TestCommand(t *testing.T) { cmd := Command("reexec") w, err := cmd.StdinPipe() - assert.NilError(t, err, "Error on pipe creation: %v", err) + if err != nil { + t.Fatalf("Error on pipe creation: %v", err) + } defer w.Close() err = cmd.Start() - assert.NilError(t, err, "Error on re-exec cmd: %v", err) + if err != nil { + t.Fatalf("Error on re-exec cmd: %v", err) + } err = cmd.Wait() - assert.Error(t, err, "exit status 2") + const expected = "exit status 2" + if err == nil || err.Error() != expected { + t.Fatalf("got %v, want %v", err, expected) + } } func TestNaiveSelf(t *testing.T) { @@ -43,10 +51,17 @@ func TestNaiveSelf(t *testing.T) { cmd := exec.Command(naiveSelf(), "-test.run=TestNaiveSelf") cmd.Env = append(os.Environ(), "TEST_CHECK=1") err := cmd.Start() - assert.NilError(t, err, "Unable to start command") + if err != nil { + t.Fatalf("Unable to start command: %v", err) + } err = cmd.Wait() - assert.Error(t, err, "exit status 2") + const expected = "exit status 2" + if err == nil || err.Error() != expected { + t.Fatalf("got %v, want %v", err, expected) + } os.Args[0] = "mkdir" - assert.Check(t, naiveSelf() != os.Args[0]) + if naiveSelf() == os.Args[0] { + t.Fatalf("Expected naiveSelf to resolve the location of mkdir") + } } From 663c5948ce9d76af2d1aaf90b54d09481782ef3e Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sat, 8 Jun 2024 14:14:37 +0200 Subject: [PATCH 33/37] pkg/reexec: touch-up GoDoc, and remove "import" comments Touch-up some GoDoc in the package, and remove "import" comments. This package is used in BuildKit, and could be a potential candidate for moving to a separate module. The "import" comments are ignored when used in go module mode so have little benefit. Let's remove them. Signed-off-by: Sebastiaan van Stijn --- reexec/command_linux.go | 19 ++++++++++--------- reexec/command_unsupported.go | 2 +- reexec/reexec.go | 19 ++++++++++--------- reexec/reexec_test.go | 2 +- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/reexec/command_linux.go b/reexec/command_linux.go index 791d14c..952633c 100644 --- a/reexec/command_linux.go +++ b/reexec/command_linux.go @@ -1,19 +1,20 @@ -package reexec // import "github.com/docker/docker/pkg/reexec" +package reexec import ( "os/exec" "syscall" ) -// Command returns *exec.Cmd which has Path as current binary. Also it setting -// SysProcAttr.Pdeathsig to SIGTERM. -// This will use the in-memory version (/proc/self/exe) of the current binary, -// it is thus safe to delete or replace the on-disk binary (os.Args[0]). +// Command returns an [*exec.Cmd] which has Path as current binary which, +// on Linux, is set to the in-memory version (/proc/self/exe) of the current +// binary, it is thus safe to delete or replace the on-disk binary (os.Args[0]). // -// As SysProcAttr.Pdeathsig is set, the signal will be sent to the process when -// the OS thread which created the process dies. It is the caller's -// responsibility to ensure that the creating thread is not terminated -// prematurely. See https://go.dev/issue/27505 for more details. +// On Linux, the Pdeathsig of [*exec.Cmd.SysProcAttr] is set to SIGTERM. +// This signal will be sent to the process when the OS thread which created +// the process dies. +// +// It is the caller's responsibility to ensure that the creating thread is +// not terminated prematurely. See https://go.dev/issue/27505 for more details. func Command(args ...string) *exec.Cmd { return &exec.Cmd{ Path: Self(), diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go index 49ef0b1..3e98b98 100644 --- a/reexec/command_unsupported.go +++ b/reexec/command_unsupported.go @@ -1,6 +1,6 @@ //go:build !linux && !windows && !freebsd && !darwin -package reexec // import "github.com/docker/docker/pkg/reexec" +package reexec import ( "os/exec" diff --git a/reexec/reexec.go b/reexec/reexec.go index d5b1e2f..b9d11a2 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -1,8 +1,10 @@ -// Package reexec facilitates the busybox style reexec of the docker binary that -// we require because of the forking limitations of using Go. Handlers can be -// registered with a name and the argv 0 of the exec of the binary will be used -// to find and execute custom init paths. -package reexec // import "github.com/docker/docker/pkg/reexec" +// Package reexec facilitates the busybox style reexec of a binary. +// +// Handlers can be registered with a name and the argv 0 of the exec of +// the binary will be used to find and execute custom init paths. +// +// It is used in dockerd to work around forking limitations when using Go. +package reexec import ( "fmt" @@ -14,7 +16,8 @@ import ( var registeredInitializers = make(map[string]func()) -// Register adds an initialization func under the specified name +// Register adds an initialization func under the specified name. It panics +// if the given name is already registered. func Register(name string, initializer func()) { if _, exists := registeredInitializers[name]; exists { panic(fmt.Sprintf("reexec func already registered under name %q", name)) @@ -26,10 +29,8 @@ func Register(name string, initializer func()) { // Init is called as the first part of the exec process and returns true if an // initialization function was called. func Init() bool { - initializer, exists := registeredInitializers[os.Args[0]] - if exists { + if initializer, ok := registeredInitializers[os.Args[0]]; ok { initializer() - return true } return false diff --git a/reexec/reexec_test.go b/reexec/reexec_test.go index c250239..5290c2a 100644 --- a/reexec/reexec_test.go +++ b/reexec/reexec_test.go @@ -1,4 +1,4 @@ -package reexec // import "github.com/docker/docker/pkg/reexec" +package reexec import ( "os" From 72716af01524c4cf58cd99b8b131b7f320f69550 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 17 Dec 2024 10:12:30 +0100 Subject: [PATCH 34/37] pkg/reexec: use const for name of test binary Also use a slightly different name, because "reexec" is used so widely as term in this package, making it somewhat confusing. Signed-off-by: Sebastiaan van Stijn --- reexec/reexec_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/reexec/reexec_test.go b/reexec/reexec_test.go index 5290c2a..0230cad 100644 --- a/reexec/reexec_test.go +++ b/reexec/reexec_test.go @@ -6,8 +6,10 @@ import ( "testing" ) +const testReExec = "test-reexec" + func init() { - Register("reexec", func() { + Register(testReExec, func() { panic("Return Error") }) Init() @@ -16,17 +18,17 @@ func init() { func TestRegister(t *testing.T) { defer func() { if r := recover(); r != nil { - const expected = `reexec func already registered under name "reexec"` + const expected = `reexec func already registered under name "test-reexec"` if r != expected { t.Errorf("got %q, want %q", r, expected) } } }() - Register("reexec", func() {}) + Register(testReExec, func() {}) } func TestCommand(t *testing.T) { - cmd := Command("reexec") + cmd := Command(testReExec) w, err := cmd.StdinPipe() if err != nil { t.Fatalf("Error on pipe creation: %v", err) From bae1ccafd355cca7de33c1c154fb16e06f86f34e Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 17 Dec 2024 10:46:07 +0100 Subject: [PATCH 35/37] pkg/reexec: make platform-agnostic (again) The reexec package originally was platform-agnostic, but gained some Linux-specific handling in 3223844c2830465c8517faa947f994a1e66cc0b1. When Windows support was implemented in Docker, the pkg/reexec package was adjusted accordingly in 1d39072914274b1a5b0496e7ed4f637dd416c222, which now made the package with with either Linux or Windows, with various other platforms (freebsd, solaris, darwin) being added back in separate changes. Based on the history above, this package should be platform-agnostic, except for Linux-specific changes introduced in 3223844c2830465c8517faa947f994a1e66cc0b1 and 33dc5c6b6cdd80265b34dc1d00c7dfa0ba719db9. This patch: - removes the stub-implementation to make it functional on other platforms. - renames the files for consistency Signed-off-by: Sebastiaan van Stijn --- reexec/command_unsupported.go | 12 ------------ reexec/{command_linux.go => reexec_linux.go} | 0 reexec/{command_other.go => reexec_other.go} | 2 +- 3 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 reexec/command_unsupported.go rename reexec/{command_linux.go => reexec_linux.go} (100%) rename reexec/{command_other.go => reexec_other.go} (91%) diff --git a/reexec/command_unsupported.go b/reexec/command_unsupported.go deleted file mode 100644 index 3e98b98..0000000 --- a/reexec/command_unsupported.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:build !linux && !windows && !freebsd && !darwin - -package reexec - -import ( - "os/exec" -) - -// Command is unsupported on operating systems apart from Linux, Windows, and Darwin. -func Command(args ...string) *exec.Cmd { - return nil -} diff --git a/reexec/command_linux.go b/reexec/reexec_linux.go similarity index 100% rename from reexec/command_linux.go rename to reexec/reexec_linux.go diff --git a/reexec/command_other.go b/reexec/reexec_other.go similarity index 91% rename from reexec/command_other.go rename to reexec/reexec_other.go index b458ef2..369791b 100644 --- a/reexec/command_other.go +++ b/reexec/reexec_other.go @@ -1,4 +1,4 @@ -//go:build freebsd || darwin || windows +//go:build !linux package reexec From b401831f77c8fc0ef0ef79532e8140009b2105bb Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 17 Dec 2024 10:50:55 +0100 Subject: [PATCH 36/37] pkg/reexec: Command: separate public API from implementation Move the exported `Command` to a platform-agnostic file, and un-export the platform-specific implementations. This allows us to maintain the GoDoc in a single place, describing platform-specific differences where needed. Signed-off-by: Sebastiaan van Stijn --- reexec/reexec.go | 29 ++++++++++++++++++++++++----- reexec/reexec_linux.go | 12 +----------- reexec/reexec_other.go | 7 +------ 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/reexec/reexec.go b/reexec/reexec.go index b9d11a2..c3a0c92 100644 --- a/reexec/reexec.go +++ b/reexec/reexec.go @@ -3,7 +3,7 @@ // Handlers can be registered with a name and the argv 0 of the exec of // the binary will be used to find and execute custom init paths. // -// It is used in dockerd to work around forking limitations when using Go. +// It is used to work around forking limitations when using Go. package reexec import ( @@ -36,10 +36,29 @@ func Init() bool { return false } -// Self returns the path to the current process's binary. On Linux, it -// returns "/proc/self/exe", which provides the in-memory version of the -// current binary, whereas on other platforms it attempts to looks up the -// absolute path for os.Args[0], or otherwise returns os.Args[0] as-is. +// Command returns an [*exec.Cmd] with its Path set to the path of the current +// binary using the result of [Self]. +// +// On Linux, the Pdeathsig of [*exec.Cmd.SysProcAttr] is set to SIGTERM. +// This signal is sent to the process when the OS thread that created +// the process dies. +// +// It is the caller's responsibility to ensure that the creating thread is +// not terminated prematurely. See https://go.dev/issue/27505 for more details. +func Command(args ...string) *exec.Cmd { + return command(args...) +} + +// Self returns the path to the current process's binary. +// +// On Linux, it returns "/proc/self/exe", which provides the in-memory version +// of the current binary. This makes it safe to delete or replace the on-disk +// binary (os.Args[0]). +// +// On Other platforms, it attempts to look up the absolute path for os.Args[0], +// or otherwise returns os.Args[0] as-is. For example if current binary is +// "my-binary" at "/usr/bin/" (or "my-binary.exe" at "C:\" on Windows), +// then it returns "/usr/bin/my-binary" and "C:\my-binary.exe" respectively. func Self() string { if runtime.GOOS == "linux" { return "/proc/self/exe" diff --git a/reexec/reexec_linux.go b/reexec/reexec_linux.go index 952633c..03f600e 100644 --- a/reexec/reexec_linux.go +++ b/reexec/reexec_linux.go @@ -5,17 +5,7 @@ import ( "syscall" ) -// Command returns an [*exec.Cmd] which has Path as current binary which, -// on Linux, is set to the in-memory version (/proc/self/exe) of the current -// binary, it is thus safe to delete or replace the on-disk binary (os.Args[0]). -// -// On Linux, the Pdeathsig of [*exec.Cmd.SysProcAttr] is set to SIGTERM. -// This signal will be sent to the process when the OS thread which created -// the process dies. -// -// It is the caller's responsibility to ensure that the creating thread is -// not terminated prematurely. See https://go.dev/issue/27505 for more details. -func Command(args ...string) *exec.Cmd { +func command(args ...string) *exec.Cmd { return &exec.Cmd{ Path: Self(), Args: args, diff --git a/reexec/reexec_other.go b/reexec/reexec_other.go index 369791b..498d28b 100644 --- a/reexec/reexec_other.go +++ b/reexec/reexec_other.go @@ -6,12 +6,7 @@ import ( "os/exec" ) -// Command returns *exec.Cmd with its Path set to the path of the current -// binary using the result of [Self]. For example if current binary is -// "my-binary" at "/usr/bin/" (or "my-binary.exe" at "C:\" on Windows), -// then cmd.Path is set to "/usr/bin/my-binary" and "C:\my-binary.exe" -// respectively. -func Command(args ...string) *exec.Cmd { +func command(args ...string) *exec.Cmd { return &exec.Cmd{ Path: Self(), Args: args, From fdac605103886b81a84af7b0b252b5e22b234356 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 17 Dec 2024 18:59:57 +0100 Subject: [PATCH 37/37] reexec: initialize module Signed-off-by: Sebastiaan van Stijn --- .github/workflows/test.yml | 2 +- Makefile | 2 +- reexec/go.mod | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 reexec/go.mod diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index daf5ace..50e4ae7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: run: | # This corresponds with the list in Makefile:1, but omits the "userns" # and "capability" modules, which require go1.21 as minimum. - echo 'PACKAGES=mountinfo mount sequential signal symlink user' >> $GITHUB_ENV + echo 'PACKAGES=mountinfo mount reexec sequential signal symlink user' >> $GITHUB_ENV - name: go mod tidy run: | make foreach CMD="go mod tidy" diff --git a/Makefile b/Makefile index 152b1dc..22ad5d9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PACKAGES ?= capability mountinfo mount sequential signal symlink user userns # IMPORTANT: when updating this list, also update the conditional one in .github/workflows/test.yml +PACKAGES ?= capability mountinfo mount reexec sequential signal symlink user userns # IMPORTANT: when updating this list, also update the conditional one in .github/workflows/test.yml BINDIR ?= _build/bin CROSS ?= linux/arm linux/arm64 linux/ppc64le linux/s390x \ freebsd/amd64 openbsd/amd64 darwin/amd64 darwin/arm64 windows/amd64 diff --git a/reexec/go.mod b/reexec/go.mod new file mode 100644 index 0000000..86f1160 --- /dev/null +++ b/reexec/go.mod @@ -0,0 +1,3 @@ +module github.com/moby/sys/reexec + +go 1.18