]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - sys-utils/ldattach.c
sys-utils: cleanup license lines, add SPDX
[thirdparty/util-linux.git] / sys-utils / ldattach.c
index 99037d62bfb1121f60de087ba1bf9fa15414ae4f..2a24b3d6f414622c58972da9e5df25752b16258a 100644 (file)
-/* line discipline loading daemon
- * open a serial device and attach a line discipline on it
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
  *
- * 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.
  *
- * =====================================================================
- * 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.
- * =====================================================================
+ * Line discipline loading daemon open a serial device and attach a line
+ * discipline on it.
  */
-
-#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
 #include <stdio.h>
+#include <stdlib.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 <sys/stat.h>
+#include <sys/types.h>
+#include <termios.h>
 #include <unistd.h>
-#include <err.h>
 
-#define dbg(format, arg...) \
-       do { if (debug) fprintf(stderr , "%s:" format "\n" , progname , ## arg); } while (0)
+#include "c.h"
+#include "all-io.h"
+#include "nls.h"
+#include "strutils.h"
+#include "closestream.h"
+
+#include <signal.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+
+#include <linux/tty.h>         /* for N_GSM0710 */
+
+#ifdef LINUX_GSMMUX_H
+# include <linux/gsmmux.h>     /* Add by guowenxue */
+#else
+struct gsm_config
+{
+       unsigned int adaption;
+       unsigned int encapsulation;
+       unsigned int initiator;
+       unsigned int t1;
+       unsigned int t2;
+       unsigned int t3;
+       unsigned int n2;
+       unsigned int mru;
+       unsigned int mtu;
+       unsigned int k;
+       unsigned int i;
+       unsigned int unused[8];         /* Padding for expansion without
+                                          breaking stuff */
+};
+# define GSMIOC_GETCONF                _IOR('G', 0, struct gsm_config)
+# define GSMIOC_SETCONF                _IOW('G', 1, struct gsm_config)
+#endif
 
 #ifndef N_GIGASET_M101
-#define N_GIGASET_M101 16
+# define N_GIGASET_M101 16
 #endif
 
-#ifndef PACKAGE_STRING
-#define PACKAGE_STRING "me"
+#ifndef N_PPS
+# define N_PPS 18
 #endif
 
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#ifndef N_GSM0710
+# define N_GSM0710 21
+#endif
+
+#define MAXINTROPARMLEN 32
+
+/* attach a line discipline ioctl */
+#ifndef TIOCSETD
+# define TIOCSETD   0x5423
 #endif
 
-static const char *progname;
 static int debug = 0;
 
+struct ld_table {
+       const char *name;
+       int value;
+};
+
 /* 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 },
+static const struct ld_table ld_discs[] = {
+       { "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 }
+       { "M101",               N_GIGASET_M101 },
+       { "GIGASET",            N_GIGASET_M101 },
+       { "PPS",                N_PPS },
+       { "GSM0710",            N_GSM0710},
+       { NULL, 0 }
 };
 
-/* look up line discipline code */
-static int lookup_ld(const char *s)
+/* known c_iflag names */
+static const struct ld_table ld_iflags[] =
 {
-    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 */
+       { "IGNBRK",     IGNBRK },
+       { "BRKINT",     BRKINT },
+       { "IGNPAR",     IGNPAR },
+       { "PARMRK",     PARMRK },
+       { "INPCK",      INPCK },
+       { "ISTRIP",     ISTRIP },
+       { "INLCR",      INLCR },
+       { "IGNCR",      IGNCR },
+       { "ICRNL",      ICRNL },
+       { "IUCLC",      IUCLC },
+       { "IXON",       IXON },
+       { "IXANY",      IXANY },
+       { "IXOFF",      IXOFF },
+       { "IMAXBEL",    IMAXBEL },
+       { "IUTF8",      IUTF8 },
+       { NULL,         0 }
+};
 
-/* 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
+static void __attribute__((__format__ (__printf__, 1, 2)))
+       dbg(char *fmt, ...)
+{
+       va_list args;
+
+       if (debug == 0)
+               return;
+       fflush(NULL);
+       va_start(args, fmt);
+#ifdef HAVE_VWARNX
+       vwarnx(fmt, args);
+#else
+       fprintf(stderr, "%s: ", program_invocation_short_name);
+       vfprintf(stderr, fmt, args);
+       fprintf(stderr, "\n");
 #endif
+       va_end(args);
+       fflush(NULL);
+}
 
-static int tcgetattr2(int fd, struct termios2 *pts)
+static int lookup_table(const struct ld_table *tab, const char *str)
 {
-    return ioctl(fd, TCGETS2, pts);
+       const struct ld_table *t;
+
+       for (t = tab; t && t->name; t++)
+               if (!strcasecmp(t->name, str))
+                       return t->value;
+       return -1;
 }
 
-static int tcsetattr2(int fd, int option, const struct termios2 *pts)
+static void print_table(FILE * out, const struct ld_table *tab)
 {
-    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);
+       const struct ld_table *t;
+       int i;
+
+       for (t = tab, i = 1; t && t->name; t++, i++) {
+               fprintf(out, "  %-12s", t->name);
+               if (!(i % 5))
+                       fputc('\n', out);
+       }
 }
 
-static void cfmakeraw2(struct termios2 *pts)
+static int parse_iflag(char *str, int *set_iflag, int *clr_iflag)
 {
-    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;
+       int iflag;
+       char *s;
+
+       for (s = strtok(str, ","); s != NULL; s = strtok(NULL, ",")) {
+               if (*s == '-')
+                       s++;
+               if ((iflag = lookup_table(ld_iflags, s)) < 0)
+                       iflag = strtos32_or_err(s, _("invalid iflag"));
+               if (s > str && *(s - 1) == '-')
+                       *clr_iflag |= iflag;
+               else
+                       *set_iflag |= iflag;
+       }
+       dbg("iflag (set/clear): %d/%d", *set_iflag, *clr_iflag);
+       return 0;
 }
 
-/* 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)
+static void __attribute__((__noreturn__)) usage(void)
 {
-    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;
-       }
+       FILE *out = stdout;
+
+       fputs(USAGE_HEADER, out);
+       fprintf(out, _(" %s [options] <ldisc> <device>\n"), program_invocation_short_name);
+
+       fputs(USAGE_SEPARATOR, out);
+       fputs(_("Attach a line discipline to a serial line.\n"), out);
+
+       fputs(USAGE_OPTIONS, out);
+       fputs(_(" -d, --debug             print verbose messages to stderr\n"), out);
+       fputs(_(" -s, --speed <value>     set serial line speed\n"), out);
+       fputs(_(" -c, --intro-command <string> intro sent before ldattach\n"), out);
+       fputs(_(" -p, --pause <seconds>   pause between intro and ldattach\n"), out);
+       fputs(_(" -7, --sevenbits         set character size to 7 bits\n"), out);
+       fputs(_(" -8, --eightbits         set character size to 8 bits\n"), out);
+       fputs(_(" -n, --noparity          set parity to none\n"), out);
+       fputs(_(" -e, --evenparity        set parity to even\n"), out);
+       fputs(_(" -o, --oddparity         set parity to odd\n"), out);
+       fputs(_(" -1, --onestopbit        set stop bits to one\n"), out);
+       fputs(_(" -2, --twostopbits       set stop bits to two\n"), out);
+       fputs(_(" -i, --iflag [-]<iflag>  set input mode flag\n"), out);
+
+       fputs(USAGE_SEPARATOR, out);
+       fprintf(out, USAGE_HELP_OPTIONS(25));
+
+       fputs(_("\nKnown <ldisc> names:\n"), out);
+       print_table(out, ld_discs);
+       fputs(USAGE_SEPARATOR, out);
+
+       fputs(_("\nKnown <iflag> names:\n"), out);
+       print_table(out, ld_iflags);
+
+       fprintf(out, USAGE_MAN_TAIL("ldattach(8)"));
+       exit(EXIT_SUCCESS);
+}
 
-#ifdef BOTHER
-    /* new method available */
-    pts->c_ospeed = pts->c_ispeed = speed;
-    pts->c_cflag &= ~CBAUD;
-    pts->c_cflag |= BOTHER;
-    return 0;
+static int my_cfsetspeed(struct termios *ts, int speed)
+{
+       /* Standard speeds
+        * -- cfsetspeed() is able to translate number to Bxxx constants
+        */
+       if (cfsetspeed(ts, speed) == 0)
+               return 0;
+
+       /* Nonstandard speeds
+        * -- we have to bypass glibc and set the speed manually (because glibc
+        *    checks for speed and supports Bxxx bit rates only)...
+        */
+#if _HAVE_STRUCT_TERMIOS_C_ISPEED
+# define BOTHER 0010000                /* non standard rate */
+       dbg("using non-standard speeds");
+       ts->c_ospeed = ts->c_ispeed = speed;
+       ts->c_cflag &= ~CBAUD;
+       ts->c_cflag |= BOTHER;
+       return 0;
 #else
-    /* new method not available */
-    return -1;
+       return -1;
 #endif
 }
 
-static void __attribute__((__noreturn__)) usage(int exitcode)
+static void handler(int s)
 {
-    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);
+       dbg("got SIG %i -> exiting", s);
+       _exit(EXIT_SUCCESS);
+}
+
+static void gsm0710_set_conf(int tty_fd)
+{
+       struct gsm_config c;
+
+       /* Add by guowenxue */
+       /*  get n_gsm configuration */
+       ioctl(tty_fd, GSMIOC_GETCONF, &c);
+       /*  we are initiator and need encoding 0 (basic) */
+       c.initiator = 1;
+       c.encapsulation = 0;
+       /*  our modem defaults to a maximum size of 127 bytes */
+       c.mru = 127;
+       c.mtu = 127;
+       /*  set the new configuration */
+       ioctl(tty_fd, GSMIOC_SETCONF, &c);
+       /* Add by guowenxue end*/
 }
 
 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;
+       int tty_fd;
+       struct termios ts;
+       int speed = 0, bits = '-', parity = '-', stop = '-';
+       int set_iflag = 0, clr_iflag = 0;
+       int ldisc;
+       int optc;
+       char *dev;
+       int intropause = 1;
+       char *introparm = NULL;
+
+       static const struct option opttbl[] = {
+               {"speed", required_argument, NULL, 's'},
+               {"sevenbits", no_argument, NULL, '7'},
+               {"eightbits", no_argument, NULL, '8'},
+               {"noparity", no_argument, NULL, 'n'},
+               {"evenparity", no_argument, NULL, 'e'},
+               {"oddparity", no_argument, NULL, 'o'},
+               {"onestopbit", no_argument, NULL, '1'},
+               {"twostopbits", no_argument, NULL, '2'},
+               {"iflag", required_argument, NULL, 'i'},
+               {"help", no_argument, NULL, 'h'},
+               {"version", no_argument, NULL, 'V'},
+               {"debug", no_argument, NULL, 'd'},
+               {"intro-command", required_argument, NULL, 'c'},
+               {"pause", required_argument, NULL, 'p'},
+               {NULL, 0, NULL, 0}
+       };
+
+       signal(SIGKILL, handler);
+       signal(SIGINT, handler);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+       close_stdout_atexit();
+
+       /* parse options */
+       if (argc == 0)
+               errx(EXIT_FAILURE, _("bad usage"));
+
+       while ((optc =
+               getopt_long(argc, argv, "dhV78neo12s:i:c:p:", opttbl,
+                           NULL)) >= 0) {
+               switch (optc) {
+               case 'd':
+                       debug = 1;
+                       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 = strtos32_or_err(optarg, _("invalid speed argument"));
+                       break;
+               case 'p':
+                       intropause = strtou32_or_err(optarg, _("invalid pause argument"));
+                       if (intropause > 10)
+                               errx(EXIT_FAILURE, "invalid pause: %s", optarg);
+                       break;
+               case 'c':
+                       introparm = optarg;
+                       break;
+               case 'i':
+                       parse_iflag(optarg, &set_iflag, &clr_iflag);
+                       break;
+
+               case 'V':
+                       print_version(EXIT_SUCCESS);
+               case 'h':
+                       usage();
+               default:
+                       errtryhelp(EXIT_FAILURE);
+               }
+       }
+
+       if (argc - optind != 2) {
+               warnx(_("not enough arguments"));
+               errtryhelp(EXIT_FAILURE);
+       }
+       /* parse line discipline specification */
+       ldisc = lookup_table(ld_discs, argv[optind]);
+       if (ldisc < 0)
+               ldisc = strtos32_or_err(argv[optind], _("invalid line discipline argument"));
+
+       /* ldisc specific option settings */
+       if (ldisc == N_GIGASET_M101) {
+               /* device specific defaults for line speed and data format */
+               if (speed == 0)
+                       speed = 115200;
+               if (bits == '-')
+                       bits = '8';
+               if (parity == '-')
+                       parity = 'n';
+               if (stop == '-')
+                       stop = '1';
+       }
+
+       /* 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 (tcgetattr(tty_fd, &ts) < 0)
+               err(EXIT_FAILURE,
+                   _("cannot get terminal attributes for %s"), dev);
+       cfmakeraw(&ts);
+       if (speed && my_cfsetspeed(&ts, speed) < 0)
+               errx(EXIT_FAILURE, _("speed %d unsupported"), speed);
+
+       switch (stop) {
        case '1':
+               ts.c_cflag &= ~CSTOPB;
+               break;
        case '2':
-           stop = optc;
-           break;
+               ts.c_cflag |= CSTOPB;
+               break;
+       case '-':
+               break;
+       default:
+               abort();
+       }
+       switch (bits) {
        case '7':
+               ts.c_cflag = (ts.c_cflag & ~CSIZE) | CS7;
+               break;
        case '8':
-           bits = optc;
-           break;
+               ts.c_cflag = (ts.c_cflag & ~CSIZE) | CS8;
+               break;
+       case '-':
+               break;
+       default:
+               abort();
+       }
+       switch (parity) {
        case 'n':
+               ts.c_cflag &= ~(PARENB | PARODD);
+               break;
        case 'e':
+               ts.c_cflag |= PARENB;
+               ts.c_cflag &= ~PARODD;
+               break;
        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);
+               ts.c_cflag |= (PARENB | PARODD);
+               break;
+       case '-':
+               break;
        default:
-           warnx("invalid option");
-           usage(EXIT_FAILURE);
+               abort();
+       }
+
+       ts.c_cflag |= CREAD;    /* just to be on the safe side */
+       ts.c_iflag |= set_iflag;
+       ts.c_iflag &= ~clr_iflag;
+
+       if (tcsetattr(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);
+
+       if (introparm && *introparm)
+       {
+               dbg("intro command is '%s'", introparm);
+               if (write_all(tty_fd, introparm, strlen(introparm)) != 0)
+                       err(EXIT_FAILURE,
+                           _("cannot write intro command to %s"), dev);
+
+               if (intropause) {
+                       dbg("waiting for %d seconds", intropause);
+                       sleep(intropause);
+               }
        }
-    }
-
-    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);
+
+       /* Attach the line discipline. */
+       if (ioctl(tty_fd, TIOCSETD, &ldisc) < 0)
+               err(EXIT_FAILURE, _("cannot set line discipline"));
+
+       dbg("line discipline set to %d", ldisc);
+
+       /* ldisc specific post-attach actions */
+       if (ldisc == N_GSM0710)
+               gsm0710_set_conf(tty_fd);
+
+       /* 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);
 }