From d3f9a9da0d60a7de30149a8c59c573d7ddb9f143 Mon Sep 17 00:00:00 2001
From: Harshavardhana <harsha@harshavardhana.net>
Date: Wed, 9 Sep 2015 15:29:28 -0700
Subject: [PATCH] Verify golang runtime for 0.5.1 and above, also verify if
 runner is a root

---
 main.go           |  11 ++++-
 verify-runtime.go | 100 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+), 1 deletion(-)
 create mode 100644 verify-runtime.go

diff --git a/main.go b/main.go
index 4b2bddbb0..c69a0ea92 100644
--- a/main.go
+++ b/main.go
@@ -31,10 +31,19 @@ import (
 
 func init() {
 	// Check for the environment early on and gracefuly report.
-	_, err := user.Current()
+	u, err := user.Current()
 	if err != nil {
 		Fatalf("Unable to obtain user's home directory. \nError: %s\n", err)
 	}
+	var uid int
+	uid, err = strconv.Atoi(u.Uid)
+	if err != nil {
+		Fatalf("Unable to convert user id to an integer. \nError: %s\n", err)
+	}
+	if uid == 0 {
+		Fatalln("Please run as a normal user, running as root is disallowed")
+	}
+	verifyMinioRuntime()
 }
 
 // Tries to get os/arch/platform specific information
diff --git a/verify-runtime.go b/verify-runtime.go
new file mode 100644
index 000000000..c21d8fcf8
--- /dev/null
+++ b/verify-runtime.go
@@ -0,0 +1,100 @@
+/*
+ * Minio Cloud Storage, (C) 2015 Minio, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+	"fmt"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+)
+
+var minGolangRuntimeVersion = "1.5.1"
+
+// following code handles the current Golang release styles, we might have to update them in future
+// if golang community divulges from the below formatting style.
+const (
+	betaRegexp = "beta[0-9]"
+	rcRegexp   = "rc[0-9]"
+)
+
+func getNormalizedGolangVersion() string {
+	version := strings.TrimPrefix(runtime.Version(), "go")
+	br := regexp.MustCompile(betaRegexp)
+	rr := regexp.MustCompile(rcRegexp)
+	betaStr := br.FindString(version)
+	version = strings.TrimRight(version, betaStr)
+	rcStr := rr.FindString(version)
+	version = strings.TrimRight(version, rcStr)
+	return version
+}
+
+type version struct {
+	major, minor, patch string
+}
+
+func newVersion(v string) version {
+	var ver version
+	verSlice := strings.Split(v, ".")
+	if len(verSlice) > 2 {
+		ver = version{
+			major: verSlice[0],
+			minor: verSlice[1],
+			patch: verSlice[2],
+		}
+		return ver
+	}
+	ver = version{
+		major: verSlice[0],
+		minor: verSlice[1],
+		patch: "0",
+	}
+	return ver
+}
+
+func (v1 version) String() string {
+	return fmt.Sprintf("%s%s%s", v1.major, v1.minor, v1.patch)
+}
+
+func (v1 version) Version() int {
+	ver, e := strconv.Atoi(v1.String())
+	if e != nil {
+		Fatalln("Unable to parse version string.")
+	}
+	return ver
+}
+
+func (v1 version) LessThan(v2 version) bool {
+	if v1.Version() < v2.Version() {
+		return true
+	}
+	return false
+}
+
+func checkGolangRuntimeVersion() {
+	v1 := newVersion(getNormalizedGolangVersion())
+	v2 := newVersion(minGolangRuntimeVersion)
+	if v1.LessThan(v2) {
+		Errorln("Old Golang runtime version ‘" + v1.String() + "’ detected., ‘mc’ requires minimum go1.5 or later.")
+	}
+}
+
+func verifyMinioRuntime() {
+	// add any other checks here.
+	checkGolangRuntimeVersion()
+}