ctlsock: exit early if socket cannot be created; delete on exit

Both are achieved by opening the socket from main and passing
it to the ctlsock package instead of passing the path.
This commit is contained in:
Jakob Unterwurzacher 2016-12-10 14:54:06 +01:00
parent e1833fa26a
commit 6af725ff09
3 changed files with 36 additions and 19 deletions

View File

@ -3,6 +3,7 @@ package main
import (
"flag"
"fmt"
"net"
"os"
"strconv"
"strings"
@ -23,9 +24,11 @@ type argContainer struct {
// Configuration file name override
config string
notifypid, scryptn int
// Helper variables that are NOT cli options all start with an underscore
// _configCustom is true when the user sets a custom config file name.
// This is not a CLI option.
_configCustom bool
// _ctlsockFd stores the control socket file descriptor (ctlsock stores the path)
_ctlsockFd net.Listener
}
var flagSet *flag.FlagSet

View File

@ -46,19 +46,14 @@ type ctlSockHandler struct {
socket *net.UnixListener
}
// CreateAndServe creates an unix socket at "path" and serves incoming
// connections in a new goroutine.
func CreateAndServe(path string, fs Interface) error {
sock, err := net.Listen("unix", path)
if err != nil {
return err
}
// Serve serves incoming connections on "sock". This call blocks so you
// probably want to run it in a new goroutine.
func Serve(sock net.Listener, fs Interface) {
handler := ctlSockHandler{
fs: fs,
socket: sock.(*net.UnixListener),
}
go handler.acceptLoop()
return nil
handler.acceptLoop()
}
func (ch *ctlSockHandler) acceptLoop() {

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"io/ioutil"
"log/syslog"
"net"
"os"
"os/exec"
"os/signal"
@ -50,7 +51,28 @@ func doMount(args *argContainer) int {
tlog.Fatal.Printf("Invalid mountpoint: %v", err)
os.Exit(ErrExitMountPoint)
}
// Get master key
// Open control socket early so we can error out before asking the user
// for the password
if args.ctlsock != "" {
// We must use an absolute path because we cd to / when daemonizing.
// This messes up the delete-on-close logic in the unix socket object.
args.ctlsock, _ = filepath.Abs(args.ctlsock)
var sock net.Listener
sock, err = net.Listen("unix", args.ctlsock)
if err != nil {
tlog.Fatal.Printf("ctlsock: %v", err)
os.Exit(ErrExitMount)
}
args._ctlsockFd = sock
// Close also deletes the socket file
defer func() {
err = sock.Close()
if err != nil {
tlog.Warn.Print(err)
}
}()
}
// Get master key (may prompt for the password)
var masterkey []byte
var confFile *configfile.ConfFile
if args.masterkey != "" {
@ -65,6 +87,7 @@ func doMount(args *argContainer) int {
masterkey = make([]byte, cryptocore.KeyLen)
} else {
// Load master key from config file
// Prompts the user for the password
masterkey, confFile = loadConfig(args)
printMasterKey(masterkey)
}
@ -177,14 +200,10 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF
finalFs = fs
ctlSockBackend = fs
}
if args.ctlsock != "" {
err := ctlsock.CreateAndServe(args.ctlsock, ctlSockBackend)
if err != nil {
// TODO if the socket cannot be created, we should exit BEFORE
// We have opened the socket early so that we cannot fail here after
// asking the user for the password
tlog.Fatal.Printf("ctlsock: %v", err)
os.Exit(ErrExitMount)
}
if args._ctlsockFd != nil {
go ctlsock.Serve(args._ctlsockFd, ctlSockBackend)
}
pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts)