diff options
-rw-r--r-- | Documentation/MANPAGE.md | 2 | ||||
-rw-r--r-- | internal/ctlsocksrv/ctlsock_listen.go | 35 | ||||
-rw-r--r-- | tests/cli/cli_test.go | 37 | ||||
-rwxr-xr-x | tests/dl-linux-tarball.bash | 2 |
4 files changed, 74 insertions, 2 deletions
diff --git a/Documentation/MANPAGE.md b/Documentation/MANPAGE.md index 5b3508f..1d3ab6c 100644 --- a/Documentation/MANPAGE.md +++ b/Documentation/MANPAGE.md @@ -381,7 +381,7 @@ Mount the filesystem read-write (`-rw`, default) or read-only (`-ro`). If both are specified, `-ro` takes precedence. #### -reverse -See the `-reverse` section in INIT FLAGS. You need to specify the +See the `-reverse` section in INIT OPTIONS. You need to specify the `-reverse` option both at `-init` and at mount. #### -serialize_reads diff --git a/internal/ctlsocksrv/ctlsock_listen.go b/internal/ctlsocksrv/ctlsock_listen.go index 1db9cbc..94ffca4 100644 --- a/internal/ctlsocksrv/ctlsock_listen.go +++ b/internal/ctlsocksrv/ctlsock_listen.go @@ -1,9 +1,44 @@ package ctlsocksrv import ( + "errors" + "io/fs" "net" + "os" + "syscall" + "time" + + "github.com/rfjakob/gocryptfs/v2/internal/tlog" ) +// cleanupOrphanedSocket deletes an orphaned socket file at `path`. +// The file at `path` will only be deleted if: +// 1) It is a socket file +// 2) Connecting to it results in ECONNREFUSED +func cleanupOrphanedSocket(path string) { + fi, err := os.Stat(path) + if err != nil { + return + } + if fi.Mode().Type() != fs.ModeSocket { + return + } + conn, err := net.DialTimeout("unix", path, time.Second) + if err == nil { + // This socket file is still active. Don't delete it. + conn.Close() + return + } + if errors.Is(err, syscall.ECONNREFUSED) { + tlog.Info.Printf("ctlsock: deleting orphaned socket file %q\n", path) + err = os.Remove(path) + if err != nil { + tlog.Warn.Printf("ctlsock: deleting socket file failed: %v", path) + } + } +} + func Listen(path string) (net.Listener, error) { + cleanupOrphanedSocket(path) return net.Listen("unix", path) } diff --git a/tests/cli/cli_test.go b/tests/cli/cli_test.go index 686d14c..b2f9f40 100644 --- a/tests/cli/cli_test.go +++ b/tests/cli/cli_test.go @@ -4,6 +4,7 @@ package cli import ( "bytes" "encoding/hex" + "errors" "fmt" "io/ioutil" "os" @@ -1033,3 +1034,39 @@ func TestMountCreat(t *testing.T) { test_helpers.UnmountPanic(mnt) } } + +// https://github.com/rfjakob/gocryptfs/issues/776 +func TestOrphanedSocket(t *testing.T) { + cDir := test_helpers.InitFS(t) + ctlSock := cDir + ".sock" + mnt := cDir + ".mnt" + test_helpers.MountOrFatal(t, cDir, mnt, "-extpass", "echo test", "-wpanic=false", "-ctlsock", ctlSock) + + mnt2 := cDir + ".mnt2" + err := test_helpers.Mount(cDir, mnt2, false, "-extpass", "echo test", "-wpanic=false", "-ctlsock", ctlSock) + exitCode := test_helpers.ExtractCmdExitCode(err) + if exitCode != exitcodes.CtlSock { + t.Errorf("wrong exit code: want=%d, have=%d", exitcodes.CtlSock, exitCode) + } + test_helpers.UnmountPanic(mnt) + + // Unmount returns before the gocryptfs process has terminated and before the + // socket file has been deleted. Wait out the deletion. + for i := 0; i < 100; i++ { + _, err := os.Stat(ctlSock) + if errors.Is(err, os.ErrNotExist) { + break + } + time.Sleep(time.Millisecond) + } + + // Create orphaned socket file + err = syscall.Mknod(ctlSock, syscall.S_IFSOCK|0666, 0) + if err != nil { + t.Fatal(err) + } + + // Should delete the socket file automatically and the mount should work + test_helpers.MountOrFatal(t, cDir, mnt, "-extpass", "echo test", "-wpanic=false", "-ctlsock", ctlSock) + test_helpers.UnmountPanic(mnt) +} diff --git a/tests/dl-linux-tarball.bash b/tests/dl-linux-tarball.bash index dfff492..03c0e7d 100755 --- a/tests/dl-linux-tarball.bash +++ b/tests/dl-linux-tarball.bash @@ -20,7 +20,7 @@ fi if [[ $SIZE_ACTUAL -ne $SIZE_WANT ]]; then echo "Downloading linux-3.0.tar.gz" if command -v wget > /dev/null ; then - wget -nv --show-progress -c -O "$TGZ" "$URL" + wget -nv -c -O "$TGZ" "$URL" else curl -o "$TGZ" "$URL" fi |