From ba0d023a6164e53493df0012d9418e3ac7d2c653 Mon Sep 17 00:00:00 2001 From: Aymeric Wibo Date: Mon, 6 Jan 2025 17:18:21 +0100 Subject: [PATCH 1/8] linker: Cleanup cookie --- src/class/linker.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class/linker.c b/src/class/linker.c index 02736e61..69e27be6 100644 --- a/src/class/linker.c +++ b/src/class/linker.c @@ -142,6 +142,7 @@ link:; if (pretty == NULL) { LOG_INFO(CLEAR "%s...", bss->present); } + else { LOG_INFO("%s" CLEAR ": %s...", pretty, bss->present); } @@ -205,7 +206,7 @@ static int prep_link(state_t* state, flamingo_arg_list_t* args, flamingo_val_t** total_hash ^= str_hash(src->str.str, src->str.size); } - char* cookie = NULL; + char* STR_CLEANUP cookie = NULL; asprintf(&cookie, "%s/bob/linker.%s.cookie.%" PRIx64 ".%s", out_path, infinitive, total_hash, archive ? "a" : "l"); assert(cookie != NULL); *rv = flamingo_val_make_cstr(cookie); From e2f06a7b328e766d339baa26ccde6916fe3d4191 Mon Sep 17 00:00:00 2001 From: Aymeric Wibo Date: Wed, 25 Dec 2024 16:39:32 +0100 Subject: [PATCH 2/8] cmd: `cmd_set_redirect` --- src/cmd.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/cmd.c b/src/cmd.c index fb5f3dbe..afee7c5b 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -44,6 +44,8 @@ void cmd_create(cmd_t* cmd, ...) { va_end(va); + cmd_set_redirect(cmd, true); + cmd->in = -1; cmd->out = -1; } @@ -83,6 +85,17 @@ void cmd_add_argv(cmd_t* cmd, int argc, char* argv[]) { } } +void cmd_set_redirect(cmd_t* cmd, bool redirect) { + // We don't do any of this output pipe stuff if we're debugging the build, because we want to see the outputs of commands in real-time before they terminate. + + if (debugging) { + cmd->redirect = false; + return; + } + + cmd->redirect = redirect; +} + static bool is_executable(char const* path) { struct stat sb; @@ -154,10 +167,9 @@ pid_t cmd_exec_async(cmd_t* cmd) { return -1; } - // Create pipes. - // We don't do any of this pipe stuff if we're debugging the build, because we want to see the outputs of commands in real-time before they terminate. + // Create stdout+stderr pipe. - if (!debugging) { + if (cmd->redirect) { int fd[2]; if (pipe(fd) < 0) { @@ -178,7 +190,7 @@ pid_t cmd_exec_async(cmd_t* cmd) { posix_spawn_file_actions_t actions; posix_spawn_file_actions_init(&actions); - if (!debugging) { + if (cmd->redirect) { posix_spawn_file_actions_addclose(&actions, cmd->out); posix_spawn_file_actions_adddup2(&actions, cmd->in, STDOUT_FILENO); @@ -198,7 +210,7 @@ pid_t cmd_exec_async(cmd_t* cmd) { posix_spawn_file_actions_destroy(&actions); - if (!debugging) { + if (cmd->redirect) { close(cmd->in); cmd->in = -1; } @@ -244,7 +256,7 @@ char* cmd_read_out(cmd_t* cmd) { char* out = strdup(""); assert(out != NULL); - if (debugging) { + if (!cmd->redirect) { return out; } From 6ec32325e68b5fa962ebeea88156b7613b4a2b62 Mon Sep 17 00:00:00 2001 From: Aymeric Wibo Date: Wed, 25 Dec 2024 16:39:51 +0100 Subject: [PATCH 3/8] cmd: `cmd_prepare_stdin` --- src/cmd.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++------ src/cmd.h | 16 +++++++++++++- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/src/cmd.c b/src/cmd.c index afee7c5b..b54121e2 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -48,6 +48,10 @@ void cmd_create(cmd_t* cmd, ...) { cmd->in = -1; cmd->out = -1; + + cmd->pending_stdin = NULL; + cmd->stdin_in = -1; + cmd->stdin_out = -1; } void cmd_add(cmd_t* cmd, char const* arg) { @@ -96,6 +100,11 @@ void cmd_set_redirect(cmd_t* cmd, bool redirect) { cmd->redirect = redirect; } +void cmd_prepare_stdin(cmd_t* cmd, char* data) { + cmd->pending_stdin = strdup(data); + assert(cmd->pending_stdin != NULL); +} + static bool is_executable(char const* path) { struct stat sb; @@ -181,6 +190,20 @@ pid_t cmd_exec_async(cmd_t* cmd) { cmd->out = fd[0]; } + // Create stdin pipe. + + if (cmd->pending_stdin != NULL) { + int fd[2]; + + if (pipe(fd) < 0) { + LOG_FATAL("pipe: %s", strerror(errno)); + return -1; + } + + cmd->stdin_in = fd[1]; + cmd->stdin_out = fd[0]; + } + // Spawn process. // We can't use 'fork()' here, because we could be called from a multi-threaded context. // https://www.qnx.com/developers/docs/8.0/com.qnx.doc.neutrino.getting_started/topic/s1_procs_Multithreaded_fork.html @@ -197,6 +220,11 @@ pid_t cmd_exec_async(cmd_t* cmd) { posix_spawn_file_actions_adddup2(&actions, cmd->in, STDERR_FILENO); } + if (cmd->pending_stdin != NULL) { + posix_spawn_file_actions_adddup2(&actions, cmd->stdin_out, STDIN_FILENO); + posix_spawn_file_actions_addclose(&actions, cmd->stdin_in); + } + extern char** environ; pid_t pid; @@ -204,8 +232,13 @@ pid_t cmd_exec_async(cmd_t* cmd) { LOG_ERROR("posix_spawnp: %s", strerror(errno)); pid = -1; - close(cmd->out); - cmd->out = -1; + if (cmd->redirect) { + close(cmd->out); + cmd->out = -1; + } + + close(cmd->stdin_in); + cmd->stdin_in = -1; } posix_spawn_file_actions_destroy(&actions); @@ -215,6 +248,17 @@ pid_t cmd_exec_async(cmd_t* cmd) { cmd->in = -1; } + // stdin stuff. + + close(cmd->stdin_out); + cmd->stdin_out = -1; + + if (cmd->pending_stdin != NULL) { + write(cmd->stdin_in, cmd->pending_stdin, strlen(cmd->pending_stdin) + 1); + close(cmd->stdin_in); + cmd->stdin_in = -1; + } + return pid; } @@ -370,13 +414,12 @@ void cmd_free(cmd_t* cmd) { free(arg); } - if (cmd->args != NULL) { - free(cmd->args); - } - + free(cmd->args); cmd->len = 0; cmd->args = NULL; + free(cmd->pending_stdin); + if (cmd->in >= 0) { close(cmd->in); } @@ -384,4 +427,12 @@ void cmd_free(cmd_t* cmd) { if (cmd->out >= 0) { close(cmd->out); } + + if (cmd->stdin_in >= 0) { + close(cmd->stdin_in); + } + + if (cmd->stdin_out >= 0) { + close(cmd->stdin_out); + } } diff --git a/src/cmd.h b/src/cmd.h index a78bb70f..fc8b2cf2 100644 --- a/src/cmd.h +++ b/src/cmd.h @@ -12,22 +12,36 @@ typedef struct { char** args; int sig; int rv; + bool redirect; - // Pipe. + // Pipe (stdout & stderr). int in; int out; + + // Pipe (stdin). + + char* pending_stdin; + + int stdin_in; + int stdin_out; } cmd_t; void cmd_create(cmd_t* cmd, ...); void cmd_add(cmd_t* cmd, char const* arg); __attribute__((__format__(__printf__, 2, 3))) void cmd_addf(cmd_t* cmd, char const* fmt, ...); void cmd_add_argv(cmd_t* cmd, int argc, char* argv[]); + +void cmd_set_redirect(cmd_t* cmd, bool redirect); +void cmd_prepare_stdin(cmd_t* cmd, char* data); + int cmd_exec_inplace(cmd_t* cmd); pid_t cmd_exec_async(cmd_t* cmd); int cmd_exec(cmd_t* cmd); + char* cmd_read_out(cmd_t* cmd); void cmd_log(cmd_t* cmd, char const* cookie, char const* prefix, char const* infinitive, char const* past, bool log_success); + void cmd_print(cmd_t* cmd); void cmd_free(cmd_t* cmd); From 5c35c5be218dad7cefc863831e357b376b80e2cb Mon Sep 17 00:00:00 2001 From: Aymeric Wibo Date: Mon, 6 Jan 2025 17:23:22 +0100 Subject: [PATCH 4/8] logging: Allow usage of `log_already_done` on no cookie in particular --- src/logging.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/logging.c b/src/logging.c index 20797a93..f4a0d26a 100644 --- a/src/logging.c +++ b/src/logging.c @@ -132,25 +132,28 @@ void progress_update(progress_t* self, size_t numerator, size_t _denominator, ch } void log_already_done(char const* cookie, char const* prefix, char const* past) { - char* STR_CLEANUP path; - asprintf(&path, "%s.log", cookie); - assert(path != NULL); - char* STR_CLEANUP out = NULL; - FILE* const f = fopen(path, "r"); - if (f != NULL) { - fseek(f, 0, SEEK_END); - size_t const size = ftell(f); + if (cookie != NULL) { + char* STR_CLEANUP path; + asprintf(&path, "%s.log", cookie); + assert(path != NULL); + + FILE* const f = fopen(path, "r"); + + if (f != NULL) { + fseek(f, 0, SEEK_END); + size_t const size = ftell(f); - out = malloc(size + 1); - assert(out != NULL); + out = malloc(size + 1); + assert(out != NULL); - rewind(f); - fread(out, 1, size, f); - out[size] = '\0'; + rewind(f); + fread(out, 1, size, f); + out[size] = '\0'; - fclose(f); + fclose(f); + } } char* const suffix = out ? ":" : "."; From d3a9a49e246dc5891cae36e83cc5bc16562ecea8 Mon Sep 17 00:00:00 2001 From: Aymeric Wibo Date: Wed, 25 Dec 2024 15:52:51 +0100 Subject: [PATCH 5/8] main: Error if all arguments are not consumed --- src/main.c | 8 ++++---- src/str.h | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main.c b/src/main.c index 5720be2d..ca56e24e 100644 --- a/src/main.c +++ b/src/main.c @@ -299,7 +299,7 @@ int main(int argc, char* argv[]) { instr = *argv++; - if (strcmp(instr, "build") == 0) { + if (argc == 0 && strcmp(instr, "build") == 0) { if (bsys_build(bsys) == 0) { rv = EXIT_SUCCESS; } @@ -317,13 +317,13 @@ int main(int argc, char* argv[]) { } } - else if (strcmp(instr, "install") == 0) { + else if (argc == 0 && strcmp(instr, "install") == 0) { if (bsys_install(bsys) == 0) { rv = EXIT_SUCCESS; } } - else if (strcmp(instr, "clean") == 0) { + else if (argc == 0 && strcmp(instr, "clean") == 0) { if (bsys_clean(bsys) == 0) { rv = EXIT_SUCCESS; } @@ -331,7 +331,7 @@ int main(int argc, char* argv[]) { // This is intentionally undocumented, as it's really only used for communication between Bob parent processes and their Bob children processes. - else if (strcmp(instr, "dep-tree") == 0) { + else if (argc == 1 && strcmp(instr, "dep-tree") == 0) { LOG_WARN("This command is internal and isn't meant for direct use. A correct consumer of this command should be able to discard this message by reading the contents within the dependency tree tags."); if (bsys_dep_tree(bsys, argc, argv) == 0) { diff --git a/src/str.h b/src/str.h index f119b29b..ec610f91 100644 --- a/src/str.h +++ b/src/str.h @@ -5,10 +5,15 @@ #include #include +#include -// TODO Rename to strnhash and have strhash equivalent for C-strings? +// TODO Rename to strnhash. uint64_t str_hash(char const* str, size_t len); void str_free(char* const* str_ref); +static inline uint64_t strhash(char const* str) { + return str_hash(str, strlen(str)); +} + #define STR_CLEANUP __attribute__((cleanup(str_free))) From f897fb2165437afa0879c37eb6b8a6f2765a589d Mon Sep 17 00:00:00 2001 From: Aymeric Wibo Date: Wed, 25 Dec 2024 15:58:41 +0100 Subject: [PATCH 6/8] main: Do error if all arguments are not consumed better --- src/main.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index ca56e24e..c7401519 100644 --- a/src/main.c +++ b/src/main.c @@ -299,7 +299,12 @@ int main(int argc, char* argv[]) { instr = *argv++; - if (argc == 0 && strcmp(instr, "build") == 0) { + if (strcmp(instr, "build") == 0) { + if (argc != 0) { + LOG_FATAL("Extraneous arguments to '%s'.", instr); + usage(); + } + if (bsys_build(bsys) == 0) { rv = EXIT_SUCCESS; } @@ -317,13 +322,23 @@ int main(int argc, char* argv[]) { } } - else if (argc == 0 && strcmp(instr, "install") == 0) { + else if (strcmp(instr, "install") == 0) { + if (argc != 0) { + LOG_FATAL("Extraneous arguments to '%s'.", instr); + usage(); + } + if (bsys_install(bsys) == 0) { rv = EXIT_SUCCESS; } } - else if (argc == 0 && strcmp(instr, "clean") == 0) { + else if (strcmp(instr, "clean") == 0) { + if (argc != 0) { + LOG_FATAL("Extraneous arguments to '%s'.", instr); + usage(); + } + if (bsys_clean(bsys) == 0) { rv = EXIT_SUCCESS; } @@ -331,7 +346,12 @@ int main(int argc, char* argv[]) { // This is intentionally undocumented, as it's really only used for communication between Bob parent processes and their Bob children processes. - else if (argc == 1 && strcmp(instr, "dep-tree") == 0) { + else if (strcmp(instr, "dep-tree") == 0) { + if (argc != 0) { + LOG_FATAL("Extraneous arguments to '%s'.", instr); + usage(); + } + LOG_WARN("This command is internal and isn't meant for direct use. A correct consumer of this command should be able to discard this message by reading the contents within the dependency tree tags."); if (bsys_dep_tree(bsys, argc, argv) == 0) { From 75882ea7a9a3f79e1ed1223dc4a509f705a66eb0 Mon Sep 17 00:00:00 2001 From: Aymeric Wibo Date: Wed, 25 Dec 2024 18:15:13 +0100 Subject: [PATCH 7/8] dep-tree: Remove wrong extraneous argument check --- src/main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main.c b/src/main.c index c7401519..39cd0869 100644 --- a/src/main.c +++ b/src/main.c @@ -347,11 +347,6 @@ int main(int argc, char* argv[]) { // This is intentionally undocumented, as it's really only used for communication between Bob parent processes and their Bob children processes. else if (strcmp(instr, "dep-tree") == 0) { - if (argc != 0) { - LOG_FATAL("Extraneous arguments to '%s'.", instr); - usage(); - } - LOG_WARN("This command is internal and isn't meant for direct use. A correct consumer of this command should be able to discard this message by reading the contents within the dependency tree tags."); if (bsys_dep_tree(bsys, argc, argv) == 0) { From fcaa37bb287652b174abba96a2fce2a6063831d9 Mon Sep 17 00:00:00 2001 From: Aymeric Wibo Date: Mon, 6 Jan 2025 17:32:44 +0100 Subject: [PATCH 8/8] ci/lint: Update to `intercept-build-18` --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 808dc90f..f05656cb 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,7 +17,7 @@ jobs: - name: Get all source files run: echo "SRC=$(find src -name "*.[ch]" -print0 -o -path src/flamingo -prune -type f | xargs -0 echo)" >> $GITHUB_ENV - name: Build (with LSP output) - run: intercept-build-15 sh bootstrap.sh + run: intercept-build-18 sh bootstrap.sh - name: Run clang-tidy run: clang-tidy $SRC - name: Make sure 'mkdir_wrapped' is used everywhere (except for once for 'fsutils.c')