summaryrefslogtreecommitdiffstats
path: root/package/utils/ucode/patches/111-uloop-add-optional-setup-callback-to-process.patch
blob: e8f597ade7cd97c4c9ac49694fd256251de46eb3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
From: Felix Fietkau <nbd@nbd.name>
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 <nbd@nbd.name>
---

--- a/lib/uloop.c
+++ b/lib/uloop.c
@@ -968,8 +968,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
  *
@@ -986,6 +987,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.
@@ -995,6 +1001,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)
@@ -1003,6 +1019,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;
@@ -1012,7 +1029,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);
 	}
 
@@ -1022,6 +1040,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;