From: Felix Fietkau Date: Wed, 8 Oct 2025 22:06:46 +0200 Subject: [PATCH] uloop: add optional setup callback to process() Add optional setup callback as 5th argument to uloop.process() that is invoked in the child process after fork() but before exec(). Signed-off-by: Felix Fietkau --- --- a/lib/uloop.c +++ b/lib/uloop.c @@ -961,8 +961,9 @@ uc_uloop_process_cb(struct uloop_process * * This function creates a process instance for executing external programs. * It takes the executable path string, an optional string array as the argument - * vector, an optional dictionary describing environment variables, and a - * callback function to be invoked when the invoked process ends. + * vector, an optional dictionary describing environment variables, a + * callback function to be invoked when the invoked process ends, and an optional + * setup callback to be invoked in the child process after fork(). * * @function module:uloop#process * @@ -979,6 +980,11 @@ uc_uloop_process_cb(struct uloop_process * @param {Function} callback * The callback function to be invoked when the invoked process ends. * + * @param {Function} [setup] + * Optional. A callback function to be invoked in the child process after fork() + * but before exec(). This can be used to set up file descriptors, change working + * directory, or perform other initialization. + * * @returns {?module:uloop.process} * Returns a process instance for executing external programs. * Returns `null` on error, e.g. due to `exec()` failure or invalid arguments. @@ -988,6 +994,16 @@ uc_uloop_process_cb(struct uloop_process * const myProcess = uloop.process("/bin/ls", ["-l", "/tmp"], null, (code) => { * printf(`Process exited with code ${code}\n`); * }); + * + * // With setup callback to redirect stderr + * const myProcess = uloop.process("/bin/ls", ["-l", "/tmp"], null, (code) => { + * printf(`Process exited with code ${code}\n`); + * }, () => { + * const fs = require('fs'); + * const errlog = fs.open('/tmp/error.log', 'w'); + * fs.dup2(errlog.fileno(), 2); + * errlog.close(); + * }); */ static uc_value_t * uc_uloop_process(uc_vm_t *vm, size_t nargs) @@ -996,6 +1012,7 @@ uc_uloop_process(uc_vm_t *vm, size_t nar uc_value_t *arguments = uc_fn_arg(1); uc_value_t *env_arg = uc_fn_arg(2); uc_value_t *callback = uc_fn_arg(3); + uc_value_t *setup_cb = uc_fn_arg(4); uc_uloop_process_t *process; uc_stringbuf_t *buf; char **argp, **envp; @@ -1005,7 +1022,8 @@ uc_uloop_process(uc_vm_t *vm, size_t nar if (ucv_type(executable) != UC_STRING || (arguments && ucv_type(arguments) != UC_ARRAY) || (env_arg && ucv_type(env_arg) != UC_OBJECT) || - !ucv_is_callable(callback)) { + !ucv_is_callable(callback) || + (setup_cb && !ucv_is_callable(setup_cb))) { err_return(EINVAL); } @@ -1015,6 +1033,13 @@ uc_uloop_process(uc_vm_t *vm, size_t nar err_return(errno); if (pid == 0) { + if (setup_cb) { + uc_vm_stack_push(vm, ucv_get(setup_cb)); + + if (uc_uloop_vm_call(vm, false, 0)) + ucv_put(uc_vm_stack_pop(vm)); + } + argp = calloc(ucv_array_length(arguments) + 2, sizeof(char *)); envp = environ;