package main /* This is a small utility that is designed to accompany the vyatta-yggdrasil package. It takes a HJSON configuration file, makes changes to it based on the command line arguments, and then spits out an updated file. */ import ( "bytes" "encoding/json" "flag" "fmt" "io/ioutil" "os" "reflect" "strconv" "strings" "github.com/hjson/hjson-go" "golang.org/x/text/encoding/unicode" "github.com/yggdrasil-network/yggdrasil-go/src/config" ) type nodeConfig = config.NodeConfig func main() { useconffile := flag.String("useconffile", "/etc/yggdrasil.conf", "configuration file") usejson := flag.Bool("json", false, "produce new config as JSON instead of HJSON") flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [-useconffile path] [-json] action foo bar ...\n\n", os.Args[0]) fmt.Println("yggdrasilconf is a utility designed to make it easier to modify the") fmt.Println("yggdrasil.conf file without resorting to using string editing like") fmt.Println("sed and awk. yggdrasilconf guarantees that the output config will") fmt.Println("always be valid and correctly formatted for the Yggdrasil version.") fmt.Println("This utility will output new configuration to stdout - it does not") fmt.Println("modify the filesystem. You must redirect the output to store it.") fmt.Println() fmt.Println("Valid actions are 'get', 'set', 'add' and 'del', followed by the\npath of the configuration item. Examples:") fmt.Println() fmt.Println(os.Args[0], "get NodeInfo name") fmt.Println(os.Args[0], "set IfName auto") fmt.Println(os.Args[0], "add Peers tcp://a.b.c.d:e") fmt.Println(os.Args[0], "add InterfacePeers eth0 tcp://a.b.c.d:e") fmt.Println(os.Args[0], "del Peers tcp://a.b.c.d:e") fmt.Println() fmt.Println("Options:") flag.PrintDefaults() fmt.Println() fmt.Println("Please note that options must always specified BEFORE the action\non the command line or they will be ignored.") } flag.Parse() flags := flag.Args() if len(flags) == 0 { flag.Usage() os.Exit(1) } action := flags[0] switch strings.ToLower(flags[0]) { case "get", "set", "add", "del": action = strings.ToLower(flags[0]) default: flag.Usage() os.Exit(1) } cfg := nodeConfig{} var config []byte var err error config, err = ioutil.ReadFile(*useconffile) if err != nil { panic(err) } if bytes.Compare(config[0:2], []byte{0xFF, 0xFE}) == 0 || bytes.Compare(config[0:2], []byte{0xFE, 0xFF}) == 0 { utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM) decoder := utf.NewDecoder() config, err = decoder.Bytes(config) if err != nil { panic(err) } } var dat map[string]interface{} if err = hjson.Unmarshal(config, &dat); err != nil { panic(err) } confJSON, err := json.Marshal(dat) if err != nil { panic(err) } json.Unmarshal(confJSON, &cfg) item := reflect.ValueOf(cfg) for index, arg := range flags { switch index { case 0: continue case len(flags) - 1: if action != "get" { break } fallthrough default: switch item.Kind() { case reflect.Map: found := false for _, key := range item.MapKeys() { if key.String() == arg { item = item.MapIndex(key) found = true break } } if !found { t := reflect.TypeOf(item.Interface()) k := reflect.ValueOf(arg) v := reflect.New(t) item.SetMapIndex(k, v) item = item.MapIndex(k) } continue case reflect.Array: continue case reflect.Struct: item = item.FieldByName(arg) continue } if !item.IsValid() { os.Exit(1) } } } switch action { case "get": var bs []byte if *usejson { if bs, err = json.Marshal(item.Interface()); err == nil { fmt.Println(string(bs)) } } else { if bs, err = hjson.Marshal(item.Interface()); err == nil { fmt.Println(string(bs)) } } if err != nil { panic(err) } return case "set": name := flags[len(flags)-2:][0] value := flags[len(flags)-1:][0] switch item.Kind() { case reflect.Struct: field := item.FieldByName(name) if !field.IsValid() { break } switch field.Kind() { case reflect.String: field.SetString(value) case reflect.Bool: field.SetBool(value == "true") case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if int, ierr := strconv.ParseInt(value, 10, 64); ierr == nil { field.SetInt(int) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if uint, uerr := strconv.ParseUint(value, 10, 64); uerr == nil { field.SetUint(uint) } } case reflect.Map: item.SetMapIndex(reflect.ValueOf(name), reflect.ValueOf(value)) } case "add": value := flags[len(flags)-1:][0] switch item.Kind() { case reflect.Slice: fallthrough case reflect.Array: if item.CanSet() { fmt.Println("add", value, "to", item) item.Set(reflect.Append(item, reflect.ValueOf(value))) } else { fmt.Println("can't add", value, "to", item) } } case "del": /*value := flags[len(flags)-1:][0] switch item.Kind() { case reflect.Slice: fallthrough case reflect.Array: }*/ } var bs []byte if *usejson { if bs, err = json.Marshal(cfg); err == nil { fmt.Println(string(bs)) } } else { if bs, err = hjson.Marshal(cfg); err == nil { fmt.Println(string(bs)) } } }