diff options
author | Andrew Waterman <waterman@cs.berkeley.edu> | 2014-12-20 13:37:14 -0800 |
---|---|---|
committer | Andrew Waterman <waterman@cs.berkeley.edu> | 2014-12-20 13:37:14 -0800 |
commit | 416c8be88c712a99451f3770534a7fe712cb17af (patch) | |
tree | 7157bc929b92b8a48bf3514f06ae5a51b3e5937f /spike_main/xspike.cc | |
parent | e26e8c58799c2b179940b83e1ab4f376a132774d (diff) | |
download | spike-416c8be88c712a99451f3770534a7fe712cb17af.zip spike-416c8be88c712a99451f3770534a7fe712cb17af.tar.gz spike-416c8be88c712a99451f3770534a7fe712cb17af.tar.bz2 |
Support building from within root directory
Diffstat (limited to 'spike_main/xspike.cc')
-rw-r--r-- | spike_main/xspike.cc | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/spike_main/xspike.cc b/spike_main/xspike.cc new file mode 100644 index 0000000..4331dbe --- /dev/null +++ b/spike_main/xspike.cc @@ -0,0 +1,102 @@ +// See LICENSE for license details. + +// xspike forks an xterm for spike's target machine console, +// preserving the current terminal for debugging. + +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/wait.h> +#include <cstdio> +#include <climits> +#include <cstring> +#include <stdexcept> + +static pid_t fork_spike(int tty_fd, int argc, char** argv); +static pid_t fork_xterm(int* tty_fd); + +int main(int argc, char** argv) +{ + int tty_fd, wait_status, ret = -1; + pid_t xterm, spike; + + static bool signal_exit = false; + auto handle_signal = [](int) { signal_exit = true; }; + + if ((xterm = fork_xterm(&tty_fd)) < 0) + { + fprintf(stderr, "could not open xterm\n"); + goto out; + } + + signal(SIGINT, handle_signal); + + if ((spike = fork_spike(tty_fd, argc, argv)) < 0) + { + fprintf(stderr, "could not open spike\n"); + goto close_xterm; + } + + while ((ret = waitpid(spike, &wait_status, 0)) < 0) + if (signal_exit) + break; + + if (ret < 0) // signal_exit + kill(spike, SIGTERM); + else + ret = WIFEXITED(wait_status) ? WEXITSTATUS(wait_status) : -1; + +close_xterm: + kill(-xterm, SIGTERM); +out: + return ret; +} + +static pid_t fork_spike(int tty_fd, int argc, char** argv) +{ + pid_t pid = fork(); + if (pid < 0) + return -1; + + if (pid == 0) + { + if (dup2(tty_fd, STDIN_FILENO) < 0 || dup2(tty_fd, STDOUT_FILENO) < 0) + return -1; + execvp("spike", argv); + return -1; + } + + return pid; +} + +static pid_t fork_xterm(int* tty_fd) +{ + static const char cmd[] = "3>&1 xterm -title xspike -e sh -c 'tty 1>&3; termios-xspike'"; + + int fds[2]; + if (pipe(fds) < 0) + return -1; + + pid_t pid = fork(); + if (pid < 0) + return -1; + + if (pid == 0) + { + setpgid(0, 0); + if (dup2(fds[1], STDOUT_FILENO) < 0) + return -1; + execl("/bin/sh", "sh", "-c", cmd, NULL); + return -1; + } + + char tty[NAME_MAX]; + ssize_t ttylen = read(fds[0], tty, sizeof(tty)); + if (ttylen <= 1 || tty[ttylen-1] != '\n') + return -1; + tty[ttylen-1] = '\0'; + if ((*tty_fd = open(tty, O_RDWR)) < 0) + return -1; + + return pid; +} |