|
|
@@ -0,0 +1,85 @@
|
|
|
+From: Felix Fietkau <[email protected]>
|
|
|
+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 <[email protected]>
|
|
|
+---
|
|
|
+
|
|
|
+--- 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;
|
|
|
+
|