diff options
-rw-r--r-- | sbin/ldattach/Makefile | 4 | ||||
-rw-r--r-- | sbin/ldattach/atomicio.c | 130 | ||||
-rw-r--r-- | sbin/ldattach/atomicio.h | 45 | ||||
-rw-r--r-- | sbin/ldattach/ldattach.8 | 14 | ||||
-rw-r--r-- | sbin/ldattach/ldattach.c | 102 |
5 files changed, 277 insertions, 18 deletions
diff --git a/sbin/ldattach/Makefile b/sbin/ldattach/Makefile index 58d57e4925b..0b1225111df 100644 --- a/sbin/ldattach/Makefile +++ b/sbin/ldattach/Makefile @@ -1,9 +1,11 @@ -# $OpenBSD: Makefile,v 1.1.1.1 2007/11/03 15:22:54 mbalmer Exp $ +# $OpenBSD: Makefile,v 1.2 2008/06/09 21:06:10 mbalmer Exp $ PROG= ldattach +SRCS= ldattach.c atomicio.c MAN= ldattach.8 CFLAGS+= -Wall -Werror +LDADD+= -lutil BINDIR= /sbin diff --git a/sbin/ldattach/atomicio.c b/sbin/ldattach/atomicio.c new file mode 100644 index 00000000000..5adb7fd0597 --- /dev/null +++ b/sbin/ldattach/atomicio.c @@ -0,0 +1,130 @@ +/* $OpenBSD: atomicio.c,v 1.1 2008/06/09 21:06:10 mbalmer Exp $ */ +/* + * Copyright (c) 2006 Damien Miller. All rights reserved. + * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/uio.h> + +#include <errno.h> +#include <poll.h> +#include <string.h> +#include <unistd.h> + +#include "atomicio.h" + +/* + * ensure all of data on socket comes through. f==read || f==vwrite + */ +size_t +atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) +{ + char *s = _s; + size_t pos = 0; + ssize_t res; + struct pollfd pfd; + + pfd.fd = fd; + pfd.events = f == read ? POLLIN : POLLOUT; + while (n > pos) { + res = (f) (fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR) + continue; + if (errno == EAGAIN) { + (void)poll(&pfd, 1, -1); + continue; + } + return 0; + case 0: + errno = EPIPE; + return pos; + default: + pos += (size_t)res; + } + } + return (pos); +} + +/* + * ensure all of data on socket comes through. f==readv || f==writev + */ +size_t +atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, + const struct iovec *_iov, int iovcnt) +{ + size_t pos = 0, rem; + ssize_t res; + struct iovec iov_array[IOV_MAX], *iov = iov_array; + struct pollfd pfd; + + if (iovcnt > IOV_MAX) { + errno = EINVAL; + return 0; + } + /* Make a copy of the iov array because we may modify it below */ + memcpy(iov, _iov, iovcnt * sizeof(*_iov)); + + pfd.fd = fd; + pfd.events = f == readv ? POLLIN : POLLOUT; + for (; iovcnt > 0 && iov[0].iov_len > 0;) { + res = (f) (fd, iov, iovcnt); + switch (res) { + case -1: + if (errno == EINTR) + continue; + if (errno == EAGAIN) { + (void)poll(&pfd, 1, -1); + continue; + } + return 0; + case 0: + errno = EPIPE; + return pos; + default: + rem = (size_t)res; + pos += rem; + /* skip completed iov entries */ + while (iovcnt > 0 && rem >= iov[0].iov_len) { + rem -= iov[0].iov_len; + iov++; + iovcnt--; + } + /* This shouldn't happen... */ + if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) { + errno = EFAULT; + return 0; + } + if (iovcnt == 0) + break; + /* update pointer in partially complete iov */ + iov[0].iov_base = ((char *)iov[0].iov_base) + rem; + iov[0].iov_len -= rem; + } + } + return pos; +} diff --git a/sbin/ldattach/atomicio.h b/sbin/ldattach/atomicio.h new file mode 100644 index 00000000000..3ff368a2cd0 --- /dev/null +++ b/sbin/ldattach/atomicio.h @@ -0,0 +1,45 @@ +/* $OpenBSD: atomicio.h,v 1.1 2008/06/09 21:06:10 mbalmer Exp $ */ + +/* + * Copyright (c) 2006 Damien Miller. All rights reserved. + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ATOMICIO_H +#define _ATOMICIO_H + +/* + * Ensure all of data on socket comes through. f==read || f==vwrite + */ +size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); + +#define vwrite (ssize_t (*)(int, void *, size_t))write + +/* + * ensure all of data on socket comes through. f==readv || f==writev + */ +size_t atomiciov(ssize_t (*)(int, const struct iovec *, int), + int, const struct iovec *, int); + +#endif /* _ATOMICIO_H */ diff --git a/sbin/ldattach/ldattach.8 b/sbin/ldattach/ldattach.8 index 4b784ed7bf6..478646738a8 100644 --- a/sbin/ldattach/ldattach.8 +++ b/sbin/ldattach/ldattach.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ldattach.8,v 1.10 2008/02/28 11:22:12 mbalmer Exp $ +.\" $OpenBSD: ldattach.8,v 1.11 2008/06/09 21:06:10 mbalmer Exp $ .\" .\" Copyright (c) 2007, 2008 Marc Balmer <mbalmer@openbsd.org> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: February 28 2008 $ +.Dd $Mdocdate: June 9 2008 $ .Dt LDATTACH 8 .Os .Sh NAME @@ -22,7 +22,7 @@ .Nd attach a line discipline to a serial line .Sh SYNOPSIS .Nm ldattach -.Op Fl 27dehmo +.Op Fl 27dehmop .Op Fl s Ar baudrate .Op Fl t Ar cond .Ar discipline @@ -59,6 +59,13 @@ Maintain modem control signals after closing the line. Specifically, this disables HUPCL. .It Fl o Use odd parity. +.It Fl p +Pass the data received from +.Ar device +to the master device of a +.Xr pty 4 +pair and vice versa. +The name of the slave device is written to standard output. .It Fl s Ar baudrate Specifies the speed of the connection. If not specified, the default of 9600 baud is used @@ -153,6 +160,7 @@ tty01 "/sbin/ldattach nmea" unknown on softcar .Sh SEE ALSO .Xr msts 4 , .Xr nmea 4 , +.Xr pty 4 , .Xr sl 4 , .Xr tty 4 , .Xr ttys 5 , diff --git a/sbin/ldattach/ldattach.c b/sbin/ldattach/ldattach.c index db3549e1a1e..32389611237 100644 --- a/sbin/ldattach/ldattach.c +++ b/sbin/ldattach/ldattach.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ldattach.c,v 1.5 2008/02/28 11:22:12 mbalmer Exp $ */ +/* $OpenBSD: ldattach.c,v 1.6 2008/06/09 21:06:10 mbalmer Exp $ */ /* * Copyright (c) 2007, 2008 Marc Balmer <mbalmer@openbsd.org> @@ -21,14 +21,18 @@ * the commandline or from init(8) (using entries in /etc/ttys). */ +#include <sys/types.h> #include <sys/ioctl.h> #include <sys/limits.h> +#include <sys/socket.h> +#include <sys/stat.h> #include <sys/ttycom.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <paths.h> +#include <poll.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -36,8 +40,12 @@ #include <syslog.h> #include <termios.h> #include <unistd.h> +#include <util.h> + +#include "atomicio.h" __dead void usage(void); +void relay(int, int); void coroner(int); volatile sig_atomic_t dying = 0; @@ -47,11 +55,53 @@ usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-27dehmo] [-s baudrate] " + fprintf(stderr, "usage: %s [-27dehmop] [-s baudrate] " "[-t cond] discipline device\n", __progname); exit(1); } +/* relay data between two file descriptors */ +void +relay(int device, int pty) +{ + struct pollfd pfd[2]; + int nfds, n, nread; + char buf[128]; + + pfd[0].fd = device; + pfd[0].events = POLLRDNORM; + pfd[1].fd = pty; + pfd[1].events = POLLRDNORM; + + while (!dying) { + nfds = poll(pfd, 2, INFTIM); + if (nfds == -1) { + syslog(LOG_ERR, "polling error"); + exit(1); + } + if (nfds == 0) + continue; + + for (n = 0; n < 2; n++) { + if (!(pfd[n].revents & POLLRDNORM)) + continue; + + nread = read(pfd[n].fd, buf, sizeof(buf)); + if (nread == -1) { + syslog(LOG_ERR, "error reading from %s: %m", + n ? "pty" : "device"); + exit(1); + } + if (nread == 0) { + syslog(LOG_ERR, "eof during read from %s: %m", + n ? "pty" : "device"); + exit(1); + } + atomicio(vwrite, pfd[1 - n].fd, buf, nread); + } + } +} + int main(int argc, char *argv[]) { @@ -60,17 +110,17 @@ main(int argc, char *argv[]) const char *errstr; sigset_t sigset; pid_t ppid; - int ch, fd, ldisc, nodaemon = 0; - int bits = 0, parity = 0, stop = 0, flowcl = 0, hupcl = 1; + int ch, fd, master = -1, slave, pty = 0, ldisc, nodaemon = 0; + int bits = 0, parity = 0, stop = 0, flowcl = 0, hupcl = 1; speed_t speed = 0; - char devn[32], *dev, *disc; + char devn[32], ptyn[32], *dev, *disc; tstamps.ts_set = tstamps.ts_clr = 0; if ((ppid = getppid()) == 1) nodaemon = 1; - while ((ch = getopt(argc, argv, "27dehmos:t:")) != -1) { + while ((ch = getopt(argc, argv, "27dehmops:t:")) != -1) { switch (ch) { case '2': stop = 2; @@ -93,6 +143,9 @@ main(int argc, char *argv[]) case 'o': parity = 'o'; break; + case 'p': + pty = 1; + break; case 's': speed = (speed_t)strtonum(optarg, 0, UINT_MAX, &errstr); if (errstr) { @@ -134,8 +187,7 @@ main(int argc, char *argv[]) disc = *argv++; dev = *argv; if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) { - (void)snprintf(devn, sizeof(devn), - "%s%s", _PATH_DEV, dev); + (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev); dev = devn; } @@ -204,7 +256,7 @@ main(int argc, char *argv[]) if (ioctl(fd, TIOCSDTR, 0) < 0) warn("TIOCSDTR"); if (ioctl(fd, TIOCSETD, &ldisc) < 0) { - syslog(LOG_ERR, "can't set the %s line discipline on %s", disc, + syslog(LOG_ERR, "can't attach %s line discipline on %s", disc, dev); goto bail_out; } @@ -233,16 +285,38 @@ main(int argc, char *argv[]) goto bail_out; } - if (!nodaemon && daemon(0, 0)) - errx(1, "can't daemonize"); + /* + * open a pty(4) pair to pass the data if the -p option has been + * given on the commandline. + */ + if (pty) { + if (openpty(&master, &slave, ptyn, NULL, NULL)) + errx(1, "can't open a pty"); + close(slave); + printf("%s\n", ptyn); + } + if (nodaemon) + openlog("ldattach", LOG_PID | LOG_CONS | LOG_PERROR, + LOG_DAEMON); + else { + openlog("ldattach", LOG_PID | LOG_CONS, LOG_DAEMON); + if (daemon(0, 0)) + errx(1, "can't daemonize"); + } syslog(LOG_INFO, "attach %s on %s", disc, dev); signal(SIGHUP, coroner); signal(SIGTERM, coroner); - sigemptyset(&sigset); - while (!dying) - sigsuspend(&sigset); + if (master != -1) { + syslog(LOG_INFO, "passing data to %s", ptyn); + relay(fd, master); + } else { + sigemptyset(&sigset); + + while (!dying) + sigsuspend(&sigset); + } bail_out: if (ppid == 1) |