Bash++
Bash++ compiler internal documentation
run_bash.h
Go to the documentation of this file.
1
7#pragma once
8
9#include <string>
10#include <vector>
11#include <cerrno>
12#include <system_error>
13
14#include <sys/wait.h>
15#include <unistd.h>
16
17#include <error/InternalError.h>
18
26inline int run_bash(const std::string& filename, const std::vector<char*>& arguments) {
27 std::vector<std::string> exec_args;
28 exec_args.reserve(2 + arguments.size());
29 exec_args.emplace_back("bash");
30 exec_args.emplace_back(filename);
31 for (auto* argument : arguments) {
32 exec_args.emplace_back(argument ? argument : "");
33 }
34
35 std::vector<char*> argv;
36 argv.reserve(exec_args.size() + 1);
37 for (auto& s : exec_args) {
38 argv.push_back(s.data());
39 }
40 argv.push_back(nullptr);
41
42 pid_t child = fork();
43 if (child < 0) {
44 std::error_code ec(errno, std::generic_category());
45 throw bpp::ErrorHandling::InternalError(std::string("fork() failed: ") + ec.message());
46 }
47
48 if (child == 0) {
49 // We are now in the child process. Execute the compiled script.
50 execvp(argv[0], argv.data());
51 // If exec fails, we cannot throw (we're in the child) and we must not run
52 // parent atexit handlers. Exit 127 is a widely-used convention for exec failure.
53 _exit(127);
54 }
55
56 int status = 0;
57 pid_t waited;
58 do {
59 waited = waitpid(child, &status, 0);
60 } while (waited < 0 && errno == EINTR);
61
62 if (waited < 0) {
63 std::error_code ec(errno, std::generic_category());
64 throw bpp::ErrorHandling::InternalError(std::string("waitpid() failed: ") + ec.message());
65 }
66
67 if (WIFEXITED(status)) {
68 return WEXITSTATUS(status);
69 } else if (WIFSIGNALED(status)) {
70 // If the child died due to a signal, there is no exit-status byte to report.
71 // There is a garbage "folklore" kind of rule that "most tools return 128 + signal number" in this case
72 // No spec in the world describes this, and the only way to know that we're "supposed" to do it
73 // is to be a member of their "boys' club."
74 // Can you tell I hate things like this?
75 // Undocumented folkloric conventions are what's wrong with FOSS & the primary mechanism for gatekeeping.
76 // Anyway, principle of least surprise, we'll do the same thing.
77 return 128 + WTERMSIG(status);
78 } else {
79 return EXIT_FAILURE;
80 }
81}
int run_bash(const std::string &filename, const std::vector< char * > &arguments)
Runs a Bash script with the given filename and arguments, and returns the exit code of the script.
Definition run_bash.h:26
An exception thrown when an internal error occurs.
Definition InternalError.h:21