[PATCH][RESEND] ldattach(8) [v2]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add an ldattach(8) utility program similar to the one in OpenBSD.

Signed-off-by: Tilman Schmidt <tilman@xxxxxxx>
---

Resending as requested.
Incorporates comments on the first version, now has support for arbitrary
line speeds if the platform supports them, corresponding long options for
all short options, and a more complete manpage. Size slightly increased
(by about 15%) as a result. Comments welcome.

 sys-utils/Makefile.am |    4
 sys-utils/ldattach.8  |  130 +++++++++++++++++++
 sys-utils/ldattach.c  |  327 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 459 insertions(+), 2 deletions(-)

diff -purNX dontdiff a/sys-utils/ldattach.8 b/sys-utils/ldattach.8
--- a/sys-utils/ldattach.8	1970-01-01 01:00:00.000000000 +0100
+++ b/sys-utils/ldattach.8	2008-02-07 00:42:51.000000000 +0100
@@ -0,0 +1,130 @@
+.\" Copyright 2008 Tilman Schmidt (tilman@xxxxxxx)
+.\" May be distributed under the GNU General Public License version 2 or later
+.TH LDATTACH 8 "14 January 2008" "Linux 2.6" "Linux Programmer's Manual"
+.SH NAME
+ldattach \- attach a line discipline to a serial line
+.SH SYNOPSIS
+.nf
+.BI "ldattach [ \-dhV78neo12 ] [ \-s " speed " ] " "ldisc device"
+.fi
+.SH DESCRIPTION
+The
+.B ldattach
+daemon opens the specified
+.I device
+file
+(which should refer to a serial device)
+and attaches the line discipline
+.B ldisc
+to it for processing of the sent and/or received data.
+It then goes into the background keeping the device open so that the
+line discipline stays loaded.
+
+The line discipline
+.B ldisc
+may be specified either by name
+or by number.
+
+In order to detach the line discipline,
+.BR kill (1)
+the
+.B ldattach
+process.
+
+With no arguments,
+.B ldattach
+prints usage information.
+.SH LINE DISCIPLINES
+As of kernel release 2.6.21, the following line disciplines are supported:
+.TP
+.BR TTY ( 0 )
+The default line discipline,
+providing transparent operation (raw mode)
+as well as the habitual terminal line editing capabilities (cooked mode).
+.TP
+.BR SLIP ( 1 )
+Serial Line IP (SLIP) protocol processor
+for transmitting TCP/IP packets over serial lines.
+.TP
+.BR MOUSE ( 2 )
+Device driver for RS232 connected pointing devices (serial mice).
+.TP
+.BR PPP ( 3 )
+Point to Point Protocol (PPP) processor
+for transmitting network packets over serial lines.
+.TP
+.BR STRIP ( 4 )
+.TP
+.BR AX25 ( 5 )
+.TP
+.BR X25 ( 6 )
+Line driver for transmitting X.25 packets over asynchronous serial lines.
+.TP
+.BR 6PACK ( 7 )
+.TP
+.BR R3964 ( 9 )
+Driver for Simatic R3964 module.
+.TP
+.BR IRDA ( 11 )
+Linux IrDa (infrared data transmission) driver -
+see http://irda.sourceforge.net/
+.TP
+.BR HDLC ( 13 )
+Synchronous HDLC driver.
+.TP
+.BR SYNC_PPP ( 14 )
+Synchronous PPP driver.
+.TP
+.BR HCI ( 15 )
+Bluetooth HCI UART driver.
+.TP
+.BR GIGASET_M101 ( 16 )
+Driver for Siemens Gigaset M101 serial DECT adapter.
+.SH OPTIONS
+.TP
+\fB-d\fP | \fB--debug\fP
+Causes
+.B ldattach
+to stay in the foreground so that it can be interrupted or debugged,
+and to print verbose messages about its progress to the standard error output.
+.TP
+\fB-h\fP | \fB--help\fP
+Prints a usage message and exits.
+.TP
+\fB-V\fP | \fB--version\fP
+Prints the program version.
+.TP
+\fB-s\fP \fIvalue\fP | \fB--speed\fP \fIvalue\fP
+Set the speed of the serial line to the specified value.
+.TP
+\fB-7\fP | \fB--sevenbits\fP
+Sets the character size of the serial line to 7 bits.
+.TP
+\fB-8\fP | \fB--eightbits\fP
+Sets the character size of the serial line to 8 bits.
+.TP
+\fB-n\fP | \fB--noparity\fP
+Sets the parity of the serial line to none.
+.TP
+\fB-e\fP | \fB--evenparity\fP
+Sets the parity of the serial line to even.
+.TP
+\fB-o\fP | \fB--oddparity\fP
+Sets the parity of the serial line to odd.
+.TP
+\fB-1\fP | \fB--onestopbit\fP
+Sets the number of stop bits of the serial line to one.
+.TP
+\fB-2\fP | \fB--twostopbits\fP
+Sets the number of stop bits of the serial line to two.
+.SH "SEE ALSO"
+.BR inputattach (1),
+.BR ttys (4)
+.SH AUTHOR
+.nf
+Tilman Schmidt (tilman@xxxxxxx)
+.fi
+.SH AVAILABILITY
+The ldattach command is part of the util-linux-ng package
+and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/.
diff -purNX dontdiff a/sys-utils/ldattach.c b/sys-utils/ldattach.c
--- a/sys-utils/ldattach.c	1970-01-01 01:00:00.000000000 +0100
+++ b/sys-utils/ldattach.c	2008-02-10 02:25:13.000000000 +0100
@@ -0,0 +1,327 @@
+/* line discipline loading daemon
+ * open a serial device and attach a line discipline on it
+ *
+ * Usage:
+ *	ldattach GIGASET_M101 /dev/ttyS0
+ *
+ * =====================================================================
+ * 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.
+ * =====================================================================
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <asm/termbits.h>
+#include <unistd.h>
+#include <err.h>
+
+#define dbg(format, arg...) \
+	do { if (debug) fprintf(stderr , "%s:" format "\n" , progname , ## arg); } while (0)
+
+#ifndef N_GIGASET_M101
+#define N_GIGASET_M101 16
+#endif
+
+#ifndef PACKAGE_STRING
+#define PACKAGE_STRING "me"
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+static const char *progname;
+static int debug = 0;
+
+/* currently supported line disciplines, plus some aliases */
+static const struct ld_entry { const char *s; int v; }
+ld_table[] = {
+	{ "TTY",	N_TTY },
+	{ "SLIP",	N_SLIP },
+	{ "MOUSE",	N_MOUSE },
+	{ "PPP",	N_PPP },
+	{ "STRIP",	N_STRIP },
+	{ "AX25",	N_AX25 },
+	{ "X25",	N_X25 },
+	{ "6PACK",	N_6PACK },
+	{ "R3964",	N_R3964 },
+	{ "IRDA",	N_IRDA },
+	{ "HDLC",	N_HDLC },
+	{ "SYNC_PPP",	N_SYNC_PPP },
+	{ "SYNCPPP",	N_SYNC_PPP },
+	{ "HCI",	N_HCI },
+	{ "GIGASET_M101",	N_GIGASET_M101 },
+	{ "GIGASET",	N_GIGASET_M101 },
+	{ "M101",	N_GIGASET_M101 }
+};
+
+/* look up line discipline code */
+static int lookup_ld(const char *s)
+{
+    size_t i;
+
+    for (i = 0; i < ARRAY_SIZE(ld_table); i++)
+	if (!strcasecmp(ld_table[i].s, s))
+	    return ld_table[i].v;
+    return -1;
+}
+
+/* replacement for tcsetattr(3) and friends supporting arbitrary speed values */
+
+/* some archs don't have separate struct termios2 */
+#ifndef TCGETS2
+#define termios2 termios
+#define TCGETS2 TCGETS
+#define TCSETS2 TCSETS
+#define TCSETSW2 TCSETSW
+#define TCSETSF2 TCSETSF
+#endif
+
+static int tcgetattr2(int fd, struct termios2 *pts)
+{
+    return ioctl(fd, TCGETS2, pts);
+}
+
+static int tcsetattr2(int fd, int option, const struct termios2 *pts)
+{
+    int request;
+
+    switch (option) {
+    case TCSANOW:
+	request = TCSETS2;
+	break;
+    case TCSADRAIN:
+	request = TCSETSW2;
+	break;
+    case TCSAFLUSH:
+	request = TCSETSF2;
+	break;
+    default:
+	errno = -EINVAL;
+	return -1;
+    }
+    return ioctl(fd, request, pts);
+}
+
+static void cfmakeraw2(struct termios2 *pts)
+{
+    pts->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+    pts->c_oflag &= ~OPOST;
+    pts->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+    pts->c_cflag &= ~(CSIZE|PARENB);
+    pts->c_cflag |= CS8;
+}
+
+/* table of standard line speeds */
+static const struct speed_entry { int s; speed_t v; }
+speed_table[] = {
+	{ 50,     B50 },
+	{ 75,     B75 },
+	{ 110,    B110 },
+	{ 134,    B134 },
+	{ 150,    B150 },
+	{ 200,    B200 },
+	{ 300,    B300 },
+	{ 600,    B600 },
+	{ 1200,   B1200 },
+	{ 1800,   B1800 },
+	{ 2400,   B2400 },
+	{ 4800,   B4800 },
+	{ 9600,   B9600 },
+	{ 19200,  B19200 },
+	{ 38400,  B38400 }
+#ifdef B57600
+	,{ 57600,  B57600 }
+#endif
+#ifdef B115200
+	,{ 115200, B115200 }
+#endif
+#ifdef B230400
+	,{ 230400, B230400 }
+#endif
+};
+
+static int cfsetspeed2(struct termios2 *pts, int speed)
+{
+    size_t i;
+
+    /* try POSIX method first */
+    for (i = 0; i < ARRAY_SIZE(speed_table); i++)
+	if (speed_table[i].s == speed) {
+	    pts->c_cflag &= ~CBAUD;
+	    pts->c_cflag |= speed_table[i].v;
+	    return 0;
+	}
+
+#ifdef BOTHER
+    /* new method available */
+    pts->c_ospeed = pts->c_ispeed = speed;
+    pts->c_cflag &= ~CBAUD;
+    pts->c_cflag |= BOTHER;
+    return 0;
+#else
+    /* new method not available */
+    return -1;
+#endif
+}
+
+static void __attribute__((__noreturn__)) usage(int exitcode)
+{
+    size_t i;
+
+    fprintf(stderr,
+	    "\nUsage: %s [ -dhV78neo12 ] [ -s <speed> ] <ldisc> <device>\n",
+	    progname);
+    fprintf(stderr, "\nKnown <ldisc> names:\n");
+    for (i = 0; i < ARRAY_SIZE(ld_table); i++)
+	fprintf(stderr, "  %s\n", ld_table[i].s);
+    exit(exitcode);
+}
+
+int main(int argc, char **argv)
+{
+    int tty_fd;
+    struct termios2 ts;
+    int speed = 0, bits = '-', parity = '-', stop = '-';
+    int ldisc;
+    int optc;
+    char *end;
+    char *dev;
+    static const struct option opttbl[] = {
+	{"speed", 1, 0, 's'},
+	{"sevenbits", 0, 0, '7'},
+	{"eightbits", 0, 0, '8'},
+	{"noparity", 0, 0, 'n'},
+	{"evenparity", 0, 0, 'e'},
+	{"oddparity", 0, 0, 'o'},
+	{"onestopbit", 0, 0, '1'},
+	{"twostopbits", 0, 0, '2'},
+	{"help", 0, 0, 'h'},
+	{"version", 0, 0, 'V'},
+	{"debug", 0, 0, 'd'},
+	{0, 0, 0, 0}
+    };
+
+    /* parse options */
+    progname = argv[0];
+    if (argc == 0)
+	usage(EXIT_SUCCESS);
+    while ((optc = getopt_long(argc, argv, "dhV78neo12s:", opttbl, NULL)) >= 0) {
+	switch (optc) {
+	case 'd':
+	    debug++;
+	    break;
+	case '1':
+	case '2':
+	    stop = optc;
+	    break;
+	case '7':
+	case '8':
+	    bits = optc;
+	    break;
+	case 'n':
+	case 'e':
+	case 'o':
+	    parity = optc;
+	    break;
+	case 's':
+	    speed = strtol(optarg, &end, 10);
+	    if (*end || speed <= 0)
+		errx(EXIT_FAILURE, "invalid speed: %s", optarg);
+	    break;
+	case 'V':
+	    printf("ldattach from %s\n", PACKAGE_STRING);
+	    break;
+	case 'h':
+	    usage(EXIT_SUCCESS);
+	default:
+	    warnx("invalid option");
+	    usage(EXIT_FAILURE);
+	}
+    }
+
+    if (argc - optind != 2)
+	usage(EXIT_FAILURE);
+
+    /* parse line discipline specification */
+    if ((ldisc = lookup_ld(argv[optind])) < 0) {
+	ldisc = strtol(argv[optind], &end, 0);
+	if (*end || ldisc < 0)
+	    errx(EXIT_FAILURE, "invalid line discipline: %s", argv[optind]);
+    }
+
+    /* open device */
+    dev = argv[optind+1];
+    if ((tty_fd = open(dev, O_RDWR|O_NOCTTY)) < 0)
+	err(EXIT_FAILURE, "cannot open %s", dev);
+    if (!isatty(tty_fd))
+	errx(EXIT_FAILURE, "%s is not a serial line", dev);
+
+    dbg("opened %s", dev);
+
+    /* set line speed and format */
+    if (tcgetattr2(tty_fd, &ts) < 0)
+	err(EXIT_FAILURE, "cannot get terminal attributes for %s", dev);
+    cfmakeraw2(&ts);
+    if (speed && cfsetspeed2(&ts, speed) < 0)
+	errx(EXIT_FAILURE, "speed %d unsupported", speed);
+    switch (stop) {
+    case '1':
+	ts.c_cflag &= ~CSTOPB;
+	break;
+    case '2':
+	ts.c_cflag |= CSTOPB;
+	break;
+    }
+    switch (bits) {
+    case '7':
+	ts.c_cflag = (ts.c_cflag & ~CSIZE) | CS7;
+	break;
+    case '8':
+	ts.c_cflag = (ts.c_cflag & ~CSIZE) | CS8;
+	break;
+    }
+    switch (parity) {
+    case 'n':
+	ts.c_cflag &= ~(PARENB|PARODD);
+	break;
+    case 'e':
+	ts.c_cflag |= PARENB;
+	ts.c_cflag &= ~PARODD;
+	break;
+    case 'o':
+	ts.c_cflag |= (PARENB|PARODD);
+	break;
+    }
+    ts.c_cflag |= CREAD;	/* just to be on the safe side */
+    if (tcsetattr2(tty_fd, TCSAFLUSH, &ts) < 0)
+	err(EXIT_FAILURE, "cannot set terminal attributes for %s", dev);
+
+    dbg("set to raw %d %c%c%c: cflag=0x%x",
+	speed, bits, parity, stop, ts.c_cflag);
+
+    /* Attach the line discpline. */
+    if (ioctl(tty_fd, TIOCSETD, &ldisc) < 0)
+	err(EXIT_FAILURE, "cannot set line discipline");
+
+    dbg("line discipline set to %d", ldisc);
+
+    /* Go into background if not in debug mode. */
+    if (!debug && daemon(0, 0) < 0)
+	err(EXIT_FAILURE, "cannot daemonize");
+
+    /* Sleep to keep the line discipline active. */
+    pause();
+
+    exit(EXIT_SUCCESS);
+}
diff -purNX dontdiff a/sys-utils/Makefile.am b/sys-utils/Makefile.am
--- a/sys-utils/Makefile.am	2008-01-16 10:31:42.000000000 +0100
+++ b/sys-utils/Makefile.am	2008-02-03 13:47:26.000000000 +0100
@@ -8,12 +8,12 @@ cytune_SOURCES = cytune.c cyclades.h

 sbin_PROGRAMS = ctrlaltdel

-usrsbinexec_PROGRAMS = readprofile tunelp rtcwake
+usrsbinexec_PROGRAMS = ldattach readprofile tunelp rtcwake

 tunelp_SOURCES = tunelp.c lp.h

 man_MANS = flock.1 readprofile.1 \
-	ctrlaltdel.8 cytune.8 dmesg.1 ipcrm.1 ipcs.1 renice.1 \
+	ctrlaltdel.8 cytune.8 dmesg.1 ipcrm.1 ipcs.1 ldattach.8 renice.1 \
 	setsid.1 tunelp.8 setarch.8 rtcwake.8

 info_TEXINFOS = ipc.texi


-- 
Tilman Schmidt                          E-Mail: tilman@xxxxxxx
Bonn, Germany
Diese Nachricht besteht zu 100% aus wiederverwerteten Bits.
Ungeöffnet mindestens haltbar bis: (siehe Rückseite)

Attachment: signature.asc
Description: OpenPGP digital signature


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux