From 9e5b93565c8a10f4b06d2bcf61305fdfb7128628 Mon Sep 17 00:00:00 2001
From: John Starks <jostarks@microsoft.com>
Date: Mon, 18 Apr 2016 15:09:55 -0700
Subject: [PATCH] Windows: don't overwrite PID file if process exists

pidfile.New() was opening a file in /proc to determine if the owning
process still exists. Use syscall.OpenProcess() on Windows instead.

Other OSes may also need to be updated here.

Signed-off-by: John Starks <jostarks@microsoft.com>
---
 pkg/pidfile/pidfile.go         |  3 +--
 pkg/pidfile/pidfile_test.go    |  8 +++++++-
 pkg/pidfile/pidfile_unix.go    | 16 ++++++++++++++++
 pkg/pidfile/pidfile_windows.go | 23 +++++++++++++++++++++++
 4 files changed, 47 insertions(+), 3 deletions(-)
 create mode 100644 pkg/pidfile/pidfile_unix.go
 create mode 100644 pkg/pidfile/pidfile_windows.go

diff --git a/pkg/pidfile/pidfile.go b/pkg/pidfile/pidfile.go
index 58cc401703..e1ac6bee35 100644
--- a/pkg/pidfile/pidfile.go
+++ b/pkg/pidfile/pidfile.go
@@ -7,7 +7,6 @@ import (
 	"fmt"
 	"io/ioutil"
 	"os"
-	"path/filepath"
 	"strconv"
 	"strings"
 )
@@ -21,7 +20,7 @@ func checkPIDFileAlreadyExists(path string) error {
 	if pidByte, err := ioutil.ReadFile(path); err == nil {
 		pidString := strings.TrimSpace(string(pidByte))
 		if pid, err := strconv.Atoi(pidString); err == nil {
-			if _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid))); err == nil {
+			if processExists(pid) {
 				return fmt.Errorf("pid file found, ensure docker is not running or delete %s", path)
 			}
 		}
diff --git a/pkg/pidfile/pidfile_test.go b/pkg/pidfile/pidfile_test.go
index d5ef87083b..73e8af76db 100644
--- a/pkg/pidfile/pidfile_test.go
+++ b/pkg/pidfile/pidfile_test.go
@@ -13,11 +13,17 @@ func TestNewAndRemove(t *testing.T) {
 		t.Fatal("Could not create test directory")
 	}
 
-	file, err := New(filepath.Join(dir, "testfile"))
+	path := filepath.Join(dir, "testfile")
+	file, err := New(path)
 	if err != nil {
 		t.Fatal("Could not create test file", err)
 	}
 
+	_, err = New(path)
+	if err == nil {
+		t.Fatal("Test file creation not blocked")
+	}
+
 	if err := file.Remove(); err != nil {
 		t.Fatal("Could not delete created test file")
 	}
diff --git a/pkg/pidfile/pidfile_unix.go b/pkg/pidfile/pidfile_unix.go
new file mode 100644
index 0000000000..28f3deca91
--- /dev/null
+++ b/pkg/pidfile/pidfile_unix.go
@@ -0,0 +1,16 @@
+// +build !windows
+
+package pidfile
+
+import (
+	"os"
+	"path/filepath"
+	"strconv"
+)
+
+func processExists(pid int) bool {
+	if _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid))); err == nil {
+		return true
+	}
+	return false
+}
diff --git a/pkg/pidfile/pidfile_windows.go b/pkg/pidfile/pidfile_windows.go
new file mode 100644
index 0000000000..ae489c627a
--- /dev/null
+++ b/pkg/pidfile/pidfile_windows.go
@@ -0,0 +1,23 @@
+package pidfile
+
+import "syscall"
+
+const (
+	processQueryLimitedInformation = 0x1000
+
+	stillActive = 259
+)
+
+func processExists(pid int) bool {
+	h, err := syscall.OpenProcess(processQueryLimitedInformation, false, uint32(pid))
+	if err != nil {
+		return false
+	}
+	var c uint32
+	err = syscall.GetExitCodeProcess(h, &c)
+	syscall.Close(h)
+	if err != nil {
+		return c == stillActive
+	}
+	return true
+}