func RunModule(module Module) { var output types.Value = nil defer func() { var result = 0 if r := recover(); r != nil { result = 1 if output == nil { output = types.Map{ types.Keyword("success"): types.Bool(false), types.Keyword("error"): types.String(fmt.Sprint(r)), } } } if output == nil { output = types.Map{ types.Keyword("success"): types.Bool(true), } } fmt.Println(edn.DumpString(output)) os.Exit(result) }() var input types.Value = nil var err error = nil if module.TakesInput() { input, err = edn.ParseReader(bufio.NewReader(os.Stdin)) } if err != nil { panic(err) } output, err = module.Exec(input) if err != nil { panic(err) } }
func (self GatherFacts) Exec(_ types.Value) (types.Value, error) { var result types.Map = make(types.Map) result[types.Keyword("os")] = types.String(runtime.GOOS) result[types.Keyword("arch")] = types.String(runtime.GOARCH) var interfaces, err = net.Interfaces() if err != nil { return nil, err } var netifs = make(types.Vector, len(interfaces)) for i, iface := range interfaces { var facemap = make(types.Map) facemap[types.Keyword("name")] = types.String(iface.Name) facemap[types.Keyword("mac-address")] = types.String(iface.HardwareAddr.String()) facemap[types.Keyword("loopback?")] = types.Bool(iface.Flags&net.FlagLoopback != 0) var addrs, err = iface.Addrs() if err != nil { return nil, err } var v4list = (*types.List)(list.New()) var v6list = (*types.List)(list.New()) for _, addr := range addrs { var addrmap = make(types.Map) switch ip := addr.(type) { case *net.IPAddr: var v4 = ip.IP.To4() addrmap[types.Keyword("address")] = types.String(ip.IP.String()) if v4 != nil { v4list.Insert(addrmap) } else { v6list.Insert(addrmap) } break case *net.IPNet: var v4 = ip.IP.To4() addrmap[types.Keyword("address")] = types.String(ip.IP.String()) size, bits := ip.Mask.Size() addrmap[types.Keyword("prefix-length")] = types.Int(size) addrmap[types.Keyword("bit-length")] = types.Int(bits) if v4 != nil { v4list.Insert(addrmap) } else { v6list.Insert(addrmap) } break } } facemap[types.Keyword("ipv4-addresses")] = v4list facemap[types.Keyword("ipv6-addresses")] = v6list netifs[i] = facemap } result[types.Keyword("network-interfaces")] = netifs return result, nil }
func (this HashFile) Exec(input types.Value) (out types.Value, err error) { var inputMap types.Map if i, ok := input.(types.Map); ok { inputMap = i } else { err = errors.New(fmt.Sprintf("expected a map as input, got a %T", input)) return } var hashName string var hashNameElement = inputMap[types.Keyword("hash")] if hashNameElement == nil { hashName = "sha256" } else if h, ok := hashNameElement.(types.String); ok { hashName = string(h) } else if k, ok := hashNameElement.(types.Keyword); ok { hashName = string(k) } else if s, ok := hashNameElement.(types.Symbol); ok { hashName = string(s) } else { err = errors.New(":hash must be a string, keyword, or symbol if specified") return } hashName = strings.ToLower(hashName) var hash hash.Hash if hashName == "md5" { hash = md5.New() } else if hashName == "sha" || hashName == "sha1" || hashName == "sha-1" { hash = sha1.New() } else if hashName == "sha224" || hashName == "sha-224" { hash = sha256.New224() } else if hashName == "sha256" || hashName == "sha-256" { hash = sha256.New() } else if hashName == "sha384" || hashName == "sha-384" { hash = sha512.New384() } else if hashName == "sha512/224" || hashName == "sha-512/224" { hash = sha512.New512_224() } else if hashName == "sha512/256" || hashName == "sha-512/256" { hash = sha512.New512_256() } else if hashName == "sha512" || hashName == "sha-512" { hash = sha512.New() } else { err = errors.New(fmt.Sprint("unknown hash name: ", hashName)) return } var fileName string var fileElem = inputMap[types.Keyword("file")] if fileElem == nil { err = errors.New(":file argument is required") return } else if f, ok := fileElem.(types.String); ok { fileName = string(f) } else { err = errors.New(":file argument must be a string") return } file, err := os.Open(fileName) if err != nil { return } hashOut := bufio.NewWriterSize(hash, hash.BlockSize()) wrote, err := io.Copy(hashOut, file) hashOut.Flush() if err != nil { return } out = types.Map{ types.Keyword("success"): types.Bool(true), types.Keyword("size"): types.Int(wrote), types.Keyword("file"): types.String(fileName), types.Keyword("hash"): types.Keyword(hashName), types.Keyword("digest"): types.String(fmt.Sprintf("%x", hash.Sum(nil))), } return }
// The command module takes as input a map, and runs that command. // // Parameters in the input map are: // :command, a list or vector, giving the command to run. Required. // :env, a map of names to values; if specified, these are added to the environment when running the command; optional // :input, a string to pass to the command's stdin; optional func (this Command) Exec(input types.Value) (output types.Value, err error) { var command []string var commandMap types.Map if m, ok := input.(types.Map); ok { commandMap = m } else { err = errors.New("input must be a map") return } var commandEntry = commandMap[types.Keyword("command")] if commandEntry == nil { err = errors.New("require at least :command in input") return } else if l, ok := commandEntry.(*types.List); ok { var list = (*list.List)(l) command = make([]string, list.Len()) var i = 0 for e := list.Front(); e != nil; e = e.Next() { if elem, ok := e.Value.(types.String); ok { command[i] = string(elem) i++ } else { err = errors.New(":command must be a list of strings") return } } } else if v, ok := commandEntry.(types.Vector); ok { var vect = ([]types.Value)(v) command = make([]string, len(vect)) for i, e := range vect { if elem, ok := e.(types.String); ok { command[i] = string(elem) } else { err = errors.New(":command must be a vector of strings") return } } } else { err = errors.New("expected a list or vector as :command") return } var cmd = exec.Command(command[0], command[1:]...) var envEntry = commandMap[types.Keyword("env")] if envEntry != nil { if e, ok := envEntry.(types.Map); ok { var env = make([]string, len(e)) var i = 0 for k := range e { v := e[k] if kk, ok := k.(types.String); ok && len(kk) > 0 { if vv, ok := v.(types.String); ok && len(vv) > 0 { env[i] = fmt.Sprint(string(kk), "=", string(vv)) } else { err = errors.New(":env values must be nonempty strings") return } } else { err = errors.New(":env keys must be nonempty strings") return } i++ } cmd.Env = env } else { err = errors.New(":env must be a map if specified") return } } var stdinEntry = commandMap[types.Keyword("input")] if stdinEntry != nil { if stdin, ok := stdinEntry.(types.String); ok { cmd.Stdin = strings.NewReader(string(stdin)) } else { err = errors.New(":input must be a string if specified") return } } var stderr = new(bytes.Buffer) var stdout = new(bytes.Buffer) cmd.Stderr = stderr cmd.Stdout = stdout err = cmd.Run() if err != nil { output = types.Map{ types.Keyword("success"): types.Bool(false), types.Keyword("err"): types.String(stderr.String()), types.Keyword("out"): types.String(stdout.String()), types.Keyword("system-time"): types.Float(cmd.ProcessState.SystemTime().Seconds()), types.Keyword("user-time"): types.Float(cmd.ProcessState.UserTime().Seconds()), } return } output = types.Map{ types.Keyword("success"): types.Bool(true), types.Keyword("err"): types.String(stderr.String()), types.Keyword("out"): types.String(stdout.String()), types.Keyword("system-time"): types.Float(cmd.ProcessState.SystemTime().Seconds()), types.Keyword("user-time"): types.Float(cmd.ProcessState.UserTime().Seconds()), } return }
func (this Shell) Exec(input types.Value) (output types.Value, err error) { var commandMap types.Map if m, ok := input.(types.Map); ok { commandMap = m } else { err = errors.New("input must be a map") return } var command string var commandEntry = commandMap[types.Keyword("command")] if commandEntry == nil { err = errors.New(":command argument is required") return } else if c, ok := commandEntry.(types.String); ok { command = string(c) } else { err = errors.New(":command must be a string") return } var shell = "/bin/sh" shellEntry := commandMap[types.Keyword("shell")] if shellEntry != nil { if s, ok := shellEntry.(types.String); ok { shell = string(s) } else { err = errors.New(":shell must be a string if specified") return } } cmd := exec.Command(shell, "-c", command) var envEntry = commandMap[types.Keyword("env")] if envEntry != nil { if e, ok := envEntry.(types.Map); ok { var env = make([]string, len(e)) var i = 0 for k := range e { v := e[k] if kk, ok := k.(types.String); ok && len(kk) > 0 { if vv, ok := v.(types.String); ok && len(vv) > 0 { env[i] = fmt.Sprint(string(kk), "=", string(vv)) } else { err = errors.New(":env values must be nonempty strings") return } } else { err = errors.New(":env keys must be nonempty strings") return } i++ } cmd.Env = env } else { err = errors.New(":env must be a map if specified") return } } inputEntry := commandMap[types.Keyword("input")] if inputEntry != nil { if i, ok := inputEntry.(types.String); ok { cmd.Stdin = strings.NewReader(string(i)) } else { err = errors.New(":input must be a string if specified") } } var stderr = new(bytes.Buffer) var stdout = new(bytes.Buffer) cmd.Stderr = stderr cmd.Stdout = stdout err = cmd.Run() if err != nil { output = types.Map{ types.Keyword("success"): types.Bool(false), types.Keyword("err"): types.String(stderr.String()), types.Keyword("out"): types.String(stdout.String()), types.Keyword("system-time"): types.Float(cmd.ProcessState.SystemTime().Seconds()), types.Keyword("user-time"): types.Float(cmd.ProcessState.UserTime().Seconds()), } return } output = types.Map{ types.Keyword("success"): types.Bool(true), types.Keyword("err"): types.String(stderr.String()), types.Keyword("out"): types.String(stdout.String()), types.Keyword("system-time"): types.Float(cmd.ProcessState.SystemTime().Seconds()), types.Keyword("user-time"): types.Float(cmd.ProcessState.UserTime().Seconds()), } return }
// Lex runs the lexer. Always returns 0. // When the -s option is given, this function is not generated; // instead, the NN_FUN macro runs the lexer. func (yylex *lexer) Lex(lval *yySymType) int { OUTER0: for { switch yylex.next(0) { case 0: { return tWhitespace } case 1: { return tOpenBracket } case 2: { return tCloseBracket } case 3: { return tOpenBrace } case 4: { return tCloseBrace } case 5: { return tOpenParen } case 6: { return tCloseParen } case 7: { return tOctothorpe } case 8: { return tNil } case 9: { lval.v = types.Bool(true) return tTrue } case 10: { lval.v = types.Bool(false) return tFalse } case 11: { lval.v = types.Character('\n') return tCharacter } case 12: { lval.v = types.Character('\r') return tCharacter } case 13: { lval.v = types.Character('\t') return tCharacter } case 14: { lval.v = types.Character(' ') return tCharacter } case 15: { panic("Unicode characters are currently unimplemented") } case 16: { s := yylex.Text()[1:] ch, _, _ := strings.NewReader(s).ReadRune() lval.v = types.Character(ch) return tCharacter } case 17: { lval.v = types.Keyword(yylex.Text()[1:]) return tKeyword } case 18: { s := yylex.Text() lval.v = types.String(s[1 : len(s)-1]) return tString } case 19: { lval.v = types.Symbol(yylex.Text()) return tSymbol } case 20: { lval.v = types.ParseBigInt(yylex.Text()) return tBigInteger } case 21: { lval.v = types.ParseFloat(yylex.Text()) return tFloat } case 22: { lval.v = types.ParseInt(yylex.Text()) return tInteger } case 23: { lval.v = types.ParseFloat(yylex.Text()) return tFloat } case 24: { lval.v = types.ParseFloat(yylex.Text()) return tFloat } case 25: { lval.v = types.ParseFloat(yylex.Text()) return tFloat } case 26: { lval.v = types.ParseRational(yylex.Text()) return tRational } case 27: { // (This rule must be last) // Unmatched token... return -1 } default: break OUTER0 } continue } yylex.pop() return 0 }