[Originally sent on Sun, 3 Feb 2008 14:02:17 +0100 (CET). Resending
 because it hasn't appeared on the list yet.]

From: Tilman Schmidt <[EMAIL PROTECTED]>

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

Signed-off-by: Tilman Schmidt <[EMAIL PROTECTED]>
---

Ok, so I'm impatient and instead of waiting any longer for a reply, I just
went ahead and wrote ldattach for Linux as I saw fit. Comments welcome.

 sys-utils/Makefile.am |    4
 sys-utils/ldattach.8  |  121 +++++++++++++++++++++
 sys-utils/ldattach.c  |  284 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 407 insertions(+), 2 deletions(-)

diff -purP 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
diff -purP 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-03 13:00:56.000000000 +0100
@@ -0,0 +1,121 @@
+.\" Copyright 2008 Tilman Schmidt ([EMAIL PROTECTED])
+.\" May be distributed under the GNU General Public License
+.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 [ \-d78neo12 ] [ \-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
+.B \-d
+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
+.BI \-s " value"
+Set the speed of the serial line to the specified value.
+.TP
+.B \-7
+Sets the character size of the serial line to 7 bits.
+.TP
+.B \-8
+Sets the character size of the serial line to 8 bits.
+.TP
+.B \-n
+Sets the parity of the serial line to none.
+.TP
+.B \-e
+Sets the parity of the serial line to even.
+.TP
+.B \-e
+Sets the parity of the serial line to odd.
+.TP
+.B \-1
+Sets the number of stop bits of the serial line to one.
+.TP
+.B \-2
+Sets the number of stop bits of the serial line to two.
+.SH AUTHORS
+.nf
+Tilman Schmidt ([EMAIL PROTECTED])
+.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 -purP 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-03 13:00:56.000000000 +0100
@@ -0,0 +1,284 @@
+/* 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 <termios.h>
+#include <unistd.h>
+
+#define dbg(format, arg...) \
+       do { if (debug) fprintf(stderr , format , ## arg); } while (0)
+
+#ifndef N_GIGASET_M101
+#define N_GIGASET_M101 16
+#endif
+
+static int ldisc;
+static speed_t speed = B0;
+static int debug = 0;
+
+/* look up line discipline code */
+static int lookup_ld(const char *s)
+{
+    static const struct ld_entry { const char *s; int v; }
+    ld_table[] = {
+       /* currently supported line disciplines, plus some aliases */
+       { "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 },
+       { NULL, -1 }
+    };
+    const struct ld_entry *ple = ld_table;
+
+    while (ple->s && strcasecmp(ple->s, s))
+       ple++;
+    return ple->v;
+}
+
+/* look up speed code */
+static speed_t lookup_speed(const char *s)
+{
+    static const struct speed_entry { const char *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 },
+       { "57600",  B57600 },
+       { "115200", B115200 },
+       { "230400", B230400 },
+       { NULL,     B0 }
+    };
+    const struct speed_entry *pse = speed_table;
+
+    while (pse->s && strcmp(pse->s, s))
+       pse++;
+    return pse->v;
+}
+
+static void usage(const char *prog)
+{
+    fprintf(stderr,
+           "Usage: %s [ -d78neo12 ] [ -s <speed> ] <ldisc> <device>\n", prog);
+    exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+    int tty_fd;
+    struct termios ts;
+    int  bits = 0, parity = 0, stop = 0;
+    int optc;
+    char *prog = argv[0];
+    char *dev;
+    static const struct option opttbl[] = {
+       {"speed", 1, 0, 's'},
+       {"debug", 0, 0, 'd'},
+       {0, 0, 0, 0}
+    };
+
+    /* parse options */
+    while ((optc = getopt_long(argc, argv, "d78neo12s:", 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':
+           if ((speed = lookup_speed(optarg)) == B0) {
+               fprintf(stderr, "%s: bad speed: %s\n", prog, optarg);
+               exit(EXIT_FAILURE);
+           }
+           break;
+       default:
+           usage(prog);
+       }
+    }
+
+    if (argc - optind != 2)
+       usage(prog);
+
+    /* parse line discipline specification */
+    if ((ldisc = lookup_ld(argv[optind])) < 0) {
+       char *end;
+       ldisc = strtol(argv[optind], &end, 0);
+       if (*end || ldisc < 0) {
+           fprintf(stderr, "%s: bad line discipline: %s\n", prog, optarg);
+           exit(EXIT_FAILURE);
+       }
+    }
+
+    /* open device */
+    dev = argv[optind+1];
+    if ((tty_fd = open(dev, O_RDWR|O_NOCTTY)) < 0) {
+       fprintf(stderr, "%s: cannot open %s: %s\n", prog, dev, strerror(errno));
+       exit(EXIT_FAILURE);
+    }
+    if (!isatty(tty_fd)) {
+       fprintf(stderr, "%s: %s is not a serial line\n", prog, dev);
+       exit(EXIT_FAILURE);
+    }
+
+    dbg("%s: opened %s\n", prog, dev);
+
+    /* Ensure that the device is in exclusive mode. */
+    if (ioctl(tty_fd, TIOCEXCL, 0) < 0) {
+       fprintf(stderr, "%s: cannot set %s to exclusive mode: %s\n",
+               prog, dev, strerror(errno));
+       exit(EXIT_FAILURE);
+    }
+
+    dbg("%s: exclusive mode set\n", prog);
+
+    /* set line speed and format */
+    if (tcgetattr(tty_fd, &ts) < 0) {
+       fprintf(stderr, "%s: cannot get terminal attributes for %s: %s\n",
+               prog, dev, strerror(errno));
+       exit(EXIT_FAILURE);
+    }
+    cfmakeraw(&ts);
+    if (speed != B0)
+       cfsetspeed(&ts, 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 (tcsetattr(tty_fd, TCSAFLUSH, &ts) < 0) {
+       fprintf(stderr, "%s: cannot set terminal attributes for %s: %s\n",
+               prog, dev, strerror(errno));
+       exit(EXIT_FAILURE);
+    }
+
+    dbg("%s: set to raw mode, speed 0x%x\n", prog, speed);
+
+    /* Attach the line discpline. */
+    if (ioctl(tty_fd, TIOCSETD, &ldisc) < 0) {
+       fprintf(stderr, "%s: cannot set line discipline: %s\n",
+               prog, strerror(errno));
+       exit(EXIT_FAILURE);
+    }
+
+    dbg("%s: line discipline set to %d\n", prog, ldisc);
+
+    /* Go into background if not in debug mode. */
+    if (!debug) {
+       /* Fork once to go into the background. */
+       switch (fork()) {
+       case 0:         /* child: continue */
+           break;
+       case -1:        /* failure: abort */
+           fprintf(stderr, "%s: cannot fork: %s\n", prog, strerror(errno));
+           exit(EXIT_FAILURE);
+       default:        /* parent: done */
+           exit(EXIT_SUCCESS);
+       }
+
+       /* Create new session. */
+       if (setsid() < 0) {
+           fprintf(stderr, "%s: cannot setsid: %s\n", prog, strerror(errno));
+           exit(EXIT_FAILURE);
+       }
+
+       /* Fork again to isolate from parent. */
+       switch (fork()) {
+       case 0:         /* child: continue */
+           break;
+       case -1:        /* failure: abort */
+           fprintf(stderr, "%s: cannot refork: %s\n", prog, strerror(errno));
+           exit(EXIT_FAILURE);
+       default:        /* parent: done */
+           exit(EXIT_SUCCESS);
+       }
+
+       /* Close unneeded files. */
+       chdir("/");
+       close(0);
+       close(1);
+       close(2);
+    }
+
+    /* Sleep to keep the line discipline active. */
+    pause();
+
+    exit(EXIT_SUCCESS);
+}

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to