123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- package stdlib
- import (
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "github.com/d5/tengo/v2"
- )
- var osModule = map[string]tengo.Object{
- "o_rdonly": tengo.Int{Value: int64(os.O_RDONLY)},
- "o_wronly": tengo.Int{Value: int64(os.O_WRONLY)},
- "o_rdwr": tengo.Int{Value: int64(os.O_RDWR)},
- "o_append": tengo.Int{Value: int64(os.O_APPEND)},
- "o_create": tengo.Int{Value: int64(os.O_CREATE)},
- "o_excl": tengo.Int{Value: int64(os.O_EXCL)},
- "o_sync": tengo.Int{Value: int64(os.O_SYNC)},
- "o_trunc": tengo.Int{Value: int64(os.O_TRUNC)},
- "mode_dir": tengo.Int{Value: int64(os.ModeDir)},
- "mode_append": tengo.Int{Value: int64(os.ModeAppend)},
- "mode_exclusive": tengo.Int{Value: int64(os.ModeExclusive)},
- "mode_temporary": tengo.Int{Value: int64(os.ModeTemporary)},
- "mode_symlink": tengo.Int{Value: int64(os.ModeSymlink)},
- "mode_device": tengo.Int{Value: int64(os.ModeDevice)},
- "mode_named_pipe": tengo.Int{Value: int64(os.ModeNamedPipe)},
- "mode_socket": tengo.Int{Value: int64(os.ModeSocket)},
- "mode_setuid": tengo.Int{Value: int64(os.ModeSetuid)},
- "mode_setgui": tengo.Int{Value: int64(os.ModeSetgid)},
- "mode_char_device": tengo.Int{Value: int64(os.ModeCharDevice)},
- "mode_sticky": tengo.Int{Value: int64(os.ModeSticky)},
- "mode_type": tengo.Int{Value: int64(os.ModeType)},
- "mode_perm": tengo.Int{Value: int64(os.ModePerm)},
- "path_separator": tengo.Char{Value: os.PathSeparator},
- "path_list_separator": tengo.Char{Value: os.PathListSeparator},
- "dev_null": &tengo.String{Value: os.DevNull},
- "seek_set": tengo.Int{Value: int64(io.SeekStart)},
- "seek_cur": tengo.Int{Value: int64(io.SeekCurrent)},
- "seek_end": tengo.Int{Value: int64(io.SeekEnd)},
- "args": &tengo.UserFunction{
- Name: "args",
- Value: osArgs,
- }, // args() => array(string)
- "chdir": &tengo.UserFunction{
- Name: "chdir",
- Value: FuncASRE(os.Chdir),
- }, // chdir(dir string) => error
- "chmod": osFuncASFmRE("chmod", os.Chmod), // chmod(name string, mode int) => error
- "chown": &tengo.UserFunction{
- Name: "chown",
- Value: FuncASIIRE(os.Chown),
- }, // chown(name string, uid int, gid int) => error
- "clearenv": &tengo.UserFunction{
- Name: "clearenv",
- Value: FuncAR(os.Clearenv),
- }, // clearenv()
- "environ": &tengo.UserFunction{
- Name: "environ",
- Value: FuncARSs(os.Environ),
- }, // environ() => array(string)
- "exit": &tengo.UserFunction{
- Name: "exit",
- Value: FuncAIR(os.Exit),
- }, // exit(code int)
- "expand_env": &tengo.UserFunction{
- Name: "expand_env",
- Value: osExpandEnv,
- }, // expand_env(s string) => string
- "getegid": &tengo.UserFunction{
- Name: "getegid",
- Value: FuncARI(os.Getegid),
- }, // getegid() => int
- "getenv": &tengo.UserFunction{
- Name: "getenv",
- Value: FuncASRS(os.Getenv),
- }, // getenv(s string) => string
- "geteuid": &tengo.UserFunction{
- Name: "geteuid",
- Value: FuncARI(os.Geteuid),
- }, // geteuid() => int
- "getgid": &tengo.UserFunction{
- Name: "getgid",
- Value: FuncARI(os.Getgid),
- }, // getgid() => int
- "getgroups": &tengo.UserFunction{
- Name: "getgroups",
- Value: FuncARIsE(os.Getgroups),
- }, // getgroups() => array(string)/error
- "getpagesize": &tengo.UserFunction{
- Name: "getpagesize",
- Value: FuncARI(os.Getpagesize),
- }, // getpagesize() => int
- "getpid": &tengo.UserFunction{
- Name: "getpid",
- Value: FuncARI(os.Getpid),
- }, // getpid() => int
- "getppid": &tengo.UserFunction{
- Name: "getppid",
- Value: FuncARI(os.Getppid),
- }, // getppid() => int
- "getuid": &tengo.UserFunction{
- Name: "getuid",
- Value: FuncARI(os.Getuid),
- }, // getuid() => int
- "getwd": &tengo.UserFunction{
- Name: "getwd",
- Value: FuncARSE(os.Getwd),
- }, // getwd() => string/error
- "hostname": &tengo.UserFunction{
- Name: "hostname",
- Value: FuncARSE(os.Hostname),
- }, // hostname() => string/error
- "lchown": &tengo.UserFunction{
- Name: "lchown",
- Value: FuncASIIRE(os.Lchown),
- }, // lchown(name string, uid int, gid int) => error
- "link": &tengo.UserFunction{
- Name: "link",
- Value: FuncASSRE(os.Link),
- }, // link(oldname string, newname string) => error
- "lookup_env": &tengo.UserFunction{
- Name: "lookup_env",
- Value: osLookupEnv,
- }, // lookup_env(key string) => string/false
- "mkdir": osFuncASFmRE("mkdir", os.Mkdir), // mkdir(name string, perm int) => error
- "mkdir_all": osFuncASFmRE("mkdir_all", os.MkdirAll), // mkdir_all(name string, perm int) => error
- "readlink": &tengo.UserFunction{
- Name: "readlink",
- Value: FuncASRSE(os.Readlink),
- }, // readlink(name string) => string/error
- "remove": &tengo.UserFunction{
- Name: "remove",
- Value: FuncASRE(os.Remove),
- }, // remove(name string) => error
- "remove_all": &tengo.UserFunction{
- Name: "remove_all",
- Value: FuncASRE(os.RemoveAll),
- }, // remove_all(name string) => error
- "rename": &tengo.UserFunction{
- Name: "rename",
- Value: FuncASSRE(os.Rename),
- }, // rename(oldpath string, newpath string) => error
- "setenv": &tengo.UserFunction{
- Name: "setenv",
- Value: FuncASSRE(os.Setenv),
- }, // setenv(key string, value string) => error
- "symlink": &tengo.UserFunction{
- Name: "symlink",
- Value: FuncASSRE(os.Symlink),
- }, // symlink(oldname string newname string) => error
- "temp_dir": &tengo.UserFunction{
- Name: "temp_dir",
- Value: FuncARS(os.TempDir),
- }, // temp_dir() => string
- "truncate": &tengo.UserFunction{
- Name: "truncate",
- Value: FuncASI64RE(os.Truncate),
- }, // truncate(name string, size int) => error
- "unsetenv": &tengo.UserFunction{
- Name: "unsetenv",
- Value: FuncASRE(os.Unsetenv),
- }, // unsetenv(key string) => error
- "create": &tengo.UserFunction{
- Name: "create",
- Value: osCreate,
- }, // create(name string) => imap(file)/error
- "open": &tengo.UserFunction{
- Name: "open",
- Value: osOpen,
- }, // open(name string) => imap(file)/error
- "open_file": &tengo.UserFunction{
- Name: "open_file",
- Value: osOpenFile,
- }, // open_file(name string, flag int, perm int) => imap(file)/error
- "find_process": &tengo.UserFunction{
- Name: "find_process",
- Value: osFindProcess,
- }, // find_process(pid int) => imap(process)/error
- "start_process": &tengo.UserFunction{
- Name: "start_process",
- Value: osStartProcess,
- }, // start_process(name string, argv array(string), dir string, env array(string)) => imap(process)/error
- "exec_look_path": &tengo.UserFunction{
- Name: "exec_look_path",
- Value: FuncASRSE(exec.LookPath),
- }, // exec_look_path(file) => string/error
- "exec": &tengo.UserFunction{
- Name: "exec",
- Value: osExec,
- }, // exec(name, args...) => command
- "stat": &tengo.UserFunction{
- Name: "stat",
- Value: osStat,
- }, // stat(name) => imap(fileinfo)/error
- "read_file": &tengo.UserFunction{
- Name: "read_file",
- Value: osReadFile,
- }, // readfile(name) => array(byte)/error
- }
- func osReadFile(args ...tengo.Object) (ret tengo.Object, err error) {
- if len(args) != 1 {
- return nil, tengo.ErrWrongNumArguments
- }
- fname, ok := tengo.ToString(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "string(compatible)",
- Found: args[0].TypeName(),
- }
- }
- bytes, err := ioutil.ReadFile(fname)
- if err != nil {
- return wrapError(err), nil
- }
- if len(bytes) > tengo.MaxBytesLen {
- return nil, tengo.ErrBytesLimit
- }
- return &tengo.Bytes{Value: bytes}, nil
- }
- func osStat(args ...tengo.Object) (ret tengo.Object, err error) {
- if len(args) != 1 {
- return nil, tengo.ErrWrongNumArguments
- }
- fname, ok := tengo.ToString(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "string(compatible)",
- Found: args[0].TypeName(),
- }
- }
- stat, err := os.Stat(fname)
- if err != nil {
- return wrapError(err), nil
- }
- fstat := &tengo.ImmutableMap{
- Value: map[string]tengo.Object{
- "name": &tengo.String{Value: stat.Name()},
- "mtime": &tengo.Time{Value: stat.ModTime()},
- "size": tengo.Int{Value: stat.Size()},
- "mode": tengo.Int{Value: int64(stat.Mode())},
- },
- }
- if stat.IsDir() {
- fstat.Value["directory"] = tengo.TrueValue
- } else {
- fstat.Value["directory"] = tengo.FalseValue
- }
- return fstat, nil
- }
- func osCreate(args ...tengo.Object) (tengo.Object, error) {
- if len(args) != 1 {
- return nil, tengo.ErrWrongNumArguments
- }
- s1, ok := tengo.ToString(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "string(compatible)",
- Found: args[0].TypeName(),
- }
- }
- res, err := os.Create(s1)
- if err != nil {
- return wrapError(err), nil
- }
- return makeOSFile(res), nil
- }
- func osOpen(args ...tengo.Object) (tengo.Object, error) {
- if len(args) != 1 {
- return nil, tengo.ErrWrongNumArguments
- }
- s1, ok := tengo.ToString(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "string(compatible)",
- Found: args[0].TypeName(),
- }
- }
- res, err := os.Open(s1)
- if err != nil {
- return wrapError(err), nil
- }
- return makeOSFile(res), nil
- }
- func osOpenFile(args ...tengo.Object) (tengo.Object, error) {
- if len(args) != 3 {
- return nil, tengo.ErrWrongNumArguments
- }
- s1, ok := tengo.ToString(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "string(compatible)",
- Found: args[0].TypeName(),
- }
- }
- i2, ok := tengo.ToInt(args[1])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "second",
- Expected: "int(compatible)",
- Found: args[1].TypeName(),
- }
- }
- i3, ok := tengo.ToInt(args[2])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "third",
- Expected: "int(compatible)",
- Found: args[2].TypeName(),
- }
- }
- res, err := os.OpenFile(s1, i2, os.FileMode(i3))
- if err != nil {
- return wrapError(err), nil
- }
- return makeOSFile(res), nil
- }
- func osArgs(args ...tengo.Object) (tengo.Object, error) {
- if len(args) != 0 {
- return nil, tengo.ErrWrongNumArguments
- }
- arr := &tengo.Array{}
- for _, osArg := range os.Args {
- if len(osArg) > tengo.MaxStringLen {
- return nil, tengo.ErrStringLimit
- }
- arr.Value = append(arr.Value, &tengo.String{Value: osArg})
- }
- return arr, nil
- }
- func osFuncASFmRE(
- name string,
- fn func(string, os.FileMode) error,
- ) *tengo.UserFunction {
- return &tengo.UserFunction{
- Name: name,
- Value: func(args ...tengo.Object) (tengo.Object, error) {
- if len(args) != 2 {
- return nil, tengo.ErrWrongNumArguments
- }
- s1, ok := tengo.ToString(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "string(compatible)",
- Found: args[0].TypeName(),
- }
- }
- i2, ok := tengo.ToInt64(args[1])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "second",
- Expected: "int(compatible)",
- Found: args[1].TypeName(),
- }
- }
- return wrapError(fn(s1, os.FileMode(i2))), nil
- },
- }
- }
- func osLookupEnv(args ...tengo.Object) (tengo.Object, error) {
- if len(args) != 1 {
- return nil, tengo.ErrWrongNumArguments
- }
- s1, ok := tengo.ToString(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "string(compatible)",
- Found: args[0].TypeName(),
- }
- }
- res, ok := os.LookupEnv(s1)
- if !ok {
- return tengo.FalseValue, nil
- }
- if len(res) > tengo.MaxStringLen {
- return nil, tengo.ErrStringLimit
- }
- return &tengo.String{Value: res}, nil
- }
- func osExpandEnv(args ...tengo.Object) (tengo.Object, error) {
- if len(args) != 1 {
- return nil, tengo.ErrWrongNumArguments
- }
- s1, ok := tengo.ToString(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "string(compatible)",
- Found: args[0].TypeName(),
- }
- }
- var vlen int
- var failed bool
- s := os.Expand(s1, func(k string) string {
- if failed {
- return ""
- }
- v := os.Getenv(k)
- // this does not count the other texts that are not being replaced
- // but the code checks the final length at the end
- vlen += len(v)
- if vlen > tengo.MaxStringLen {
- failed = true
- return ""
- }
- return v
- })
- if failed || len(s) > tengo.MaxStringLen {
- return nil, tengo.ErrStringLimit
- }
- return &tengo.String{Value: s}, nil
- }
- func osExec(args ...tengo.Object) (tengo.Object, error) {
- if len(args) == 0 {
- return nil, tengo.ErrWrongNumArguments
- }
- name, ok := tengo.ToString(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "string(compatible)",
- Found: args[0].TypeName(),
- }
- }
- var execArgs []string
- for idx, arg := range args[1:] {
- execArg, ok := tengo.ToString(arg)
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: fmt.Sprintf("args[%d]", idx),
- Expected: "string(compatible)",
- Found: args[1+idx].TypeName(),
- }
- }
- execArgs = append(execArgs, execArg)
- }
- return makeOSExecCommand(exec.Command(name, execArgs...)), nil
- }
- func osFindProcess(args ...tengo.Object) (tengo.Object, error) {
- if len(args) != 1 {
- return nil, tengo.ErrWrongNumArguments
- }
- i1, ok := tengo.ToInt(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "int(compatible)",
- Found: args[0].TypeName(),
- }
- }
- proc, err := os.FindProcess(i1)
- if err != nil {
- return wrapError(err), nil
- }
- return makeOSProcess(proc), nil
- }
- func osStartProcess(args ...tengo.Object) (tengo.Object, error) {
- if len(args) != 4 {
- return nil, tengo.ErrWrongNumArguments
- }
- name, ok := tengo.ToString(args[0])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "first",
- Expected: "string(compatible)",
- Found: args[0].TypeName(),
- }
- }
- var argv []string
- var err error
- switch arg1 := args[1].(type) {
- case *tengo.Array:
- argv, err = stringArray(arg1.Value, "second")
- if err != nil {
- return nil, err
- }
- case *tengo.ImmutableArray:
- argv, err = stringArray(arg1.Value, "second")
- if err != nil {
- return nil, err
- }
- default:
- return nil, tengo.ErrInvalidArgumentType{
- Name: "second",
- Expected: "array",
- Found: arg1.TypeName(),
- }
- }
- dir, ok := tengo.ToString(args[2])
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: "third",
- Expected: "string(compatible)",
- Found: args[2].TypeName(),
- }
- }
- var env []string
- switch arg3 := args[3].(type) {
- case *tengo.Array:
- env, err = stringArray(arg3.Value, "fourth")
- if err != nil {
- return nil, err
- }
- case *tengo.ImmutableArray:
- env, err = stringArray(arg3.Value, "fourth")
- if err != nil {
- return nil, err
- }
- default:
- return nil, tengo.ErrInvalidArgumentType{
- Name: "fourth",
- Expected: "array",
- Found: arg3.TypeName(),
- }
- }
- proc, err := os.StartProcess(name, argv, &os.ProcAttr{
- Dir: dir,
- Env: env,
- })
- if err != nil {
- return wrapError(err), nil
- }
- return makeOSProcess(proc), nil
- }
- func stringArray(arr []tengo.Object, argName string) ([]string, error) {
- var sarr []string
- for idx, elem := range arr {
- str, ok := elem.(*tengo.String)
- if !ok {
- return nil, tengo.ErrInvalidArgumentType{
- Name: fmt.Sprintf("%s[%d]", argName, idx),
- Expected: "string",
- Found: elem.TypeName(),
- }
- }
- sarr = append(sarr, str.Value)
- }
- return sarr, nil
- }
|