diff --git a/libs/eavmlib/src/atomvm.erl b/libs/eavmlib/src/atomvm.erl index ba21145d9..8e10bf4b6 100644 --- a/libs/eavmlib/src/atomvm.erl +++ b/libs/eavmlib/src/atomvm.erl @@ -347,14 +347,17 @@ get_creation() -> %% @param Path path to the command to execute %% @param Args arguments to pass to the command. First item is the name %% of the command -%% @param Envp environment variables to pass to the command. +%% @param Envp environment variables to pass to the command or `undefined' +%% to use environ (VM environment variables) %% @param Options options to run execve. Should be `[stdout]' %% @returns a tuple with the process id and a fd to the stdout of the process. %% @doc Fork and execute a program using fork(2) and execve(2). Pipe stdout %% so output of the program can be read with `atomvm:posix_read/2'. %% @end %%----------------------------------------------------------------------------- --spec subprocess(Path :: iodata(), Args :: [iodata()], Env :: [iodata()], Options :: [stdout]) -> +-spec subprocess( + Path :: iodata(), Args :: [iodata()], Env :: [iodata()] | undefined, Options :: [stdout] +) -> {ok, non_neg_integer(), posix_fd()} | {error, posix_error()}. subprocess(_Path, _Args, _Env, _Options) -> erlang:nif_error(undefined). diff --git a/src/libAtomVM/posix_nifs.c b/src/libAtomVM/posix_nifs.c index 0c10b33a6..28e1d2507 100644 --- a/src/libAtomVM/posix_nifs.c +++ b/src/libAtomVM/posix_nifs.c @@ -58,6 +58,10 @@ #include "nifs.h" #include "posix_nifs.h" +#if HAVE_EXECVE +extern char **environ; +#endif + term posix_errno_to_term(int err, GlobalContext *glb) { #if HAVE_OPEN && HAVE_CLOSE || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_SETTIMEOFDAY) @@ -511,6 +515,9 @@ static term nif_atomvm_posix_select_stop(Context *ctx, int argc, term argv[]) #if HAVE_EXECVE static void free_string_list(char **list) { + if (IS_NULL_PTR(list)) { + return; + } char **ptr = list; while (*ptr) { char *str = *ptr; @@ -564,11 +571,18 @@ static term nif_atomvm_subprocess(Context *ctx, int argc, term argv[]) free(path); RAISE_ERROR(BADARG_ATOM); } - char **envp = parse_string_list(argv[2]); - if (IS_NULL_PTR(envp)) { - free(path); - free_string_list(args); - RAISE_ERROR(BADARG_ATOM); + char **envp; + char **envp_array = NULL; + if (argv[2] == UNDEFINED_ATOM) { + envp = environ; + } else { + envp_array = parse_string_list(argv[2]); + if (IS_NULL_PTR(envp_array)) { + free(path); + free_string_list(args); + RAISE_ERROR(BADARG_ATOM); + } + envp = envp_array; } int pstdout[2]; @@ -576,7 +590,7 @@ static term nif_atomvm_subprocess(Context *ctx, int argc, term argv[]) if (r < 0) { free(path); free_string_list(args); - free_string_list(envp); + free_string_list(envp_array); return errno_to_error_tuple_maybe_gc(ctx); } pid_t pid; @@ -609,7 +623,7 @@ static term nif_atomvm_subprocess(Context *ctx, int argc, term argv[]) if (UNLIKELY(r != 0)) { free(path); free_string_list(args); - free_string_list(envp); + free_string_list(envp_array); close(pstdout[0]); close(pstdout[1]); return error_tuple_maybe_gc(r, ctx); @@ -620,7 +634,7 @@ static term nif_atomvm_subprocess(Context *ctx, int argc, term argv[]) int err = errno; free(path); free_string_list(args); - free_string_list(envp); + free_string_list(envp_array); close(pstdout[0]); close(pstdout[1]); return error_tuple_maybe_gc(err, ctx); @@ -646,7 +660,7 @@ static term nif_atomvm_subprocess(Context *ctx, int argc, term argv[]) close(pstdout[1]); // close write-end of the pipe free(path); free_string_list(args); - free_string_list(envp); + free_string_list(envp_array); if (UNLIKELY(memory_ensure_free_opt(ctx, TUPLE_SIZE(3) + TERM_BOXED_RESOURCE_SIZE, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); diff --git a/tests/libs/eavmlib/test_file.erl b/tests/libs/eavmlib/test_file.erl index 775ed6643..679d75a75 100644 --- a/tests/libs/eavmlib/test_file.erl +++ b/tests/libs/eavmlib/test_file.erl @@ -322,7 +322,7 @@ test_subprocess(true) -> ok. test_subprocess_echo() -> - {ok, _Pid, StdoutFd} = atomvm:subprocess("/bin/echo", ["echo"], [], [stdout]), + {ok, _Pid, StdoutFd} = atomvm:subprocess("/bin/echo", ["echo"], undefined, [stdout]), {ok, <<"\n">>} = atomvm:posix_read(StdoutFd, 10), eof = atomvm:posix_read(StdoutFd, 10), ok = atomvm:posix_close(StdoutFd), diff --git a/tests/libs/estdlib/test_epmd.erl b/tests/libs/estdlib/test_epmd.erl index ade9ad500..18dce2947 100644 --- a/tests/libs/estdlib/test_epmd.erl +++ b/tests/libs/estdlib/test_epmd.erl @@ -39,7 +39,9 @@ has_command("BEAM", Command) -> R = os:cmd("command -v " ++ Command), R =/= []; has_command("ATOM", Command) -> - {ok, _, Fd} = atomvm:subprocess("/bin/sh", ["sh", "-c", "command -v " ++ Command], [], [stdout]), + {ok, _, Fd} = atomvm:subprocess("/bin/sh", ["sh", "-c", "command -v " ++ Command], undefined, [ + stdout + ]), Result = case atomvm:posix_read(Fd, 200) of eof -> false; @@ -52,7 +54,7 @@ ensure_epmd("BEAM") -> _ = os:cmd("epmd -daemon"), ok; ensure_epmd("ATOM") -> - {ok, _, Fd} = atomvm:subprocess("/bin/sh", ["sh", "-c", "epmd -daemon"], [], [stdout]), + {ok, _, Fd} = atomvm:subprocess("/bin/sh", ["sh", "-c", "epmd -daemon"], undefined, [stdout]), ok = atomvm:posix_close(Fd), ok.