From 150e646b0592c6485530e90d5e2f487b342355e1 Mon Sep 17 00:00:00 2001
From: Xiang Li <xiangli.cs@gmail.com>
Date: Tue, 29 Dec 2015 10:40:58 -0800
Subject: [PATCH] etcdserver: always check if the data dir is writable before
 starting etcd

---
 etcdserver/server.go     | 13 ++++++-------
 pkg/fileutil/fileutil.go | 12 ++++++++++++
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/etcdserver/server.go b/etcdserver/server.go
index a2a12e935..513cd6237 100644
--- a/etcdserver/server.go
+++ b/etcdserver/server.go
@@ -204,6 +204,10 @@ func NewServer(cfg *ServerConfig) (*EtcdServer, error) {
 		cl *cluster
 	)
 
+	if terr := fileutil.TouchDirAll(cfg.DataDir); terr != nil {
+		return nil, fmt.Errorf("cannot access data directory: %v", terr)
+	}
+
 	if !cfg.V3demo && fileutil.Exist(path.Join(cfg.SnapDir(), databaseFilename)) {
 		return nil, errors.New("experimental-v3demo cannot be disabled once it is enabled")
 	}
@@ -284,10 +288,6 @@ func NewServer(cfg *ServerConfig) (*EtcdServer, error) {
 		cfg.PrintWithInitial()
 		id, n, s, w = startNode(cfg, cl, cl.MemberIDs())
 	case haveWAL:
-		if err := fileutil.IsDirWriteable(cfg.DataDir); err != nil {
-			return nil, fmt.Errorf("cannot write to data directory: %v", err)
-		}
-
 		if err := fileutil.IsDirWriteable(cfg.MemberDir()); err != nil {
 			return nil, fmt.Errorf("cannot write to member directory: %v", err)
 		}
@@ -323,9 +323,8 @@ func NewServer(cfg *ServerConfig) (*EtcdServer, error) {
 		return nil, fmt.Errorf("unsupported bootstrap config")
 	}
 
-	err = os.MkdirAll(cfg.MemberDir(), privateDirMode)
-	if err != nil && err != os.ErrExist {
-		return nil, err
+	if terr := fileutil.TouchDirAll(cfg.MemberDir()); terr != nil {
+		return nil, fmt.Errorf("cannot access member directory: %v", terr)
 	}
 
 	sstats := &stats.ServerStats{
diff --git a/pkg/fileutil/fileutil.go b/pkg/fileutil/fileutil.go
index b728a4953..6f4ccf780 100644
--- a/pkg/fileutil/fileutil.go
+++ b/pkg/fileutil/fileutil.go
@@ -26,6 +26,8 @@ import (
 
 const (
 	privateFileMode = 0600
+	// owner can make/remove files inside the directory
+	privateDirMode = 0700
 )
 
 var (
@@ -57,6 +59,16 @@ func ReadDir(dirpath string) ([]string, error) {
 	return names, nil
 }
 
+// TouchDirAll is simliar to os.MkdirAll. It creates directories with 0700 permission if any directory
+// does not exists. TouchDirAll also ensures the given directory is writable.
+func TouchDirAll(dir string) error {
+	err := os.MkdirAll(dir, privateDirMode)
+	if err != nil && err != os.ErrExist {
+		return err
+	}
+	return IsDirWriteable(dir)
+}
+
 func Exist(name string) bool {
 	_, err := os.Stat(name)
 	return err == nil