123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- package cmdline
- import (
- "io/ioutil"
- "strings"
- "github.com/rancher/os/pkg/util"
- yaml "github.com/cloudfoundry-incubator/candiedyaml"
- )
- func Read(parseAll bool) (m map[interface{}]interface{}, err error) {
- cmdLine, err := ioutil.ReadFile("/proc/cmdline")
- if err != nil {
- return nil, err
- }
- if len(cmdLine) == 0 {
- return nil, nil
- }
- cmdLineObj := Parse(strings.TrimSpace(util.UnescapeKernelParams(string(cmdLine))), parseAll)
- return cmdLineObj, nil
- }
- func GetCmdline(key string) interface{} {
- parseAll := true
- if strings.HasPrefix(key, "cc.") || strings.HasPrefix(key, "rancher.") {
- // the normal case
- parseAll = false
- }
- cmdline, _ := Read(parseAll)
- v, _ := GetOrSetVal(key, cmdline, nil)
- return v
- }
- func GetOrSetVal(args string, data map[interface{}]interface{}, value interface{}) (interface{}, map[interface{}]interface{}) {
- parts := strings.Split(args, ".")
- tData := data
- if value != nil {
- tData = util.MapCopy(data)
- }
- t := tData
- for i, part := range parts {
- val, ok := t[part]
- last := i+1 == len(parts)
- // Reached end, set the value
- if last && value != nil {
- if s, ok := value.(string); ok {
- value = UnmarshalOrReturnString(s)
- }
- t[part] = value
- return value, tData
- }
- // Missing intermediate key, create key
- if !last && value != nil && !ok {
- newData := map[interface{}]interface{}{}
- t[part] = newData
- t = newData
- continue
- }
- if !ok {
- break
- }
- if last {
- return val, tData
- }
- newData, ok := val.(map[interface{}]interface{})
- if !ok {
- break
- }
- t = newData
- }
- return "", tData
- }
- // Replace newlines, colons, and question marks with random strings
- // This is done to avoid YAML treating these as special characters
- var (
- newlineMagicString = "9XsJcx6dR5EERYCC"
- colonMagicString = "V0Rc21pIVknMm2rr"
- questionMarkMagicString = "FoPL6JLMAaJqKMJT"
- )
- func reverseReplacement(result interface{}) interface{} {
- switch val := result.(type) {
- case map[interface{}]interface{}:
- for k, v := range val {
- val[k] = reverseReplacement(v)
- }
- return val
- case []interface{}:
- for i, item := range val {
- val[i] = reverseReplacement(item)
- }
- return val
- case string:
- val = strings.Replace(val, newlineMagicString, "\n", -1)
- val = strings.Replace(val, colonMagicString, ":", -1)
- val = strings.Replace(val, questionMarkMagicString, "?", -1)
- return val
- }
- return result
- }
- func UnmarshalOrReturnString(value string) (result interface{}) {
- value = strings.Replace(value, "\n", newlineMagicString, -1)
- value = strings.Replace(value, ":", colonMagicString, -1)
- value = strings.Replace(value, "?", questionMarkMagicString, -1)
- if err := yaml.Unmarshal([]byte(value), &result); err != nil {
- result = value
- }
- result = reverseReplacement(result)
- return
- }
- func Parse(cmdLine string, parseAll bool) map[interface{}]interface{} {
- result := map[interface{}]interface{}{}
- outer:
- for _, part := range strings.Split(cmdLine, " ") {
- if strings.HasPrefix(part, "cc.") {
- part = part[3:]
- } else if !strings.HasPrefix(part, "rancher.") {
- if !parseAll {
- continue
- }
- }
- var value string
- kv := strings.SplitN(part, "=", 2)
- if len(kv) == 1 {
- value = "true"
- } else {
- value = kv[1]
- }
- current := result
- keys := strings.Split(kv[0], ".")
- for i, key := range keys {
- if i == len(keys)-1 {
- current[key] = UnmarshalOrReturnString(value)
- } else {
- if obj, ok := current[key]; ok {
- if newCurrent, ok := obj.(map[interface{}]interface{}); ok {
- current = newCurrent
- } else {
- continue outer
- }
- } else {
- newCurrent := make(map[interface{}]interface{})
- current[key] = newCurrent
- current = newCurrent
- }
- }
- }
- }
- return result
- }
|