fx.diagnostics: process: implement environment management

This commit is contained in:
2026-07-12 22:14:57 +01:00
parent 5c837abc6c
commit e9a1bfbde2
3 changed files with 230 additions and 26 deletions
@@ -1,6 +1,7 @@
#ifndef FX_DIAGNOSTICS_PROCESS_H_
#define FX_DIAGNOSTICS_PROCESS_H_
#include <fx/collections/array.h>
#include <fx/collections/hashtable.h>
#include <fx/macros.h>
#include <fx/stream.h>
@@ -17,8 +18,7 @@ FX_TYPE_CLASS_DECLARATION_END(fx_process)
typedef struct fx_process_start_info {
bool proc_redirect_stdin, proc_redirect_stdout, proc_redirect_stderr;
const char *proc_file_name;
const char **proc_args;
size_t proc_args_count;
const fx_array *proc_args;
const fx_hashtable *proc_environment;
} fx_process_start_info;
+222 -20
View File
@@ -1,13 +1,22 @@
#define _POSIX_C_SOURCE 200809L
#include <fx/collections/array.h>
#include <fx/diagnostics/process.h>
#include <fx/global.h>
#include <fx/io/path.h>
#include <fx/io/pipe.h>
#include <fx/io/stream.h>
#include <fx/iterator.h>
#include <fx/macros.h>
#include <fx/string.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
static fx_process *self = NULL;
extern const char **environ;
FX_API fx_type_id fx_process_iterator_get_type();
FX_DECLARE_TYPE(fx_process_iterator);
@@ -21,6 +30,7 @@ struct fx_process_p {
bool proc_redirect_stdin, proc_redirect_stdout, proc_redirect_stderr;
fx_stream *proc_stdin, *proc_stdout, *proc_stderr;
pid_t proc_id;
fx_hashtable *proc_environment;
};
struct fx_process_iterator_p {
@@ -28,12 +38,109 @@ struct fx_process_iterator_p {
/*** PRIVATE FUNCTIONS ********************************************************/
static bool exec_name_is_path(const char *s)
{
fx_wchar c;
while (*s) {
c = fx_wchar_utf8_codepoint_decode(s);
if (c == FX_WCHAR_INVALID) {
break;
}
if (c == '/') {
return true;
}
s += fx_wchar_utf8_codepoint_stride(s);
}
return false;
}
const fx_string *get_path(void)
{
const char *path_env = NULL;
fx_process *self = fx_process_get_self();
if (!self) {
goto fallback;
}
const fx_hashtable *env = fx_process_get_environment(self);
if (!env) {
goto fallback;
}
const fx_value *path_v = fx_hashtable_get(env, &FX_CSTR("PATH"));
if (!path_v) {
goto fallback;
}
fx_string *result = NULL;
fx_value_get_object(path_v, &result);
return result;
fallback:
path_env = getenv("PATH");
if (!path_env) {
return NULL;
}
return fx_string_create_from_cstr(path_env);
}
static fx_status find_executable(fx_string *exec_path)
{
const char *exec_path_cstr = fx_string_get_cstr(exec_path);
const fx_string *path_env = get_path();
if (!path_env) {
return FX_ERR_NO_ENTRY;
}
const char *delim[] = {":"};
size_t nr_delim = sizeof delim / sizeof delim[0];
fx_path *path = NULL;
fx_iterator *it = fx_string_tokenise(
path_env,
delim,
nr_delim,
FX_STRING_TOK_F_NORMAL);
fx_status status = FX_ERR_NO_ENTRY;
fx_foreach(tok, it)
{
path = fx_path_join_list(2, tok, &FX_VALUE_OBJECT(exec_path));
if (fx_path_is_file(path)) {
fx_string_clear(exec_path);
fx_string_append_cstr(
exec_path,
fx_path_get_cstr(path));
status = FX_SUCCESS;
break;
}
}
fx_iterator_unref(it);
fx_path_unref(path);
return status;
}
static fx_status process_start(struct fx_process_p *proc)
{
fx_iostream *in_r = NULL, *in_w = NULL;
fx_iostream *out_r = NULL, *out_w = NULL;
fx_iostream *err_r = NULL, *err_w = NULL;
fx_status status = FX_SUCCESS;
bool name_is_path
= exec_name_is_path(fx_string_get_cstr(proc->proc_exec_path));
if (!name_is_path) {
status = find_executable(proc->proc_exec_path);
}
if (!FX_OK(status)) {
return status;
}
if (proc->proc_redirect_stdin) {
status = fx_pipe_create(&in_r, &in_w);
@@ -76,7 +183,6 @@ static fx_status process_start(struct fx_process_p *proc)
if (proc->proc_redirect_stdin) {
fx_iostream_unref(in_w);
fd = fx_iostream_steal_os_handle(in_r);
fprintf(stderr, "dup2(%d, %d)\n", fd, 0);
int err = dup2(fd, 0);
close(fd);
}
@@ -96,12 +202,23 @@ static fx_status process_start(struct fx_process_p *proc)
}
const char **argv = NULL;
const char **envp = NULL;
const char *default_argv[] = {
fx_string_get_cstr(proc->proc_exec_path),
NULL,
};
size_t argc = 0;
size_t envc = 0;
if (proc->proc_args) {
argc = fx_array_get_size(proc->proc_args);
}
if (proc->proc_environment) {
envc = fx_hashtable_get_count(proc->proc_environment);
}
if (argc) {
argv = calloc(argc + 1, sizeof(char *));
@@ -110,9 +227,38 @@ static fx_status process_start(struct fx_process_p *proc)
= fx_array_get_ref(proc->proc_args, i);
fx_value_get_cstr(arg_value, &argv[i]);
}
} else {
argv = default_argv;
}
execv(fx_string_get_cstr(proc->proc_exec_path), (char *const *)argv);
if (envc) {
envp = calloc(envc + 1, sizeof(char *));
size_t i = 0;
fx_stringstream *tmp = fx_stringstream_create();
const fx_iterator *it
= fx_iterator_begin(proc->proc_environment);
fx_foreach(v, it)
{
fx_hashtable_item *item = NULL;
fx_value_get_object(v, &item);
const fx_value *name_v
= fx_hashtable_item_get_key(item);
const fx_value *value_v
= fx_hashtable_item_get_value(item);
fx_value_to_string(name_v, tmp, NULL);
fx_stream_write_char(tmp, '=');
fx_value_to_string(value_v, tmp, NULL);
envp[i++] = fx_stringstream_steal(tmp);
}
fx_iterator_unref(it);
fx_string_unref(tmp);
}
execve(fx_string_get_cstr(proc->proc_exec_path),
(char *const *)argv,
(char *const *)envp);
exit(127);
cleanup:
@@ -159,6 +305,12 @@ static fx_status process_kill(struct fx_process_p *proc)
return FX_SUCCESS;
}
static const fx_hashtable *process_get_environment(
const struct fx_process_p *proc)
{
return proc->proc_environment;
}
static fx_stream *process_get_stdin(struct fx_process_p *proc)
{
return proc->proc_stdin;
@@ -210,25 +362,10 @@ fx_process *fx_process_create(const fx_process_start_info *info)
return NULL;
}
if (info->proc_args_count > 0) {
proc->proc_args = fx_array_create();
if (!proc->proc_args) {
fx_process_unref(out);
return NULL;
}
}
for (size_t i = 0; i < info->proc_args_count; i++) {
fx_string *arg = fx_string_create_from_cstr(info->proc_args[i]);
if (!arg) {
fx_process_unref(out);
return NULL;
}
fx_array_push_back(proc->proc_args, FX_VALUE_OBJECT(arg));
fx_string_unref(arg);
}
proc->proc_args = fx_array_ref((fx_array *)info->proc_args);
proc->proc_environment
= fx_hashtable_ref((fx_hashtable *)info->proc_environment);
proc->proc_redirect_stdin = info->proc_redirect_stdin;
proc->proc_redirect_stdout = info->proc_redirect_stdout;
proc->proc_redirect_stderr = info->proc_redirect_stderr;
@@ -236,6 +373,56 @@ fx_process *fx_process_create(const fx_process_start_info *info)
return out;
}
fx_process *fx_process_get_self(void)
{
if (self) {
return self;
}
self = fx_object_create(FX_DIAGNOSTICS_TYPE_PROCESS);
if (!self) {
return NULL;
}
struct fx_process_p *proc
= fx_object_get_private(self, FX_DIAGNOSTICS_TYPE_PROCESS);
proc->proc_id = getpid();
fx_hashtable *env = fx_hashtable_create();
for (size_t i = 0; environ[i]; i++) {
char *envstr = fx_strdup(environ[i]);
const char *name = envstr;
char *sep = strchr(name, '=');
const char *value = NULL;
if (sep) {
*sep = '\0';
value = sep + 1;
}
fx_string *name_str = fx_string_create_from_cstr(name);
fx_string *value_str = fx_string_create();
if (value) {
fx_string_append_cstr(value_str, value);
}
fx_hashtable_put(
env,
&FX_VALUE_OBJECT(name_str),
&FX_VALUE_OBJECT(value_str));
fx_string_unref(name_str);
fx_string_unref(value_str);
free(envstr);
}
proc->proc_environment = env;
fx_register_global(self);
return self;
}
fx_status fx_process_start(fx_process *proc)
{
FX_CLASS_DISPATCH_STATIC_0(
@@ -261,6 +448,14 @@ fx_status fx_process_kill(fx_process *proc)
proc);
}
const fx_hashtable *fx_process_get_environment(const fx_process *proc)
{
FX_CLASS_DISPATCH_STATIC_0(
FX_DIAGNOSTICS_TYPE_PROCESS,
process_get_environment,
proc);
}
fx_stream *fx_process_get_stdin(fx_process *proc)
{
FX_CLASS_DISPATCH_STATIC_0(
@@ -317,6 +512,13 @@ static void process_init(fx_object *obj, void *priv)
static void process_fini(fx_object *obj, void *priv)
{
struct fx_process_p *proc = priv;
fx_array_unref(proc->proc_args);
fx_iostream_unref(proc->proc_stdin);
fx_iostream_unref(proc->proc_stdout);
fx_iostream_unref(proc->proc_stderr);
fx_string_unref(proc->proc_exec_path);
fx_hashtable_unref(proc->proc_environment);
}
/*** ITERATOR DEFINITION ******************************************************/
+6 -4
View File
@@ -9,17 +9,19 @@ int main(int argc, const char **argv)
const char *exec = argv[1];
const char *msg = argv[2];
const char *args[] = {
"hello",
"world",
const fx_value arg_values[] = {
FX_CSTR("hello"),
FX_CSTR("world"),
};
fx_array *args = fx_array_create_with_values(
arg_values,
sizeof arg_values / sizeof arg_values[0]);
fx_process *self = fx_process_get_self();
const fx_hashtable *env = fx_process_get_environment(self);
fx_process_start_info info = {
.proc_args = args,
.proc_args_count = sizeof args / sizeof args[0],
.proc_redirect_stdout = true,
.proc_redirect_stdin = true,
.proc_file_name = exec,