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 ( import (
"flag" "flag"
"fmt" "fmt"
"net"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@ -23,9 +24,11 @@ type argContainer struct {
// Configuration file name override // Configuration file name override
config string config string
notifypid, scryptn int 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. // _configCustom is true when the user sets a custom config file name.
// This is not a CLI option.
_configCustom bool _configCustom bool
// _ctlsockFd stores the control socket file descriptor (ctlsock stores the path)
_ctlsockFd net.Listener
} }
var flagSet *flag.FlagSet var flagSet *flag.FlagSet

View File

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

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"log/syslog" "log/syslog"
"net"
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
@ -50,7 +51,28 @@ func doMount(args *argContainer) int {
tlog.Fatal.Printf("Invalid mountpoint: %v", err) tlog.Fatal.Printf("Invalid mountpoint: %v", err)
os.Exit(ErrExitMountPoint) 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 masterkey []byte
var confFile *configfile.ConfFile var confFile *configfile.ConfFile
if args.masterkey != "" { if args.masterkey != "" {
@ -65,6 +87,7 @@ func doMount(args *argContainer) int {
masterkey = make([]byte, cryptocore.KeyLen) masterkey = make([]byte, cryptocore.KeyLen)
} else { } else {
// Load master key from config file // Load master key from config file
// Prompts the user for the password
masterkey, confFile = loadConfig(args) masterkey, confFile = loadConfig(args)
printMasterKey(masterkey) printMasterKey(masterkey)
} }
@ -177,14 +200,10 @@ func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfF
finalFs = fs finalFs = fs
ctlSockBackend = fs ctlSockBackend = fs
} }
if args.ctlsock != "" { // We have opened the socket early so that we cannot fail here after
err := ctlsock.CreateAndServe(args.ctlsock, ctlSockBackend) // asking the user for the password
if err != nil { if args._ctlsockFd != nil {
// TODO if the socket cannot be created, we should exit BEFORE go ctlsock.Serve(args._ctlsockFd, ctlSockBackend)
// asking the user for the password
tlog.Fatal.Printf("ctlsock: %v", err)
os.Exit(ErrExitMount)
}
} }
pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true} pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts) pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts)