[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 <tilman@xxxxxxx> Add an ldattach(8) utility program similar to the one in OpenBSD. Signed-off-by: Tilman Schmidt <tilman@xxxxxxx> --- 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 (tilman@xxxxxxx) +.\" 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 (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 -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