Browse code

pkg/reexec: deprecate and migrate to github.com/moby/sys/reexec

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2024/12/18 22:00:12
Showing 23 changed files
... ...
@@ -8,8 +8,8 @@ import (
8 8
 
9 9
 	winio "github.com/Microsoft/go-winio"
10 10
 	"github.com/docker/docker/pkg/idtools"
11
-	"github.com/docker/docker/pkg/reexec"
12 11
 	"github.com/docker/docker/pkg/system"
12
+	"github.com/moby/sys/reexec"
13 13
 	"github.com/pkg/errors"
14 14
 	"golang.org/x/sys/windows"
15 15
 )
... ...
@@ -8,8 +8,8 @@ import (
8 8
 
9 9
 	"github.com/docker/docker/builder/remotecontext"
10 10
 	"github.com/docker/docker/pkg/archive"
11
-	"github.com/docker/docker/pkg/reexec"
12 11
 	"github.com/moby/buildkit/frontend/dockerfile/instructions"
12
+	"github.com/moby/sys/reexec"
13 13
 	"gotest.tools/v3/assert"
14 14
 	is "gotest.tools/v3/assert/cmp"
15 15
 	"gotest.tools/v3/skip"
... ...
@@ -7,7 +7,7 @@ import (
7 7
 
8 8
 	"github.com/docker/docker/builder"
9 9
 	"github.com/docker/docker/pkg/archive"
10
-	"github.com/docker/docker/pkg/reexec"
10
+	"github.com/moby/sys/reexec"
11 11
 	"github.com/pkg/errors"
12 12
 	"gotest.tools/v3/skip"
13 13
 )
... ...
@@ -9,7 +9,7 @@ import (
9 9
 	"testing"
10 10
 
11 11
 	"github.com/docker/docker/daemon/config"
12
-	"github.com/docker/docker/pkg/reexec"
12
+	"github.com/moby/sys/reexec"
13 13
 	"golang.org/x/sys/unix"
14 14
 	"gotest.tools/v3/assert"
15 15
 )
... ...
@@ -10,9 +10,9 @@ import (
10 10
 	"github.com/containerd/log"
11 11
 	"github.com/docker/docker/daemon/config"
12 12
 	"github.com/docker/docker/dockerversion"
13
-	"github.com/docker/docker/pkg/reexec"
14 13
 	"github.com/docker/docker/pkg/rootless"
15 14
 	"github.com/moby/buildkit/util/apicaps"
15
+	"github.com/moby/sys/reexec"
16 16
 	"github.com/moby/term"
17 17
 	"github.com/spf13/cobra"
18 18
 
... ...
@@ -3,7 +3,7 @@ package main
3 3
 import (
4 4
 	"testing"
5 5
 
6
-	"github.com/docker/docker/pkg/reexec"
6
+	"github.com/moby/sys/reexec"
7 7
 )
8 8
 
9 9
 func TestMain(m *testing.M) {
... ...
@@ -31,9 +31,9 @@ import (
31 31
 	"github.com/docker/docker/pkg/idtools"
32 32
 	"github.com/docker/docker/pkg/ioutils"
33 33
 	"github.com/docker/docker/pkg/longpath"
34
-	"github.com/docker/docker/pkg/reexec"
35 34
 	"github.com/docker/docker/pkg/system"
36 35
 	"github.com/docker/go-units"
36
+	"github.com/moby/sys/reexec"
37 37
 	"github.com/pkg/errors"
38 38
 	"golang.org/x/sys/windows"
39 39
 )
... ...
@@ -31,7 +31,7 @@ import (
31 31
 	"github.com/docker/docker/libnetwork/osl"
32 32
 	"github.com/docker/docker/libnetwork/types"
33 33
 	"github.com/docker/docker/pkg/plugins"
34
-	"github.com/docker/docker/pkg/reexec"
34
+	"github.com/moby/sys/reexec"
35 35
 	"github.com/pkg/errors"
36 36
 	"github.com/vishvananda/netns"
37 37
 	"golang.org/x/sync/errgroup"
... ...
@@ -15,8 +15,8 @@ import (
15 15
 	"github.com/containerd/log"
16 16
 	"github.com/docker/docker/internal/otelutil"
17 17
 	"github.com/docker/docker/libnetwork/types"
18
-	"github.com/docker/docker/pkg/reexec"
19 18
 	"github.com/docker/docker/pkg/stringid"
19
+	"github.com/moby/sys/reexec"
20 20
 	"github.com/opencontainers/runtime-spec/specs-go"
21 21
 	"go.opentelemetry.io/otel"
22 22
 	"go.opentelemetry.io/otel/propagation"
... ...
@@ -11,7 +11,7 @@ import (
11 11
 	"syscall"
12 12
 
13 13
 	"github.com/docker/docker/pkg/archive"
14
-	"github.com/docker/docker/pkg/reexec"
14
+	"github.com/moby/sys/reexec"
15 15
 	"github.com/pkg/errors"
16 16
 	"golang.org/x/sys/unix"
17 17
 )
... ...
@@ -5,7 +5,7 @@ package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
5 5
 import (
6 6
 	"testing"
7 7
 
8
-	"github.com/docker/docker/pkg/reexec"
8
+	"github.com/moby/sys/reexec"
9 9
 )
10 10
 
11 11
 func TestMain(m *testing.M) {
12 12
deleted file mode 100644
... ...
@@ -1,83 +0,0 @@
1
-// Package reexec facilitates the busybox style reexec of a binary.
2
-//
3
-// Handlers can be registered with a name and the argv 0 of the exec of
4
-// the binary will be used to find and execute custom init paths.
5
-//
6
-// It is used to work around forking limitations when using Go.
7
-package reexec
8
-
9
-import (
10
-	"fmt"
11
-	"os"
12
-	"os/exec"
13
-	"path/filepath"
14
-	"runtime"
15
-)
16
-
17
-var registeredInitializers = make(map[string]func())
18
-
19
-// Register adds an initialization func under the specified name. It panics
20
-// if the given name is already registered.
21
-func Register(name string, initializer func()) {
22
-	if _, exists := registeredInitializers[name]; exists {
23
-		panic(fmt.Sprintf("reexec func already registered under name %q", name))
24
-	}
25
-
26
-	registeredInitializers[name] = initializer
27
-}
28
-
29
-// Init is called as the first part of the exec process and returns true if an
30
-// initialization function was called.
31
-func Init() bool {
32
-	if initializer, ok := registeredInitializers[os.Args[0]]; ok {
33
-		initializer()
34
-		return true
35
-	}
36
-	return false
37
-}
38
-
39
-// Command returns an [*exec.Cmd] with its Path set to the path of the current
40
-// binary using the result of [Self].
41
-//
42
-// On Linux, the Pdeathsig of [*exec.Cmd.SysProcAttr] is set to SIGTERM.
43
-// This signal is sent to the process when the OS thread that created
44
-// the process dies.
45
-//
46
-// It is the caller's responsibility to ensure that the creating thread is
47
-// not terminated prematurely. See https://go.dev/issue/27505 for more details.
48
-func Command(args ...string) *exec.Cmd {
49
-	return command(args...)
50
-}
51
-
52
-// Self returns the path to the current process's binary.
53
-//
54
-// On Linux, it returns "/proc/self/exe", which provides the in-memory version
55
-// of the current binary. This makes it safe to delete or replace the on-disk
56
-// binary (os.Args[0]).
57
-//
58
-// On Other platforms, it attempts to look up the absolute path for os.Args[0],
59
-// or otherwise returns os.Args[0] as-is. For example if current binary is
60
-// "my-binary" at "/usr/bin/" (or "my-binary.exe" at "C:\" on Windows),
61
-// then it returns "/usr/bin/my-binary" and "C:\my-binary.exe" respectively.
62
-func Self() string {
63
-	if runtime.GOOS == "linux" {
64
-		return "/proc/self/exe"
65
-	}
66
-	return naiveSelf()
67
-}
68
-
69
-func naiveSelf() string {
70
-	name := os.Args[0]
71
-	if filepath.Base(name) == name {
72
-		if lp, err := exec.LookPath(name); err == nil {
73
-			return lp
74
-		}
75
-	}
76
-	// handle conversion of relative paths to absolute
77
-	if absName, err := filepath.Abs(name); err == nil {
78
-		return absName
79
-	}
80
-	// if we couldn't get absolute name, return original
81
-	// (NOTE: Go only errors on Abs() if os.Getwd fails)
82
-	return name
83
-}
84 1
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+// Package reexec facilitates the busybox style reexec of a binary.
1
+//
2
+// Deprecated: this package is deprecated and moved to a separate module. Use [github.com/moby/sys/reexec] instead.
3
+package reexec
4
+
5
+import (
6
+	"os/exec"
7
+
8
+	"github.com/moby/sys/reexec"
9
+)
10
+
11
+// Register adds an initialization func under the specified name. It panics
12
+// if the given name is already registered.
13
+//
14
+// Deprecated: use [reexec.Register] instead.
15
+func Register(name string, initializer func()) {
16
+	reexec.Register(name, initializer)
17
+}
18
+
19
+// Init is called as the first part of the exec process and returns true if an
20
+// initialization function was called.
21
+//
22
+// Deprecated: use [reexec.Init] instead.
23
+func Init() bool {
24
+	return reexec.Init()
25
+}
26
+
27
+// Command returns an [*exec.Cmd] with its Path set to the path of the current
28
+// binary using the result of [Self].
29
+//
30
+// Deprecated: use [reexec.Command] instead.
31
+func Command(args ...string) *exec.Cmd {
32
+	return reexec.Command(args...)
33
+}
34
+
35
+// Self returns the path to the current process's binary.
36
+//
37
+// Deprecated: use [reexec.Self] instead.
38
+func Self() string {
39
+	return reexec.Self()
40
+}
0 41
deleted file mode 100644
... ...
@@ -1,16 +0,0 @@
1
-package reexec
2
-
3
-import (
4
-	"os/exec"
5
-	"syscall"
6
-)
7
-
8
-func command(args ...string) *exec.Cmd {
9
-	return &exec.Cmd{
10
-		Path: Self(),
11
-		Args: args,
12
-		SysProcAttr: &syscall.SysProcAttr{
13
-			Pdeathsig: syscall.SIGTERM,
14
-		},
15
-	}
16
-}
17 1
deleted file mode 100644
... ...
@@ -1,14 +0,0 @@
1
-//go:build !linux
2
-
3
-package reexec
4
-
5
-import (
6
-	"os/exec"
7
-)
8
-
9
-func command(args ...string) *exec.Cmd {
10
-	return &exec.Cmd{
11
-		Path: Self(),
12
-		Args: args,
13
-	}
14
-}
15 1
deleted file mode 100644
... ...
@@ -1,69 +0,0 @@
1
-package reexec
2
-
3
-import (
4
-	"os"
5
-	"os/exec"
6
-	"testing"
7
-)
8
-
9
-const testReExec = "test-reexec"
10
-
11
-func init() {
12
-	Register(testReExec, func() {
13
-		panic("Return Error")
14
-	})
15
-	Init()
16
-}
17
-
18
-func TestRegister(t *testing.T) {
19
-	defer func() {
20
-		if r := recover(); r != nil {
21
-			const expected = `reexec func already registered under name "test-reexec"`
22
-			if r != expected {
23
-				t.Errorf("got %q, want %q", r, expected)
24
-			}
25
-		}
26
-	}()
27
-	Register(testReExec, func() {})
28
-}
29
-
30
-func TestCommand(t *testing.T) {
31
-	cmd := Command(testReExec)
32
-	w, err := cmd.StdinPipe()
33
-	if err != nil {
34
-		t.Fatalf("Error on pipe creation: %v", err)
35
-	}
36
-	defer w.Close()
37
-
38
-	err = cmd.Start()
39
-	if err != nil {
40
-		t.Fatalf("Error on re-exec cmd: %v", err)
41
-	}
42
-	err = cmd.Wait()
43
-	const expected = "exit status 2"
44
-	if err == nil || err.Error() != expected {
45
-		t.Fatalf("got %v, want %v", err, expected)
46
-	}
47
-}
48
-
49
-func TestNaiveSelf(t *testing.T) {
50
-	if os.Getenv("TEST_CHECK") == "1" {
51
-		os.Exit(2)
52
-	}
53
-	cmd := exec.Command(naiveSelf(), "-test.run=TestNaiveSelf")
54
-	cmd.Env = append(os.Environ(), "TEST_CHECK=1")
55
-	err := cmd.Start()
56
-	if err != nil {
57
-		t.Fatalf("Unable to start command: %v", err)
58
-	}
59
-	err = cmd.Wait()
60
-	const expected = "exit status 2"
61
-	if err == nil || err.Error() != expected {
62
-		t.Fatalf("got %v, want %v", err, expected)
63
-	}
64
-
65
-	os.Args[0] = "mkdir"
66
-	if naiveSelf() == os.Args[0] {
67
-		t.Fatalf("Expected naiveSelf to resolve the location of mkdir")
68
-	}
69
-}
... ...
@@ -72,6 +72,7 @@ require (
72 72
 	github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e
73 73
 	github.com/moby/sys/mount v0.3.4
74 74
 	github.com/moby/sys/mountinfo v0.7.2
75
+	github.com/moby/sys/reexec v0.1.0
75 76
 	github.com/moby/sys/sequential v0.6.0
76 77
 	github.com/moby/sys/signal v0.7.1
77 78
 	github.com/moby/sys/symlink v0.3.0
... ...
@@ -382,6 +382,8 @@ github.com/moby/sys/mount v0.3.4 h1:yn5jq4STPztkkzSKpZkLcmjue+bZJ0u2AuQY1iNI1Ww=
382 382
 github.com/moby/sys/mount v0.3.4/go.mod h1:KcQJMbQdJHPlq5lcYT+/CjatWM4PuxKe+XLSVS4J6Os=
383 383
 github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
384 384
 github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
385
+github.com/moby/sys/reexec v0.1.0 h1:RrBi8e0EBTLEgfruBOFcxtElzRGTEUkeIFaVXgU7wok=
386
+github.com/moby/sys/reexec v0.1.0/go.mod h1:EqjBg8F3X7iZe5pU6nRZnYCMUTXoxsjiIfHup5wYIN8=
385 387
 github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
386 388
 github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
387 389
 github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
388 390
new file mode 100644
... ...
@@ -0,0 +1,202 @@
0
+
1
+                                 Apache License
2
+                           Version 2.0, January 2004
3
+                        http://www.apache.org/licenses/
4
+
5
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+   1. Definitions.
8
+
9
+      "License" shall mean the terms and conditions for use, reproduction,
10
+      and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+      "Licensor" shall mean the copyright owner or entity authorized by
13
+      the copyright owner that is granting the License.
14
+
15
+      "Legal Entity" shall mean the union of the acting entity and all
16
+      other entities that control, are controlled by, or are under common
17
+      control with that entity. For the purposes of this definition,
18
+      "control" means (i) the power, direct or indirect, to cause the
19
+      direction or management of such entity, whether by contract or
20
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+      outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+      "You" (or "Your") shall mean an individual or Legal Entity
24
+      exercising permissions granted by this License.
25
+
26
+      "Source" form shall mean the preferred form for making modifications,
27
+      including but not limited to software source code, documentation
28
+      source, and configuration files.
29
+
30
+      "Object" form shall mean any form resulting from mechanical
31
+      transformation or translation of a Source form, including but
32
+      not limited to compiled object code, generated documentation,
33
+      and conversions to other media types.
34
+
35
+      "Work" shall mean the work of authorship, whether in Source or
36
+      Object form, made available under the License, as indicated by a
37
+      copyright notice that is included in or attached to the work
38
+      (an example is provided in the Appendix below).
39
+
40
+      "Derivative Works" shall mean any work, whether in Source or Object
41
+      form, that is based on (or derived from) the Work and for which the
42
+      editorial revisions, annotations, elaborations, or other modifications
43
+      represent, as a whole, an original work of authorship. For the purposes
44
+      of this License, Derivative Works shall not include works that remain
45
+      separable from, or merely link (or bind by name) to the interfaces of,
46
+      the Work and Derivative Works thereof.
47
+
48
+      "Contribution" shall mean any work of authorship, including
49
+      the original version of the Work and any modifications or additions
50
+      to that Work or Derivative Works thereof, that is intentionally
51
+      submitted to Licensor for inclusion in the Work by the copyright owner
52
+      or by an individual or Legal Entity authorized to submit on behalf of
53
+      the copyright owner. For the purposes of this definition, "submitted"
54
+      means any form of electronic, verbal, or written communication sent
55
+      to the Licensor or its representatives, including but not limited to
56
+      communication on electronic mailing lists, source code control systems,
57
+      and issue tracking systems that are managed by, or on behalf of, the
58
+      Licensor for the purpose of discussing and improving the Work, but
59
+      excluding communication that is conspicuously marked or otherwise
60
+      designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+      "Contributor" shall mean Licensor and any individual or Legal Entity
63
+      on behalf of whom a Contribution has been received by Licensor and
64
+      subsequently incorporated within the Work.
65
+
66
+   2. Grant of Copyright License. Subject to the terms and conditions of
67
+      this License, each Contributor hereby grants to You a perpetual,
68
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+      copyright license to reproduce, prepare Derivative Works of,
70
+      publicly display, publicly perform, sublicense, and distribute the
71
+      Work and such Derivative Works in Source or Object form.
72
+
73
+   3. Grant of Patent License. Subject to the terms and conditions of
74
+      this License, each Contributor hereby grants to You a perpetual,
75
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+      (except as stated in this section) patent license to make, have made,
77
+      use, offer to sell, sell, import, and otherwise transfer the Work,
78
+      where such license applies only to those patent claims licensable
79
+      by such Contributor that are necessarily infringed by their
80
+      Contribution(s) alone or by combination of their Contribution(s)
81
+      with the Work to which such Contribution(s) was submitted. If You
82
+      institute patent litigation against any entity (including a
83
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+      or a Contribution incorporated within the Work constitutes direct
85
+      or contributory patent infringement, then any patent licenses
86
+      granted to You under this License for that Work shall terminate
87
+      as of the date such litigation is filed.
88
+
89
+   4. Redistribution. You may reproduce and distribute copies of the
90
+      Work or Derivative Works thereof in any medium, with or without
91
+      modifications, and in Source or Object form, provided that You
92
+      meet the following conditions:
93
+
94
+      (a) You must give any other recipients of the Work or
95
+          Derivative Works a copy of this License; and
96
+
97
+      (b) You must cause any modified files to carry prominent notices
98
+          stating that You changed the files; and
99
+
100
+      (c) You must retain, in the Source form of any Derivative Works
101
+          that You distribute, all copyright, patent, trademark, and
102
+          attribution notices from the Source form of the Work,
103
+          excluding those notices that do not pertain to any part of
104
+          the Derivative Works; and
105
+
106
+      (d) If the Work includes a "NOTICE" text file as part of its
107
+          distribution, then any Derivative Works that You distribute must
108
+          include a readable copy of the attribution notices contained
109
+          within such NOTICE file, excluding those notices that do not
110
+          pertain to any part of the Derivative Works, in at least one
111
+          of the following places: within a NOTICE text file distributed
112
+          as part of the Derivative Works; within the Source form or
113
+          documentation, if provided along with the Derivative Works; or,
114
+          within a display generated by the Derivative Works, if and
115
+          wherever such third-party notices normally appear. The contents
116
+          of the NOTICE file are for informational purposes only and
117
+          do not modify the License. You may add Your own attribution
118
+          notices within Derivative Works that You distribute, alongside
119
+          or as an addendum to the NOTICE text from the Work, provided
120
+          that such additional attribution notices cannot be construed
121
+          as modifying the License.
122
+
123
+      You may add Your own copyright statement to Your modifications and
124
+      may provide additional or different license terms and conditions
125
+      for use, reproduction, or distribution of Your modifications, or
126
+      for any such Derivative Works as a whole, provided Your use,
127
+      reproduction, and distribution of the Work otherwise complies with
128
+      the conditions stated in this License.
129
+
130
+   5. Submission of Contributions. Unless You explicitly state otherwise,
131
+      any Contribution intentionally submitted for inclusion in the Work
132
+      by You to the Licensor shall be under the terms and conditions of
133
+      this License, without any additional terms or conditions.
134
+      Notwithstanding the above, nothing herein shall supersede or modify
135
+      the terms of any separate license agreement you may have executed
136
+      with Licensor regarding such Contributions.
137
+
138
+   6. Trademarks. This License does not grant permission to use the trade
139
+      names, trademarks, service marks, or product names of the Licensor,
140
+      except as required for reasonable and customary use in describing the
141
+      origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+   7. Disclaimer of Warranty. Unless required by applicable law or
144
+      agreed to in writing, Licensor provides the Work (and each
145
+      Contributor provides its Contributions) on an "AS IS" BASIS,
146
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+      implied, including, without limitation, any warranties or conditions
148
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+      PARTICULAR PURPOSE. You are solely responsible for determining the
150
+      appropriateness of using or redistributing the Work and assume any
151
+      risks associated with Your exercise of permissions under this License.
152
+
153
+   8. Limitation of Liability. In no event and under no legal theory,
154
+      whether in tort (including negligence), contract, or otherwise,
155
+      unless required by applicable law (such as deliberate and grossly
156
+      negligent acts) or agreed to in writing, shall any Contributor be
157
+      liable to You for damages, including any direct, indirect, special,
158
+      incidental, or consequential damages of any character arising as a
159
+      result of this License or out of the use or inability to use the
160
+      Work (including but not limited to damages for loss of goodwill,
161
+      work stoppage, computer failure or malfunction, or any and all
162
+      other commercial damages or losses), even if such Contributor
163
+      has been advised of the possibility of such damages.
164
+
165
+   9. Accepting Warranty or Additional Liability. While redistributing
166
+      the Work or Derivative Works thereof, You may choose to offer,
167
+      and charge a fee for, acceptance of support, warranty, indemnity,
168
+      or other liability obligations and/or rights consistent with this
169
+      License. However, in accepting such obligations, You may act only
170
+      on Your own behalf and on Your sole responsibility, not on behalf
171
+      of any other Contributor, and only if You agree to indemnify,
172
+      defend, and hold each Contributor harmless for any liability
173
+      incurred by, or claims asserted against, such Contributor by reason
174
+      of your accepting any such warranty or additional liability.
175
+
176
+   END OF TERMS AND CONDITIONS
177
+
178
+   APPENDIX: How to apply the Apache License to your work.
179
+
180
+      To apply the Apache License to your work, attach the following
181
+      boilerplate notice, with the fields enclosed by brackets "[]"
182
+      replaced with your own identifying information. (Don't include
183
+      the brackets!)  The text should be enclosed in the appropriate
184
+      comment syntax for the file format. We also recommend that a
185
+      file or class name and description of purpose be included on the
186
+      same "printed page" as the copyright notice for easier
187
+      identification within third-party archives.
188
+
189
+   Copyright [yyyy] [name of copyright owner]
190
+
191
+   Licensed under the Apache License, Version 2.0 (the "License");
192
+   you may not use this file except in compliance with the License.
193
+   You may obtain a copy of the License at
194
+
195
+       http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+   Unless required by applicable law or agreed to in writing, software
198
+   distributed under the License is distributed on an "AS IS" BASIS,
199
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+   See the License for the specific language governing permissions and
201
+   limitations under the License.
0 202
new file mode 100644
... ...
@@ -0,0 +1,83 @@
0
+// Package reexec facilitates the busybox style reexec of a binary.
1
+//
2
+// Handlers can be registered with a name and the argv 0 of the exec of
3
+// the binary will be used to find and execute custom init paths.
4
+//
5
+// It is used to work around forking limitations when using Go.
6
+package reexec
7
+
8
+import (
9
+	"fmt"
10
+	"os"
11
+	"os/exec"
12
+	"path/filepath"
13
+	"runtime"
14
+)
15
+
16
+var registeredInitializers = make(map[string]func())
17
+
18
+// Register adds an initialization func under the specified name. It panics
19
+// if the given name is already registered.
20
+func Register(name string, initializer func()) {
21
+	if _, exists := registeredInitializers[name]; exists {
22
+		panic(fmt.Sprintf("reexec func already registered under name %q", name))
23
+	}
24
+
25
+	registeredInitializers[name] = initializer
26
+}
27
+
28
+// Init is called as the first part of the exec process and returns true if an
29
+// initialization function was called.
30
+func Init() bool {
31
+	if initializer, ok := registeredInitializers[os.Args[0]]; ok {
32
+		initializer()
33
+		return true
34
+	}
35
+	return false
36
+}
37
+
38
+// Command returns an [*exec.Cmd] with its Path set to the path of the current
39
+// binary using the result of [Self].
40
+//
41
+// On Linux, the Pdeathsig of [*exec.Cmd.SysProcAttr] is set to SIGTERM.
42
+// This signal is sent to the process when the OS thread that created
43
+// the process dies.
44
+//
45
+// It is the caller's responsibility to ensure that the creating thread is
46
+// not terminated prematurely. See https://go.dev/issue/27505 for more details.
47
+func Command(args ...string) *exec.Cmd {
48
+	return command(args...)
49
+}
50
+
51
+// Self returns the path to the current process's binary.
52
+//
53
+// On Linux, it returns "/proc/self/exe", which provides the in-memory version
54
+// of the current binary. This makes it safe to delete or replace the on-disk
55
+// binary (os.Args[0]).
56
+//
57
+// On Other platforms, it attempts to look up the absolute path for os.Args[0],
58
+// or otherwise returns os.Args[0] as-is. For example if current binary is
59
+// "my-binary" at "/usr/bin/" (or "my-binary.exe" at "C:\" on Windows),
60
+// then it returns "/usr/bin/my-binary" and "C:\my-binary.exe" respectively.
61
+func Self() string {
62
+	if runtime.GOOS == "linux" {
63
+		return "/proc/self/exe"
64
+	}
65
+	return naiveSelf()
66
+}
67
+
68
+func naiveSelf() string {
69
+	name := os.Args[0]
70
+	if filepath.Base(name) == name {
71
+		if lp, err := exec.LookPath(name); err == nil {
72
+			return lp
73
+		}
74
+	}
75
+	// handle conversion of relative paths to absolute
76
+	if absName, err := filepath.Abs(name); err == nil {
77
+		return absName
78
+	}
79
+	// if we couldn't get absolute name, return original
80
+	// (NOTE: Go only errors on Abs() if os.Getwd fails)
81
+	return name
82
+}
0 83
new file mode 100644
... ...
@@ -0,0 +1,16 @@
0
+package reexec
1
+
2
+import (
3
+	"os/exec"
4
+	"syscall"
5
+)
6
+
7
+func command(args ...string) *exec.Cmd {
8
+	return &exec.Cmd{
9
+		Path: Self(),
10
+		Args: args,
11
+		SysProcAttr: &syscall.SysProcAttr{
12
+			Pdeathsig: syscall.SIGTERM,
13
+		},
14
+	}
15
+}
0 16
new file mode 100644
... ...
@@ -0,0 +1,14 @@
0
+//go:build !linux
1
+
2
+package reexec
3
+
4
+import (
5
+	"os/exec"
6
+)
7
+
8
+func command(args ...string) *exec.Cmd {
9
+	return &exec.Cmd{
10
+		Path: Self(),
11
+		Args: args,
12
+	}
13
+}
... ...
@@ -954,6 +954,9 @@ github.com/moby/sys/mount
954 954
 # github.com/moby/sys/mountinfo v0.7.2
955 955
 ## explicit; go 1.17
956 956
 github.com/moby/sys/mountinfo
957
+# github.com/moby/sys/reexec v0.1.0
958
+## explicit; go 1.18
959
+github.com/moby/sys/reexec
957 960
 # github.com/moby/sys/sequential v0.6.0
958 961
 ## explicit; go 1.17
959 962
 github.com/moby/sys/sequential