os.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. package stdlib
  2. import (
  3. "fmt"
  4. "io"
  5. "io/ioutil"
  6. "os"
  7. "os/exec"
  8. "runtime"
  9. "github.com/d5/tengo/v2"
  10. )
  11. var osModule = map[string]tengo.Object{
  12. "platform": &tengo.String{Value: runtime.GOOS},
  13. "arch": &tengo.String{Value: runtime.GOARCH},
  14. "o_rdonly": &tengo.Int{Value: int64(os.O_RDONLY)},
  15. "o_wronly": &tengo.Int{Value: int64(os.O_WRONLY)},
  16. "o_rdwr": &tengo.Int{Value: int64(os.O_RDWR)},
  17. "o_append": &tengo.Int{Value: int64(os.O_APPEND)},
  18. "o_create": &tengo.Int{Value: int64(os.O_CREATE)},
  19. "o_excl": &tengo.Int{Value: int64(os.O_EXCL)},
  20. "o_sync": &tengo.Int{Value: int64(os.O_SYNC)},
  21. "o_trunc": &tengo.Int{Value: int64(os.O_TRUNC)},
  22. "mode_dir": &tengo.Int{Value: int64(os.ModeDir)},
  23. "mode_append": &tengo.Int{Value: int64(os.ModeAppend)},
  24. "mode_exclusive": &tengo.Int{Value: int64(os.ModeExclusive)},
  25. "mode_temporary": &tengo.Int{Value: int64(os.ModeTemporary)},
  26. "mode_symlink": &tengo.Int{Value: int64(os.ModeSymlink)},
  27. "mode_device": &tengo.Int{Value: int64(os.ModeDevice)},
  28. "mode_named_pipe": &tengo.Int{Value: int64(os.ModeNamedPipe)},
  29. "mode_socket": &tengo.Int{Value: int64(os.ModeSocket)},
  30. "mode_setuid": &tengo.Int{Value: int64(os.ModeSetuid)},
  31. "mode_setgui": &tengo.Int{Value: int64(os.ModeSetgid)},
  32. "mode_char_device": &tengo.Int{Value: int64(os.ModeCharDevice)},
  33. "mode_sticky": &tengo.Int{Value: int64(os.ModeSticky)},
  34. "mode_type": &tengo.Int{Value: int64(os.ModeType)},
  35. "mode_perm": &tengo.Int{Value: int64(os.ModePerm)},
  36. "path_separator": &tengo.Char{Value: os.PathSeparator},
  37. "path_list_separator": &tengo.Char{Value: os.PathListSeparator},
  38. "dev_null": &tengo.String{Value: os.DevNull},
  39. "seek_set": &tengo.Int{Value: int64(io.SeekStart)},
  40. "seek_cur": &tengo.Int{Value: int64(io.SeekCurrent)},
  41. "seek_end": &tengo.Int{Value: int64(io.SeekEnd)},
  42. "args": &tengo.UserFunction{
  43. Name: "args",
  44. Value: osArgs,
  45. }, // args() => array(string)
  46. "chdir": &tengo.UserFunction{
  47. Name: "chdir",
  48. Value: FuncASRE(os.Chdir),
  49. }, // chdir(dir string) => error
  50. "chmod": osFuncASFmRE("chmod", os.Chmod), // chmod(name string, mode int) => error
  51. "chown": &tengo.UserFunction{
  52. Name: "chown",
  53. Value: FuncASIIRE(os.Chown),
  54. }, // chown(name string, uid int, gid int) => error
  55. "clearenv": &tengo.UserFunction{
  56. Name: "clearenv",
  57. Value: FuncAR(os.Clearenv),
  58. }, // clearenv()
  59. "environ": &tengo.UserFunction{
  60. Name: "environ",
  61. Value: FuncARSs(os.Environ),
  62. }, // environ() => array(string)
  63. "exit": &tengo.UserFunction{
  64. Name: "exit",
  65. Value: FuncAIR(os.Exit),
  66. }, // exit(code int)
  67. "expand_env": &tengo.UserFunction{
  68. Name: "expand_env",
  69. Value: osExpandEnv,
  70. }, // expand_env(s string) => string
  71. "getegid": &tengo.UserFunction{
  72. Name: "getegid",
  73. Value: FuncARI(os.Getegid),
  74. }, // getegid() => int
  75. "getenv": &tengo.UserFunction{
  76. Name: "getenv",
  77. Value: FuncASRS(os.Getenv),
  78. }, // getenv(s string) => string
  79. "geteuid": &tengo.UserFunction{
  80. Name: "geteuid",
  81. Value: FuncARI(os.Geteuid),
  82. }, // geteuid() => int
  83. "getgid": &tengo.UserFunction{
  84. Name: "getgid",
  85. Value: FuncARI(os.Getgid),
  86. }, // getgid() => int
  87. "getgroups": &tengo.UserFunction{
  88. Name: "getgroups",
  89. Value: FuncARIsE(os.Getgroups),
  90. }, // getgroups() => array(string)/error
  91. "getpagesize": &tengo.UserFunction{
  92. Name: "getpagesize",
  93. Value: FuncARI(os.Getpagesize),
  94. }, // getpagesize() => int
  95. "getpid": &tengo.UserFunction{
  96. Name: "getpid",
  97. Value: FuncARI(os.Getpid),
  98. }, // getpid() => int
  99. "getppid": &tengo.UserFunction{
  100. Name: "getppid",
  101. Value: FuncARI(os.Getppid),
  102. }, // getppid() => int
  103. "getuid": &tengo.UserFunction{
  104. Name: "getuid",
  105. Value: FuncARI(os.Getuid),
  106. }, // getuid() => int
  107. "getwd": &tengo.UserFunction{
  108. Name: "getwd",
  109. Value: FuncARSE(os.Getwd),
  110. }, // getwd() => string/error
  111. "hostname": &tengo.UserFunction{
  112. Name: "hostname",
  113. Value: FuncARSE(os.Hostname),
  114. }, // hostname() => string/error
  115. "lchown": &tengo.UserFunction{
  116. Name: "lchown",
  117. Value: FuncASIIRE(os.Lchown),
  118. }, // lchown(name string, uid int, gid int) => error
  119. "link": &tengo.UserFunction{
  120. Name: "link",
  121. Value: FuncASSRE(os.Link),
  122. }, // link(oldname string, newname string) => error
  123. "lookup_env": &tengo.UserFunction{
  124. Name: "lookup_env",
  125. Value: osLookupEnv,
  126. }, // lookup_env(key string) => string/false
  127. "mkdir": osFuncASFmRE("mkdir", os.Mkdir), // mkdir(name string, perm int) => error
  128. "mkdir_all": osFuncASFmRE("mkdir_all", os.MkdirAll), // mkdir_all(name string, perm int) => error
  129. "readlink": &tengo.UserFunction{
  130. Name: "readlink",
  131. Value: FuncASRSE(os.Readlink),
  132. }, // readlink(name string) => string/error
  133. "remove": &tengo.UserFunction{
  134. Name: "remove",
  135. Value: FuncASRE(os.Remove),
  136. }, // remove(name string) => error
  137. "remove_all": &tengo.UserFunction{
  138. Name: "remove_all",
  139. Value: FuncASRE(os.RemoveAll),
  140. }, // remove_all(name string) => error
  141. "rename": &tengo.UserFunction{
  142. Name: "rename",
  143. Value: FuncASSRE(os.Rename),
  144. }, // rename(oldpath string, newpath string) => error
  145. "setenv": &tengo.UserFunction{
  146. Name: "setenv",
  147. Value: FuncASSRE(os.Setenv),
  148. }, // setenv(key string, value string) => error
  149. "symlink": &tengo.UserFunction{
  150. Name: "symlink",
  151. Value: FuncASSRE(os.Symlink),
  152. }, // symlink(oldname string newname string) => error
  153. "temp_dir": &tengo.UserFunction{
  154. Name: "temp_dir",
  155. Value: FuncARS(os.TempDir),
  156. }, // temp_dir() => string
  157. "truncate": &tengo.UserFunction{
  158. Name: "truncate",
  159. Value: FuncASI64RE(os.Truncate),
  160. }, // truncate(name string, size int) => error
  161. "unsetenv": &tengo.UserFunction{
  162. Name: "unsetenv",
  163. Value: FuncASRE(os.Unsetenv),
  164. }, // unsetenv(key string) => error
  165. "create": &tengo.UserFunction{
  166. Name: "create",
  167. Value: osCreate,
  168. }, // create(name string) => imap(file)/error
  169. "open": &tengo.UserFunction{
  170. Name: "open",
  171. Value: osOpen,
  172. }, // open(name string) => imap(file)/error
  173. "open_file": &tengo.UserFunction{
  174. Name: "open_file",
  175. Value: osOpenFile,
  176. }, // open_file(name string, flag int, perm int) => imap(file)/error
  177. "find_process": &tengo.UserFunction{
  178. Name: "find_process",
  179. Value: osFindProcess,
  180. }, // find_process(pid int) => imap(process)/error
  181. "start_process": &tengo.UserFunction{
  182. Name: "start_process",
  183. Value: osStartProcess,
  184. }, // start_process(name string, argv array(string), dir string, env array(string)) => imap(process)/error
  185. "exec_look_path": &tengo.UserFunction{
  186. Name: "exec_look_path",
  187. Value: FuncASRSE(exec.LookPath),
  188. }, // exec_look_path(file) => string/error
  189. "exec": &tengo.UserFunction{
  190. Name: "exec",
  191. Value: osExec,
  192. }, // exec(name, args...) => command
  193. "stat": &tengo.UserFunction{
  194. Name: "stat",
  195. Value: osStat,
  196. }, // stat(name) => imap(fileinfo)/error
  197. "read_file": &tengo.UserFunction{
  198. Name: "read_file",
  199. Value: osReadFile,
  200. }, // readfile(name) => array(byte)/error
  201. }
  202. func osReadFile(args ...tengo.Object) (ret tengo.Object, err error) {
  203. if len(args) != 1 {
  204. return nil, tengo.ErrWrongNumArguments
  205. }
  206. fname, ok := tengo.ToString(args[0])
  207. if !ok {
  208. return nil, tengo.ErrInvalidArgumentType{
  209. Name: "first",
  210. Expected: "string(compatible)",
  211. Found: args[0].TypeName(),
  212. }
  213. }
  214. bytes, err := ioutil.ReadFile(fname)
  215. if err != nil {
  216. return wrapError(err), nil
  217. }
  218. if len(bytes) > tengo.MaxBytesLen {
  219. return nil, tengo.ErrBytesLimit
  220. }
  221. return &tengo.Bytes{Value: bytes}, nil
  222. }
  223. func osStat(args ...tengo.Object) (ret tengo.Object, err error) {
  224. if len(args) != 1 {
  225. return nil, tengo.ErrWrongNumArguments
  226. }
  227. fname, ok := tengo.ToString(args[0])
  228. if !ok {
  229. return nil, tengo.ErrInvalidArgumentType{
  230. Name: "first",
  231. Expected: "string(compatible)",
  232. Found: args[0].TypeName(),
  233. }
  234. }
  235. stat, err := os.Stat(fname)
  236. if err != nil {
  237. return wrapError(err), nil
  238. }
  239. fstat := &tengo.ImmutableMap{
  240. Value: map[string]tengo.Object{
  241. "name": &tengo.String{Value: stat.Name()},
  242. "mtime": &tengo.Time{Value: stat.ModTime()},
  243. "size": &tengo.Int{Value: stat.Size()},
  244. "mode": &tengo.Int{Value: int64(stat.Mode())},
  245. },
  246. }
  247. if stat.IsDir() {
  248. fstat.Value["directory"] = tengo.TrueValue
  249. } else {
  250. fstat.Value["directory"] = tengo.FalseValue
  251. }
  252. return fstat, nil
  253. }
  254. func osCreate(args ...tengo.Object) (tengo.Object, error) {
  255. if len(args) != 1 {
  256. return nil, tengo.ErrWrongNumArguments
  257. }
  258. s1, ok := tengo.ToString(args[0])
  259. if !ok {
  260. return nil, tengo.ErrInvalidArgumentType{
  261. Name: "first",
  262. Expected: "string(compatible)",
  263. Found: args[0].TypeName(),
  264. }
  265. }
  266. res, err := os.Create(s1)
  267. if err != nil {
  268. return wrapError(err), nil
  269. }
  270. return makeOSFile(res), nil
  271. }
  272. func osOpen(args ...tengo.Object) (tengo.Object, error) {
  273. if len(args) != 1 {
  274. return nil, tengo.ErrWrongNumArguments
  275. }
  276. s1, ok := tengo.ToString(args[0])
  277. if !ok {
  278. return nil, tengo.ErrInvalidArgumentType{
  279. Name: "first",
  280. Expected: "string(compatible)",
  281. Found: args[0].TypeName(),
  282. }
  283. }
  284. res, err := os.Open(s1)
  285. if err != nil {
  286. return wrapError(err), nil
  287. }
  288. return makeOSFile(res), nil
  289. }
  290. func osOpenFile(args ...tengo.Object) (tengo.Object, error) {
  291. if len(args) != 3 {
  292. return nil, tengo.ErrWrongNumArguments
  293. }
  294. s1, ok := tengo.ToString(args[0])
  295. if !ok {
  296. return nil, tengo.ErrInvalidArgumentType{
  297. Name: "first",
  298. Expected: "string(compatible)",
  299. Found: args[0].TypeName(),
  300. }
  301. }
  302. i2, ok := tengo.ToInt(args[1])
  303. if !ok {
  304. return nil, tengo.ErrInvalidArgumentType{
  305. Name: "second",
  306. Expected: "int(compatible)",
  307. Found: args[1].TypeName(),
  308. }
  309. }
  310. i3, ok := tengo.ToInt(args[2])
  311. if !ok {
  312. return nil, tengo.ErrInvalidArgumentType{
  313. Name: "third",
  314. Expected: "int(compatible)",
  315. Found: args[2].TypeName(),
  316. }
  317. }
  318. res, err := os.OpenFile(s1, i2, os.FileMode(i3))
  319. if err != nil {
  320. return wrapError(err), nil
  321. }
  322. return makeOSFile(res), nil
  323. }
  324. func osArgs(args ...tengo.Object) (tengo.Object, error) {
  325. if len(args) != 0 {
  326. return nil, tengo.ErrWrongNumArguments
  327. }
  328. arr := &tengo.Array{}
  329. for _, osArg := range os.Args {
  330. if len(osArg) > tengo.MaxStringLen {
  331. return nil, tengo.ErrStringLimit
  332. }
  333. arr.Value = append(arr.Value, &tengo.String{Value: osArg})
  334. }
  335. return arr, nil
  336. }
  337. func osFuncASFmRE(
  338. name string,
  339. fn func(string, os.FileMode) error,
  340. ) *tengo.UserFunction {
  341. return &tengo.UserFunction{
  342. Name: name,
  343. Value: func(args ...tengo.Object) (tengo.Object, error) {
  344. if len(args) != 2 {
  345. return nil, tengo.ErrWrongNumArguments
  346. }
  347. s1, ok := tengo.ToString(args[0])
  348. if !ok {
  349. return nil, tengo.ErrInvalidArgumentType{
  350. Name: "first",
  351. Expected: "string(compatible)",
  352. Found: args[0].TypeName(),
  353. }
  354. }
  355. i2, ok := tengo.ToInt64(args[1])
  356. if !ok {
  357. return nil, tengo.ErrInvalidArgumentType{
  358. Name: "second",
  359. Expected: "int(compatible)",
  360. Found: args[1].TypeName(),
  361. }
  362. }
  363. return wrapError(fn(s1, os.FileMode(i2))), nil
  364. },
  365. }
  366. }
  367. func osLookupEnv(args ...tengo.Object) (tengo.Object, error) {
  368. if len(args) != 1 {
  369. return nil, tengo.ErrWrongNumArguments
  370. }
  371. s1, ok := tengo.ToString(args[0])
  372. if !ok {
  373. return nil, tengo.ErrInvalidArgumentType{
  374. Name: "first",
  375. Expected: "string(compatible)",
  376. Found: args[0].TypeName(),
  377. }
  378. }
  379. res, ok := os.LookupEnv(s1)
  380. if !ok {
  381. return tengo.FalseValue, nil
  382. }
  383. if len(res) > tengo.MaxStringLen {
  384. return nil, tengo.ErrStringLimit
  385. }
  386. return &tengo.String{Value: res}, nil
  387. }
  388. func osExpandEnv(args ...tengo.Object) (tengo.Object, error) {
  389. if len(args) != 1 {
  390. return nil, tengo.ErrWrongNumArguments
  391. }
  392. s1, ok := tengo.ToString(args[0])
  393. if !ok {
  394. return nil, tengo.ErrInvalidArgumentType{
  395. Name: "first",
  396. Expected: "string(compatible)",
  397. Found: args[0].TypeName(),
  398. }
  399. }
  400. var vlen int
  401. var failed bool
  402. s := os.Expand(s1, func(k string) string {
  403. if failed {
  404. return ""
  405. }
  406. v := os.Getenv(k)
  407. // this does not count the other texts that are not being replaced
  408. // but the code checks the final length at the end
  409. vlen += len(v)
  410. if vlen > tengo.MaxStringLen {
  411. failed = true
  412. return ""
  413. }
  414. return v
  415. })
  416. if failed || len(s) > tengo.MaxStringLen {
  417. return nil, tengo.ErrStringLimit
  418. }
  419. return &tengo.String{Value: s}, nil
  420. }
  421. func osExec(args ...tengo.Object) (tengo.Object, error) {
  422. if len(args) == 0 {
  423. return nil, tengo.ErrWrongNumArguments
  424. }
  425. name, ok := tengo.ToString(args[0])
  426. if !ok {
  427. return nil, tengo.ErrInvalidArgumentType{
  428. Name: "first",
  429. Expected: "string(compatible)",
  430. Found: args[0].TypeName(),
  431. }
  432. }
  433. var execArgs []string
  434. for idx, arg := range args[1:] {
  435. execArg, ok := tengo.ToString(arg)
  436. if !ok {
  437. return nil, tengo.ErrInvalidArgumentType{
  438. Name: fmt.Sprintf("args[%d]", idx),
  439. Expected: "string(compatible)",
  440. Found: args[1+idx].TypeName(),
  441. }
  442. }
  443. execArgs = append(execArgs, execArg)
  444. }
  445. return makeOSExecCommand(exec.Command(name, execArgs...)), nil
  446. }
  447. func osFindProcess(args ...tengo.Object) (tengo.Object, error) {
  448. if len(args) != 1 {
  449. return nil, tengo.ErrWrongNumArguments
  450. }
  451. i1, ok := tengo.ToInt(args[0])
  452. if !ok {
  453. return nil, tengo.ErrInvalidArgumentType{
  454. Name: "first",
  455. Expected: "int(compatible)",
  456. Found: args[0].TypeName(),
  457. }
  458. }
  459. proc, err := os.FindProcess(i1)
  460. if err != nil {
  461. return wrapError(err), nil
  462. }
  463. return makeOSProcess(proc), nil
  464. }
  465. func osStartProcess(args ...tengo.Object) (tengo.Object, error) {
  466. if len(args) != 4 {
  467. return nil, tengo.ErrWrongNumArguments
  468. }
  469. name, ok := tengo.ToString(args[0])
  470. if !ok {
  471. return nil, tengo.ErrInvalidArgumentType{
  472. Name: "first",
  473. Expected: "string(compatible)",
  474. Found: args[0].TypeName(),
  475. }
  476. }
  477. var argv []string
  478. var err error
  479. switch arg1 := args[1].(type) {
  480. case *tengo.Array:
  481. argv, err = stringArray(arg1.Value, "second")
  482. if err != nil {
  483. return nil, err
  484. }
  485. case *tengo.ImmutableArray:
  486. argv, err = stringArray(arg1.Value, "second")
  487. if err != nil {
  488. return nil, err
  489. }
  490. default:
  491. return nil, tengo.ErrInvalidArgumentType{
  492. Name: "second",
  493. Expected: "array",
  494. Found: arg1.TypeName(),
  495. }
  496. }
  497. dir, ok := tengo.ToString(args[2])
  498. if !ok {
  499. return nil, tengo.ErrInvalidArgumentType{
  500. Name: "third",
  501. Expected: "string(compatible)",
  502. Found: args[2].TypeName(),
  503. }
  504. }
  505. var env []string
  506. switch arg3 := args[3].(type) {
  507. case *tengo.Array:
  508. env, err = stringArray(arg3.Value, "fourth")
  509. if err != nil {
  510. return nil, err
  511. }
  512. case *tengo.ImmutableArray:
  513. env, err = stringArray(arg3.Value, "fourth")
  514. if err != nil {
  515. return nil, err
  516. }
  517. default:
  518. return nil, tengo.ErrInvalidArgumentType{
  519. Name: "fourth",
  520. Expected: "array",
  521. Found: arg3.TypeName(),
  522. }
  523. }
  524. proc, err := os.StartProcess(name, argv, &os.ProcAttr{
  525. Dir: dir,
  526. Env: env,
  527. })
  528. if err != nil {
  529. return wrapError(err), nil
  530. }
  531. return makeOSProcess(proc), nil
  532. }
  533. func stringArray(arr []tengo.Object, argName string) ([]string, error) {
  534. var sarr []string
  535. for idx, elem := range arr {
  536. str, ok := elem.(*tengo.String)
  537. if !ok {
  538. return nil, tengo.ErrInvalidArgumentType{
  539. Name: fmt.Sprintf("%s[%d]", argName, idx),
  540. Expected: "string",
  541. Found: elem.TypeName(),
  542. }
  543. }
  544. sarr = append(sarr, str.Value)
  545. }
  546. return sarr, nil
  547. }