package sysutils import ( `bytes` `errors` `fmt` `io/ioutil` `os` `runtime` `strconv` `strings` `r00t2.io/sysutils/paths` ) /* EnvMapper contains the environment variables as grouped by their basic type. If a variable's type cannot be determined, it's placed in Strings. If a variable's type is a list, it will be an []interface{} as each item may be a different variable type. It essentially is the same as EnvMap except with the types split out for convenience. */ type EnvMapper struct { Booleans map[string]bool `json:"bools"` Numbers map[string]int `json:"nums"` Strings map[string]string `json:"strings"` Lists map[string][]interface{} `json:"lists"` } // GetEnvMapper returns a pointer to a populated EnvMapper. func GetEnvMapper() (e *EnvMapper, err error) { var em map[string]interface{} var env EnvMapper env = EnvMapper{ Booleans: nil, Numbers: nil, Strings: nil, Lists: nil, } for k, v := range em { switch t := v.(type) { case bool: if env.Booleans == nil { env.Booleans = make(map[string]bool, 0) } env.Booleans[k] = t continue case int: if env.Numbers == nil { env.Numbers = make(map[string]int, 0) } env.Numbers[k] = t continue case []interface{}: if env.Lists == nil { env.Lists = make(map[string][]interface{}, 0) } env.Lists[k] = t case string: // the "default" since everything could probably be typeswitched to a string otherwise. if env.Strings == nil { env.Strings = make(map[string]string, 0) } env.Strings[k] = t } } *e = env return } /* EnvMap returns a map of environment variables. The variable is an interface due to it attempting to use a variable's value to its "true" native type. If a type cannot be determined, it will be treated a string. */ func EnvMap() (envs map[string]interface{}, err error) { var ems map[string]string if ems, err = EnvMapString(); err != nil { return } for k, v := range ems { // Is int? if i, ok := getNum(v); ok { envs[k] = i continue } // Is bool? if b, ok := getBool(v); ok { envs[k] = b continue } // Is array? if a, ok := getArr(v); ok { envs[k] = a continue } // It's a string (probably). envs[k] = v } return } // EnvMapString is like EnvMap, but all values are treated as strings. func EnvMapString() (envs map[string]string, err error) { var envArray []string envs = make(map[string]string, 0) envArray = os.Environ() for _, e := range envArray { var k, v string var kv []string kv = strings.SplitN(e, "=", 2) k = kv[0] if len(kv) == 2 { v = kv[1] } else { v = "" } envs[k] = v } return } // UTILITY FUNCS // getBool attempts to convert a string value to a boolean. func getBool(s string) (b bool, ok bool) { switch s2 := strings.ToLower(strings.TrimSpace(s)); s2 { case "true", "yes", "y": b = true ok = true case "false", "no", "n": b = false ok = true } return } // getNum attempts to convert a string value to an int. func getNum(s string) (n int, ok bool) { var err error if n, err = strconv.Atoi(s); err == nil { ok = true } return } // getArr attempts to convert a string value to an array of interface{}. func getArr(s string) (a []interface{}, ok bool) { var arrS []string if arrS, ok = getArrStr(s); !ok { return } a = make([]interface{}, len(arrS)) for idx, i := range arrS { if b, ok := getBool(i); ok { a[idx] = b } else if n, ok := getNum(i); ok { a[idx] = n } else if l, ok := getArr(i); ok { a[idx] = l } else { a[idx] = i } } return } // getArrStr attempts to convert a string value to an array of strings. func getArrStr(s string) (a []string, ok bool) { var sep string = ":" if runtime.GOOS == "windows" { sep = ";" } a = strings.Split(s, sep) l := len(s) if l <= 1 { return } ok = true return } /* GetEnvPid will only work on *NIX-like systems with procfs. It gets the environment variables of a given process' PID. */ func GetEnvPid(pid uint32) (env map[string]string, err error) { var envBytes []byte var envArr [][]byte var procPath string var exists bool env = make(map[string]string, 0) procPath = fmt.Sprintf("/proc/%v/environ", pid) if exists, err = paths.RealPathExists(&procPath); err != nil { return } if !exists { err = errors.New(fmt.Sprintf("information for pid %v does not exist", pid)) return } if envBytes, err = ioutil.ReadFile(procPath); err != nil { return } envArr = bytes.Split(envBytes, []byte{0x0}) for _, b := range envArr { // s := strings.TrimSpace(string(b)) s := string(b) e := strings.SplitN(s, "=", 2) for _, i := range e { if len(i) != 2 { env[string(i[0])] = "" continue } env[string(i[0])] = string(i[1]) } } return }