From 6911c1b1acd455e514de2fc88b3eaf0a23cabdd6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 25 May 2015 20:57:47 +0200 Subject: Add Tomi Manninen OH2BNS's axwrapper program. Axwrapper first creates a pipe and then forks and execs the program with arguments given at the axwrapper command line. The argv[0] argument is mandatory; further arguments are optional. The parent process then sits and waits for any I/O to and from the user and converts any carriage return characters from the user to line feeds and any line feeds from the program to carriage returns. This is useful when starting non-AX.25-aware programs from ax25d. Signed-off-by: Ralf Baechle --- ax25/axwrapper.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 ax25/axwrapper.c (limited to 'ax25/axwrapper.c') diff --git a/ax25/axwrapper.c b/ax25/axwrapper.c new file mode 100644 index 0000000..872932a --- /dev/null +++ b/ax25/axwrapper.c @@ -0,0 +1,225 @@ +/* + * axwrapper.c - Convert end-of-line sequences for non-AX.25 aware programs - + * version 1.1 + * + * Copyright (C) 1996-2001 Tomi Manninen, OH2BNS, . + * + * Compile with: gcc -Wall -O6 -o axwrapper axwrapper.c + * + * Usage: axwrapper [-p ] ... + * + * Axwrapper first creates a pipe and then forks and execs the program + * with arguments given at the axwrapper command line. + * The parent process then sits and waits for any I/O to and from the + * user and converts any 's from user to 's and any 's from + * the program to 's. This is useful when starting non-AX.25 aware + * programs from ax25d. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FLUSHTIMEOUT 500000 /* 0.5 sec */ + +#define PERROR(s) fprintf(stderr, "*** %s: %s\r", (s), strerror(errno)) +#define USAGE() fputs("Usage: axwrapper [-p ] ...\r", stderr) + +void sigchld_handler(int sig) +{ + /* fprintf(stderr, "Caught SIGCHLD, exiting...\r"); */ + exit(0); +} + +void convert_cr_lf(unsigned char *buf, int len) +{ + while (len-- > 0) { + if (*buf == '\r') *buf = '\n'; + buf++; + } +} + +void convert_lf_cr(unsigned char *buf, int len) +{ + while (len-- > 0) { + if (*buf == '\n') *buf = '\r'; + buf++; + } +} + +int main(int argc, char **argv) +{ + unsigned char buf[4096], *stdoutbuf; + int pipe_in[2]; + int pipe_out[2]; + int pipe_err[2]; + int len; + int pid; + int paclen = 256; + fd_set fdset; + struct timeval tv; + + while ((len = getopt(argc, argv, "p:")) != -1) { + switch (len) { + case 'p': + paclen = atoi(optarg); + break; + case ':': + case '?': + USAGE(); + exit(1); + } + } + + if (argc - optind < 2) { + USAGE(); + exit(1); + } + + if ((stdoutbuf = malloc(paclen)) == NULL) { + PERROR("axwrapper: malloc"); + exit(1); + } + + setvbuf(stdout, stdoutbuf, _IOFBF, paclen); + + if (pipe(pipe_in) == -1) { + PERROR("axwrapper: pipe"); + exit(1); + } + if (pipe(pipe_out) == -1) { + PERROR("axwrapper: pipe"); + exit(1); + } + if (pipe(pipe_err) == -1) { + PERROR("axwrapper: pipe"); + exit(1); + } + + /* signal(SIGCHLD, sigchld_handler); */ + signal(SIGCHLD, SIG_IGN); + + pid = fork(); + + if (pid == -1) { + /* fork error */ + PERROR("axwrapper: fork"); + exit(1); + } + + if (pid == 0) { + /* child */ + dup2(pipe_in[0], STDIN_FILENO); + close(pipe_in[1]); + + dup2(pipe_out[1], STDOUT_FILENO); + close(pipe_out[0]); + + dup2(pipe_err[1], STDERR_FILENO); + close(pipe_err[0]); + + execve(argv[optind], argv + optind + 1, NULL); + + /* execve() should not return */ + perror("axwrapper: execve"); + exit(1); + } + + /* parent */ + + close(pipe_in[0]); + close(pipe_out[1]); + close(pipe_err[1]); + + if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) { + perror("axwrapper: fcntl"); + exit(1); + } + if (fcntl(pipe_out[0], F_SETFL, O_NONBLOCK) == -1) { + perror("axwrapper: fcntl"); + exit(1); + } + if (fcntl(pipe_err[0], F_SETFL, O_NONBLOCK) == -1) { + perror("axwrapper: fcntl"); + exit(1); + } + + while (1) { + FD_ZERO(&fdset); + FD_SET(STDIN_FILENO, &fdset); + FD_SET(pipe_out[0], &fdset); + FD_SET(pipe_err[0], &fdset); + tv.tv_sec = 0; + tv.tv_usec = FLUSHTIMEOUT; + + len = select(256, &fdset, 0, 0, &tv); + if (len == -1) { + perror("axwrapper: select"); + exit(1); + } + if (len == 0) { + fflush(stdout); + } + + if (FD_ISSET(STDIN_FILENO, &fdset)) { + len = read(STDIN_FILENO, buf, sizeof(buf)); + if (len < 0 && errno != EAGAIN) { + perror("axwrapper: read"); + break; + } + if (len == 0) + break; + convert_cr_lf(buf, len); + write(pipe_in[1], buf, len); + } + if (FD_ISSET(pipe_out[0], &fdset)) { + len = read(pipe_out[0], buf, sizeof(buf)); + if (len < 0 && errno != EAGAIN) { + perror("axwrapper: read"); + break; + } + if (len == 0) + break; + convert_lf_cr(buf, len); + fwrite(buf, 1, len, stdout); + } + if (FD_ISSET(pipe_err[0], &fdset)) { + len = read(pipe_err[0], buf, sizeof(buf)); + if (len < 0 && errno != EAGAIN) { + perror("axwrapper: read"); + break; + } + if (len == 0) + break; + convert_lf_cr(buf, len); + fwrite(buf, 1, len, stderr); + } + } + + kill(pid, SIGTERM); + close(pipe_in[1]); + close(pipe_out[0]); + close(pipe_err[0]); + return 0; +} -- cgit v1.2.3