libwebsockets
Lightweight C library for HTML5 websockets
|
The lws_spawn
API provides a robust, platform-agnostic way to create and manage child processes directly from your C application, fully integrated with the libwebsockets event loop.
The lws_spawn
API is designed to securely run external executables as child processes. Its key features include:
stdin
, stdout
, and stderr
are automatically redirected to pipes. These pipes are represented as standard struct lws
connection instances (wsi
), allowing you to interact with the child process using familiar lws protocol callbacks.chroot()
jail and the working directory for the child process.The primary entrypoint for this API is lws_spawn_piped()
. It takes a single argument: a pointer to a struct lws_spawn_piped_info
which you populate to describe the child process you want to create.
Key members of struct lws_spawn_piped_info
:
exec_array
: A NULL
-terminated array of strings for the executable path and its arguments (equivalent to argv
).env_array
: A NULL
-terminated array of strings for the child's environment variables (e.g., {"VAR1=VALUE1", "VAR2=VALUE2", NULL}
).vh
: The lws_vhost
the new stdio wsi
should be associated with.protocol_name
: The name of the lws protocol that will handle events for the stdio wsi
. This is mandatory for proper cleanup.reap_cb
: A mandatory callback function of type lsp_cb_t
that lws will call after the child process has terminated and been reaped.opaque
: A user pointer that will be passed to your reap_cb
and will also be available on the stdio wsi
via lws_get_opaque_user_data()
.timeout_us
: Optional timeout in microseconds. If the process runs longer than this, it will be sent a SIGTERM
.Proper cleanup is essential. When the child process exits, its stdio pipes are closed by the operating system. This generates a LWS_CALLBACK_RAW_FILE_CLOSE
event on each of the three stdio wsi
.
Your protocol handler must implement a case for this reason and call lws_spawn_stdwsi_closed()
:
When lws has been notified that all three stdio wsi
have closed, it will proceed to reap the child process and invoke your reap_cb
.
On Linux, lws_spawn
can automatically create a transient cgroup v2 for each spawned process, providing resource isolation. The cgroup is automatically removed when the process is reaped.
By default, creating new cgroups in /sys/fs/cgroup/
requires root
privileges. A non-root user will get a "Permission Denied" error.
The recommended solution is to have an administrator (or a CI setup script) perform a one-time setup to delegate control of a subdirectory to the user running the lws application:
For applications that start as root
and then drop privileges, lws provides a helper function to perform this setup programmatically: int lws_spawn_cgroup_admin_init(const char *toplevel_name, const char *owner_or_NULL, const char *group_or_NULL);
. Call this function once at startup while your process still has root privileges. The cgroup directory will take on the ownership and group given in the args, NULL means to skip the change. If toplevel_name
is NULL, it defaults to the builtin one "lws" as the toplevel token. It returns success (0) if the toplevel entry already existed as well as if successfully created.
Typically it will called by a daemon during init while it is still root, and configured to prepare the cgroup dir ownership for the less-privileged user / group it subsequently runs under.
To enable cgroup containment for a spawned process, set the following members in your struct lws_spawn_piped_info
:
cgroup_name_suffix
: A string that will be used to name the cgroup directory. For example, a suffix of "lws/my-task"
will create a cgroup at /sys/fs/cgroup/lws/my-task
. This must be unique for concurrent spawns.p_cgroup_ret
: An optional pointer to an int
. If provided, lws will write 0
to this integer on successful cgroup creation, and 1
on failure.If cgroup creation fails (e.g., due to permissions), lws_spawn_piped()
will not fail. It will log a warning and proceed to spawn the process without cgroup containment. Use p_cgroup_ret
to confirm the outcome.
For a complete, working example that demonstrates these concepts, including cgroup setup and verification, please refer to the API test located at:
minimal-examples-lowlevel/api-tests/api-test-lws_spawn/