1
0
mirror of https://github.com/janet-lang/janet synced 2024-09-07 21:16:58 +00:00

Add os/posix-exec (along os/posix-fork)

Useful for old-style unix daemons, start up scripts, and so on.
Easy to add on top of os/execute.

May want to consider allowing the same IO redirection as os/execute
and os/spawn.

May also want to put both fork and exec behind a config switch since I
suppose some systems may not support them, although I don't know of any
concrete examples.
This commit is contained in:
Calvin Rose 2023-10-08 21:03:08 -05:00
parent 6ae81058aa
commit 549ee95f3d
2 changed files with 44 additions and 6 deletions

View File

@ -0,0 +1,5 @@
# Switch to python
(print "running in Janet")
(os/posix-exec ["python"] :p)
(print "will not print")

View File

@ -1081,11 +1081,18 @@ static JanetFile *get_stdio_for_handle(JanetHandle handle, void *orig, int iswri
} }
#endif #endif
static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) { typedef enum {
JANET_EXECUTE_EXECUTE,
JANET_EXECUTE_SPAWN,
JANET_EXECUTE_EXEC
} JanetExecuteMode;
static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS); janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS);
janet_arity(argc, 1, 3); janet_arity(argc, 1, 3);
/* Get flags */ /* Get flags */
int is_spawn = mode == JANET_EXECUTE_SPAWN;
uint64_t flags = 0; uint64_t flags = 0;
if (argc > 1) { if (argc > 1) {
flags = janet_getflags(argv, 1, "epxd"); flags = janet_getflags(argv, 1, "epxd");
@ -1109,7 +1116,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
int pipe_owner_flags = (is_spawn && (flags & 0x8)) ? JANET_PROC_ALLOW_ZOMBIE : 0; int pipe_owner_flags = (is_spawn && (flags & 0x8)) ? JANET_PROC_ALLOW_ZOMBIE : 0;
/* Get optional redirections */ /* Get optional redirections */
if (argc > 2) { if (argc > 2 && (mode != JANET_EXECUTE_EXEC)) {
JanetDictView tab = janet_getdictionary(argv, 2); JanetDictView tab = janet_getdictionary(argv, 2);
Janet maybe_stdin = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("in")); Janet maybe_stdin = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("in"));
Janet maybe_stdout = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("out")); Janet maybe_stdout = janet_dictionary_get(tab.kvs, tab.cap, janet_ckeywordv("out"));
@ -1230,12 +1237,29 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
* of posix_spawn would modify the argv array passed in. */ * of posix_spawn would modify the argv array passed in. */
char *const *cargv = (char *const *)child_argv; char *const *cargv = (char *const *)child_argv;
/* Use posix_spawn to spawn new process */
if (use_environ) { if (use_environ) {
janet_lock_environ(); janet_lock_environ();
} }
/* exec mode */
if (mode == JANET_EXECUTE_EXEC) {
#ifdef JANET_WINDOWS
janet_panic("not supported on windows");
#else
int status;
do {
if (janet_flag_at(flags, 1)) {
status = execvpe(cargv[0], cargv, use_environ ? environ : envp);
} else {
status = execve(cargv[0], cargv, use_environ ? environ : envp);
}
} while (status == -1 && errno == EINTR);
janet_panicf("%p: %s", cargv[0], strerror(errno ? errno : ENOENT));
#endif
}
/* Use posix_spawn to spawn new process */
/* Posix spawn setup */ /* Posix spawn setup */
posix_spawn_file_actions_t actions; posix_spawn_file_actions_t actions;
posix_spawn_file_actions_init(&actions); posix_spawn_file_actions_init(&actions);
@ -1344,7 +1368,7 @@ JANET_CORE_FN(os_execute,
"contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. " "contain the keys :in, :out, and :err, which allow redirecting stdio in the subprocess. "
"These arguments should be core/file values. " "These arguments should be core/file values. "
"Returns the exit status of the program.") { "Returns the exit status of the program.") {
return os_execute_impl(argc, argv, 0); return os_execute_impl(argc, argv, JANET_EXECUTE_EXECUTE);
} }
JANET_CORE_FN(os_spawn, JANET_CORE_FN(os_spawn,
@ -1357,7 +1381,15 @@ JANET_CORE_FN(os_spawn,
"The returned value `proc` has the fields :in, :out, :err, :return-code, and " "The returned value `proc` has the fields :in, :out, :err, :return-code, and "
"the additional field :pid on unix-like platforms. Use `(os/proc-wait proc)` to rejoin the " "the additional field :pid on unix-like platforms. Use `(os/proc-wait proc)` to rejoin the "
"subprocess or `(os/proc-kill proc)`.") { "subprocess or `(os/proc-kill proc)`.") {
return os_execute_impl(argc, argv, 1); return os_execute_impl(argc, argv, JANET_EXECUTE_SPAWN);
}
JANET_CORE_FN(os_posix_exec,
"(os/posix-exec args &opt flags env)",
"Use the execvpe or execve system calls to replace the current process with an interface similar to os/execute. "
"Hoever, instead of creating a subprocess, the current process is replaced. Is not supported on windows, and "
"does not allow redirection of stdio.") {
return os_execute_impl(argc, argv, JANET_EXECUTE_EXEC);
} }
#ifdef JANET_EV #ifdef JANET_EV
@ -2651,6 +2683,7 @@ void janet_lib_os(JanetTable *env) {
JANET_CORE_REG("os/spawn", os_spawn), JANET_CORE_REG("os/spawn", os_spawn),
JANET_CORE_REG("os/shell", os_shell), JANET_CORE_REG("os/shell", os_shell),
JANET_CORE_REG("os/posix-fork", os_posix_fork), JANET_CORE_REG("os/posix-fork", os_posix_fork),
JANET_CORE_REG("os/posix-exec", os_posix_exec),
/* no need to sandbox process management if you can't create processes /* no need to sandbox process management if you can't create processes
* (allows for limited functionality if use exposes C-functions to create specific processes) */ * (allows for limited functionality if use exposes C-functions to create specific processes) */
JANET_CORE_REG("os/proc-wait", os_proc_wait), JANET_CORE_REG("os/proc-wait", os_proc_wait),