Skip to content

Commit 1f06387

Browse files
Preserve unix socket file (#20499)
By default Gitea will always unlink any sockets that are provided using the `LISTEN_FDS` environment variable. This is because it uses this variable to handle passing when it is doing a graceful restart. However, this same mechanism is used by systemd - which explicitly expects that passed in sockets should not be unlinked by the receiving process. This PR adjusts Gitea's graceful restart mechanism to use an additional environment variable which tracks if a listening socket was opened by Gitea - and therefore should be unlinked on shutdown by Gitea. Fix #20490 Co-authored-by: zeripath <art27@cantab.net>
1 parent 99efa02 commit 1f06387

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

Diff for: modules/graceful/net_unix.go

+35-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
const (
2424
listenFDs = "LISTEN_FDS"
2525
startFD = 3
26+
unlinkFDs = "GITEA_UNLINK_FDS"
2627
)
2728

2829
// In order to keep the working directory the same as when we started we record
@@ -33,8 +34,10 @@ var (
3334
once = sync.Once{}
3435
mutex = sync.Mutex{}
3536

36-
providedListeners = []net.Listener{}
37-
activeListeners = []net.Listener{}
37+
providedListenersToUnlink = []bool{}
38+
activeListenersToUnlink = []bool{}
39+
providedListeners = []net.Listener{}
40+
activeListeners = []net.Listener{}
3841
)
3942

4043
func getProvidedFDs() (savedErr error) {
@@ -53,6 +56,16 @@ func getProvidedFDs() (savedErr error) {
5356
return
5457
}
5558

59+
fdsToUnlinkStr := strings.Split(os.Getenv(unlinkFDs), ",")
60+
providedListenersToUnlink = make([]bool, n)
61+
for _, fdStr := range fdsToUnlinkStr {
62+
i, err := strconv.Atoi(fdStr)
63+
if err != nil || i < 0 || i >= n {
64+
continue
65+
}
66+
providedListenersToUnlink[i] = true
67+
}
68+
5669
for i := startFD; i < n+startFD; i++ {
5770
file := os.NewFile(uintptr(i), fmt.Sprintf("listener_FD%d", i))
5871

@@ -136,8 +149,11 @@ func GetListenerTCP(network string, address *net.TCPAddr) (*net.TCPListener, err
136149
for i, l := range providedListeners {
137150
if isSameAddr(l.Addr(), address) {
138151
providedListeners = append(providedListeners[:i], providedListeners[i+1:]...)
152+
needsUnlink := providedListenersToUnlink[i]
153+
providedListenersToUnlink = append(providedListenersToUnlink[:i], providedListenersToUnlink[i+1:]...)
139154

140155
activeListeners = append(activeListeners, l)
156+
activeListenersToUnlink = append(activeListenersToUnlink, needsUnlink)
141157
return l.(*net.TCPListener), nil
142158
}
143159
}
@@ -148,6 +164,7 @@ func GetListenerTCP(network string, address *net.TCPAddr) (*net.TCPListener, err
148164
return nil, err
149165
}
150166
activeListeners = append(activeListeners, l)
167+
activeListenersToUnlink = append(activeListenersToUnlink, false)
151168
return l, nil
152169
}
153170

@@ -166,9 +183,15 @@ func GetListenerUnix(network string, address *net.UnixAddr) (*net.UnixListener,
166183
for i, l := range providedListeners {
167184
if isSameAddr(l.Addr(), address) {
168185
providedListeners = append(providedListeners[:i], providedListeners[i+1:]...)
186+
needsUnlink := providedListenersToUnlink[i]
187+
providedListenersToUnlink = append(providedListenersToUnlink[:i], providedListenersToUnlink[i+1:]...)
188+
189+
activeListenersToUnlink = append(activeListenersToUnlink, needsUnlink)
169190
activeListeners = append(activeListeners, l)
170191
unixListener := l.(*net.UnixListener)
171-
unixListener.SetUnlinkOnClose(true)
192+
if needsUnlink {
193+
unixListener.SetUnlinkOnClose(true)
194+
}
172195
return unixListener, nil
173196
}
174197
}
@@ -189,6 +212,7 @@ func GetListenerUnix(network string, address *net.UnixAddr) (*net.UnixListener,
189212
}
190213

191214
activeListeners = append(activeListeners, l)
215+
activeListenersToUnlink = append(activeListenersToUnlink, true)
192216
return l, nil
193217
}
194218

@@ -223,3 +247,11 @@ func getActiveListeners() []net.Listener {
223247
copy(listeners, activeListeners)
224248
return listeners
225249
}
250+
251+
func getActiveListenersToUnlink() []bool {
252+
mutex.Lock()
253+
defer mutex.Unlock()
254+
listenersToUnlink := make([]bool, len(activeListenersToUnlink))
255+
copy(listenersToUnlink, activeListenersToUnlink)
256+
return listenersToUnlink
257+
}

Diff for: modules/graceful/restart_unix.go

+15
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"net"
1313
"os"
1414
"os/exec"
15+
"strconv"
1516
"strings"
1617
"sync"
1718
"syscall"
@@ -75,6 +76,20 @@ func RestartProcess() (int, error) {
7576
}
7677
env = append(env, fmt.Sprintf("%s=%d", listenFDs, len(listeners)))
7778

79+
sb := &strings.Builder{}
80+
for i, unlink := range getActiveListenersToUnlink() {
81+
if !unlink {
82+
continue
83+
}
84+
_, _ = sb.WriteString(strconv.Itoa(i))
85+
_, _ = sb.WriteString(",")
86+
}
87+
unlinkStr := sb.String()
88+
if len(unlinkStr) > 0 {
89+
unlinkStr = unlinkStr[:len(unlinkStr)-1]
90+
env = append(env, fmt.Sprintf("%s=%s", unlinkFDs, unlinkStr))
91+
}
92+
7893
allFiles := append([]*os.File{os.Stdin, os.Stdout, os.Stderr}, files...)
7994
process, err := os.StartProcess(argv0, os.Args, &os.ProcAttr{
8095
Dir: originalWD,

0 commit comments

Comments
 (0)