summaryrefslogtreecommitdiffstats
path: root/ax25/axwrapper.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2015-05-25 20:57:47 +0200
committerRalf Baechle <ralf@linux-mips.org>2015-05-25 21:02:13 +0200
commit6911c1b1acd455e514de2fc88b3eaf0a23cabdd6 (patch)
tree4bcb25b6fd2e2374f66b5000b5ff12b6f7240ddf /ax25/axwrapper.c
parent4984e59635ed76196dc5f9a18ae8118be4853758 (diff)
Add Tomi Manninen OH2BNS's axwrapper program.
Axwrapper first creates a pipe and then forks and execs the program <server-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 <ralf@linux-mips.org>
Diffstat (limited to 'ax25/axwrapper.c')
-rw-r--r--ax25/axwrapper.c225
1 files changed, 225 insertions, 0 deletions
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, <tomi.manninen@hut.fi>.
+ *
+ * Compile with: gcc -Wall -O6 -o axwrapper axwrapper.c
+ *
+ * Usage: axwrapper [-p <paclen>] <filename> <argv[0]> ...
+ *
+ * Axwrapper first creates a pipe and then forks and execs the program
+ * <filename> 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 <CR>'s from user to <NL>'s and any <NL>'s from
+ * the program to <CR>'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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+
+#define FLUSHTIMEOUT 500000 /* 0.5 sec */
+
+#define PERROR(s) fprintf(stderr, "*** %s: %s\r", (s), strerror(errno))
+#define USAGE() fputs("Usage: axwrapper [-p <paclen>] <filename> <argv[0]> ...\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;
+}