| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #ifndef SPAWN_SERVER_H |
| 4 | #define SPAWN_SERVER_H |
| 5 | |
| 6 | #include "../common.h" |
| 7 | |
| 8 | #define SPAWN_SERVER_TRANSFER_FDS 4 |
| 9 | |
| 10 | typedef enum __attribute__((packed)) { |
| 11 | SPAWN_INSTANCE_TYPE_EXEC = 0, |
| 12 | SPAWN_INSTANCE_TYPE_CALLBACK = 1 |
| 13 | } SPAWN_INSTANCE_TYPE; |
| 14 | |
| 15 | typedef enum __attribute__((packed)) { |
| 16 | SPAWN_SERVER_OPTION_EXEC = (1 << 0), |
| 17 | SPAWN_SERVER_OPTION_CALLBACK = (1 << 1), |
| 18 | } SPAWN_SERVER_OPTIONS; |
| 19 | |
| 20 | // this is only used publicly for SPAWN_INSTANCE_TYPE_CALLBACK |
| 21 | // which is not available in Windows |
| 22 | typedef struct spawn_request { |
| 23 | const char *cmdline; // the cmd line of the command we should run |
| 24 | size_t request_id; // the incremental request id |
| 25 | pid_t pid; // the pid of the child |
| 26 | int sock; // the socket for this request |
| 27 | int fds[SPAWN_SERVER_TRANSFER_FDS]; // 0 = stdin, 1 = stdout, 2 = stderr, 3 = custom |
| 28 | const char **envp; // the environment of the parent process |
| 29 | const char **argv; // the command line and its parameters |
| 30 | const void *data; // the data structure for the callback |
| 31 | size_t data_size; // the data structure size |
| 32 | SPAWN_INSTANCE_TYPE type; // the type of the request |
| 33 | |
| 34 | struct spawn_request *prev, *next; // linking of active requests at the spawn server |
| 35 | } SPAWN_REQUEST; |
| 36 | |
| 37 | typedef int (*spawn_request_callback_t)(SPAWN_REQUEST *request); |
| 38 | |
| 39 | typedef struct spawn_instance SPAWN_INSTANCE; |
| 40 | typedef struct spawn_server SPAWN_SERVER; |
| 41 | |
| 42 | SPAWN_SERVER* spawn_server_create(SPAWN_SERVER_OPTIONS options, const char *name, spawn_request_callback_t child_callback, int argc, const char **argv); |
| 43 | void spawn_server_destroy(SPAWN_SERVER *server); |
| 44 | pid_t spawn_server_pid(SPAWN_SERVER *server); |
| 45 | |
| 46 | SPAWN_INSTANCE* spawn_server_exec(SPAWN_SERVER *server, int stderr_fd, int custom_fd, const char **argv, const void *data, size_t data_size, SPAWN_INSTANCE_TYPE type); |
| 47 | int spawn_server_exec_kill(SPAWN_SERVER *server, SPAWN_INSTANCE *si, int timeout_ms); |
| 48 | int spawn_server_exec_wait(SPAWN_SERVER *server, SPAWN_INSTANCE *si); |
| 49 | |
| 50 | typedef enum __attribute__((packed)) { |
| 51 | SPAWN_TIMEDWAIT_EXITED = 0, // the child exited; *status holds its status and si has been freed |
| 52 | SPAWN_TIMEDWAIT_RUNNING = 1, // the timeout expired; the child is still running and si remains valid |
| 53 | SPAWN_TIMEDWAIT_ERROR = 2, // the wait could not be completed (broken status channel / unusable |
| 54 | // handle); the child's state is unknown, si remains valid, and the |
| 55 | // caller must reclaim it (e.g. via spawn_server_exec_kill()) |
| 56 | } SPAWN_TIMEDWAIT_RESULT; |
| 57 | |
| 58 | // Wait for the child for up to timeout_ms. A non-positive timeout_ms performs a single, minimal |
| 59 | // bounded poll (the nofork backend uses a ~1ms slice because its wait primitive treats 0 as |
| 60 | // "wait forever"; the others poll once); the wait is always bounded, never infinite. |
| 61 | // On SPAWN_TIMEDWAIT_EXITED the instance has been freed, exactly like spawn_server_exec_wait(). |
| 62 | // On SPAWN_TIMEDWAIT_RUNNING or SPAWN_TIMEDWAIT_ERROR the caller keeps ownership and must eventually |
| 63 | // call spawn_server_exec_timedwait(), spawn_server_exec_wait() or spawn_server_exec_kill(). |
| 64 | // ERROR is distinct from RUNNING on purpose: the wait could not progress (it is not merely "not yet"), |
| 65 | // so callers must NOT loop on it (that would spin forever when timeout_ms == 0) - they must reclaim |
| 66 | // the instance, typically by killing it. |
| 67 | // status is optional (may be NULL): on EXITED the wait/cleanup still happens, the status is just not stored. |
| 68 | SPAWN_TIMEDWAIT_RESULT spawn_server_exec_timedwait(SPAWN_SERVER *server, SPAWN_INSTANCE *si, int timeout_ms, int *status); |
| 69 | |
| 70 | int spawn_server_instance_read_fd(SPAWN_INSTANCE *si); |
| 71 | int spawn_server_instance_write_fd(SPAWN_INSTANCE *si); |
| 72 | pid_t spawn_server_instance_pid(SPAWN_INSTANCE *si); |
| 73 | void spawn_server_instance_read_fd_unset(SPAWN_INSTANCE *si); |
| 74 | void spawn_server_instance_write_fd_unset(SPAWN_INSTANCE *si); |
| 75 | |
| 76 | #endif //SPAWN_SERVER_H |