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') 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); diff --git a/src/cmd.c b/src/cmd.c index fb5f3dbe..b54121e2 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -44,8 +44,14 @@ void cmd_create(cmd_t* cmd, ...) { va_end(va); + cmd_set_redirect(cmd, true); + 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) { @@ -83,6 +89,22 @@ 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; +} + +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; @@ -154,10 +176,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) { @@ -169,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 @@ -178,13 +213,18 @@ 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); 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; @@ -192,17 +232,33 @@ 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); - if (!debugging) { + if (cmd->redirect) { close(cmd->in); 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; } @@ -244,7 +300,7 @@ char* cmd_read_out(cmd_t* cmd) { char* out = strdup(""); assert(out != NULL); - if (debugging) { + if (!cmd->redirect) { return out; } @@ -358,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); } @@ -372,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); 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 ? ":" : "."; diff --git a/src/main.c b/src/main.c index 5720be2d..39cd0869 100644 --- a/src/main.c +++ b/src/main.c @@ -300,6 +300,11 @@ int main(int argc, char* argv[]) { instr = *argv++; if (strcmp(instr, "build") == 0) { + if (argc != 0) { + LOG_FATAL("Extraneous arguments to '%s'.", instr); + usage(); + } + if (bsys_build(bsys) == 0) { rv = EXIT_SUCCESS; } @@ -318,12 +323,22 @@ int main(int argc, char* argv[]) { } 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 (strcmp(instr, "clean") == 0) { + if (argc != 0) { + LOG_FATAL("Extraneous arguments to '%s'.", instr); + usage(); + } + if (bsys_clean(bsys) == 0) { rv = EXIT_SUCCESS; } 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)))