systemd: prevent unmount rc command from sending a STOPPING=1 sd-notify message

This prevents an `rclone rcd` server from prematurely going into the
'deactivating' state, which was causing systemd to kill it with a
SIGABRT after the stop timeout.

Fixes #7540
This commit is contained in:
AThePeanut4 2024-07-15 22:41:51 +02:00 committed by Nick Craig-Wood
parent 4824837eed
commit 14629c66f9
2 changed files with 6 additions and 8 deletions

View File

@ -18,11 +18,11 @@ import (
"github.com/rclone/rclone/fs/config/flags" "github.com/rclone/rclone/fs/config/flags"
"github.com/rclone/rclone/lib/atexit" "github.com/rclone/rclone/lib/atexit"
"github.com/rclone/rclone/lib/daemonize" "github.com/rclone/rclone/lib/daemonize"
"github.com/rclone/rclone/lib/systemd"
"github.com/rclone/rclone/vfs" "github.com/rclone/rclone/vfs"
"github.com/rclone/rclone/vfs/vfscommon" "github.com/rclone/rclone/vfs/vfscommon"
"github.com/rclone/rclone/vfs/vfsflags" "github.com/rclone/rclone/vfs/vfsflags"
"github.com/coreos/go-systemd/v22/daemon"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
@ -307,6 +307,7 @@ func NewMountCommand(commandName string, hidden bool, mount MountFn) *cobra.Comm
// Wait for foreground mount, if any... // Wait for foreground mount, if any...
if mountDaemon == nil { if mountDaemon == nil {
if err == nil { if err == nil {
defer systemd.Notify()()
err = mnt.Wait() err = mnt.Wait()
} }
if err != nil { if err != nil {
@ -385,7 +386,6 @@ func (m *MountPoint) Wait() error {
var finaliseOnce sync.Once var finaliseOnce sync.Once
finalise := func() { finalise := func() {
finaliseOnce.Do(func() { finaliseOnce.Do(func() {
_, _ = daemon.SdNotify(false, daemon.SdNotifyStopping)
// Unmount only if directory was mounted by rclone, e.g. don't unmount autofs hooks. // Unmount only if directory was mounted by rclone, e.g. don't unmount autofs hooks.
if err := CheckMountReady(m.MountPoint); err != nil { if err := CheckMountReady(m.MountPoint); err != nil {
fs.Debugf(m.MountPoint, "Unmounted externally. Just exit now.") fs.Debugf(m.MountPoint, "Unmounted externally. Just exit now.")
@ -401,11 +401,6 @@ func (m *MountPoint) Wait() error {
fnHandle := atexit.Register(finalise) fnHandle := atexit.Register(finalise)
defer atexit.Unregister(fnHandle) defer atexit.Unregister(fnHandle)
// Notify systemd
if _, err := daemon.SdNotify(false, daemon.SdNotifyReady); err != nil {
return fmt.Errorf("failed to notify systemd: %w", err)
}
// Reload VFS cache on SIGHUP // Reload VFS cache on SIGHUP
sigHup := make(chan os.Signal, 1) sigHup := make(chan os.Signal, 1)
NotifyOnSigHup(sigHup) NotifyOnSigHup(sigHup)

View File

@ -9,10 +9,13 @@ import (
"github.com/rclone/rclone/lib/atexit" "github.com/rclone/rclone/lib/atexit"
) )
// Notify systemd that the service is starting. This returns a // Notify systemd that the service is ready. This returns a
// function which should be called to notify that the service is // function which should be called to notify that the service is
// stopping. This function will be called on exit if the service exits // stopping. This function will be called on exit if the service exits
// on a signal. // on a signal.
// NOTE: this function should only be called once, and so it
// should generally only be used directly in a command's Run handler.
// It should not be called as a result of rc commands. See #7540.
func Notify() func() { func Notify() func() {
if _, err := daemon.SdNotify(false, daemon.SdNotifyReady); err != nil { if _, err := daemon.SdNotify(false, daemon.SdNotifyReady); err != nil {
log.Printf("failed to notify ready to systemd: %v", err) log.Printf("failed to notify ready to systemd: %v", err)