From 66cfa12ace26825ddf35a8d49f5bab756a5fa60b Mon Sep 17 00:00:00 2001 From: Curtis McEnroe Date: Wed, 21 Feb 2018 14:46:27 -0500 Subject: Add broadcast --- broadcast.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 broadcast.c (limited to 'broadcast.c') diff --git a/broadcast.c b/broadcast.c new file mode 100644 index 0000000..e5957ae --- /dev/null +++ b/broadcast.c @@ -0,0 +1,117 @@ +/* Copyright (c) 2018, Curtis McEnroe + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined __FreeBSD__ +#include +#elif defined __linux__ +#include +#else +#include +#endif + +static struct termios saveTerm; +static void restoreTerm(void) { + tcsetattr(STDERR_FILENO, TCSADRAIN, &saveTerm); +} + +int main(int argc, char *argv[]) { + int error; + + if (argc > 1) { + argv++; + } else { + uid_t uid = getuid(); + struct passwd *user = getpwuid(uid); + if (!user) err(EX_OSFILE, "/etc/passwd"); + argv[0] = user->pw_shell; + } + + int input = STDIN_FILENO; + int local = STDERR_FILENO; + int remote = STDOUT_FILENO; + + error = tcgetattr(local, &saveTerm); + if (error) err(EX_IOERR, "tcgetattr"); + atexit(restoreTerm); + + struct termios raw; + cfmakeraw(&raw); + error = tcsetattr(local, TCSADRAIN, &raw); + if (error) err(EX_IOERR, "tcsetattr"); + + struct winsize window; + error = ioctl(local, TIOCGWINSZ, &window); + if (error) err(EX_IOERR, "ioctl(%d, TIOCGWINSZ, ...)", local); + + ssize_t size = write(remote, &window, sizeof(window)); + if (size < 0) err(EX_IOERR, "write(%d)", remote); + if ((size_t)size < sizeof(window)) errx(EX_IOERR, "short write(%d)", remote); + + int pty; + pid_t pid = forkpty(&pty, NULL, NULL, &window); + if (pid < 0) err(EX_OSERR, "forkpty"); + + if (!pid) { + execvp(*argv, argv); + err(EX_USAGE, "%s", *argv); + } + + char buf[4096]; + struct pollfd fds[2] = { + { .fd = input, .events = POLLIN }, + { .fd = pty, .events = POLLIN }, + }; + while (0 < poll(fds, 2, -1)) { + if (fds[0].revents) { + ssize_t readSize = read(input, buf, sizeof(buf)); + if (readSize < 0) err(EX_IOERR, "read(%d)", input); + + ssize_t writeSize = write(pty, buf, readSize); + if (writeSize < 0) err(EX_IOERR, "write(%d)", pty); + if (writeSize < readSize) errx(EX_IOERR, "short write(%d)", pty); + } + + if (fds[1].revents) { + ssize_t readSize = read(pty, buf, sizeof(buf)); + if (readSize < 0) err(EX_IOERR, "read(%d)", pty); + + ssize_t writeSize = write(local, buf, readSize); + if (writeSize < 0) err(EX_IOERR, "write(%d)", local); + if (writeSize < readSize) errx(EX_IOERR, "short write(%d)", local); + + writeSize = write(remote, buf, readSize); + if (writeSize < 0) err(EX_IOERR, "write(%d)", remote); + if (writeSize < readSize) errx(EX_IOERR, "short write(%d)", remote); + } + + int status; + pid_t dead = waitpid(pid, &status, WNOHANG); + if (dead < 0) err(EX_OSERR, "waitpid"); + if (dead) return WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE; + } + err(EX_IOERR, "poll"); +} -- cgit 1.4.1