1 /* line discipline loading daemon
2 * open a serial device and attach a line discipline on it
5 * ldattach GIGASET_M101 /dev/ttyS0
7 * =====================================================================
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 * =====================================================================
21 #include <sys/ioctl.h>
23 #include <sys/types.h>
30 #include "closestream.h"
32 #ifndef N_GIGASET_M101
33 # define N_GIGASET_M101 16
40 /* attach a line discipline ioctl */
42 # define TIOCSETD 0x5423
52 /* currently supported line disciplines, plus some aliases */
53 static const struct ld_table ld_discs
[] = {
65 { "SYNC_PPP", N_SYNC_PPP
},
66 { "SYNCPPP", N_SYNC_PPP
},
69 { "M101", N_GIGASET_M101
},
70 { "GIGASET", N_GIGASET_M101
},
71 { "GIGASET_M101", N_GIGASET_M101
},
75 /* known c_iflag names */
76 static const struct ld_table ld_iflags
[] =
91 { "IMAXBEL", IMAXBEL
},
96 static void dbg(char *fmt
, ...)
103 fprintf(stderr
, "%s: ", program_invocation_short_name
);
105 vfprintf(stderr
, fmt
, args
);
107 fprintf(stderr
, "\n");
112 static int lookup_table(const struct ld_table
*tab
, const char *str
)
114 const struct ld_table
*t
;
116 for (t
= tab
; t
&& t
->name
; t
++)
117 if (!strcasecmp(t
->name
, str
))
122 static void print_table(FILE * out
, const struct ld_table
*tab
)
124 const struct ld_table
*t
;
127 for (t
= tab
, i
= 1; t
&& t
->name
; t
++, i
++) {
128 fprintf(out
, " %-10s", t
->name
);
134 static int parse_iflag(char *str
, int *set_iflag
, int *clr_iflag
)
139 for (s
= strtok(str
, ","); s
!= NULL
; s
= strtok(NULL
, ",")) {
142 if ((iflag
= lookup_table(ld_iflags
, s
)) < 0)
143 iflag
= strtos32_or_err(s
, _("invalid iflag"));
144 if (s
> str
&& *(s
- 1) == '-')
149 dbg("iflag (set/clear): %d/%d", *set_iflag
, *clr_iflag
);
154 static void __attribute__ ((__noreturn__
)) usage(int exitcode
)
156 FILE *out
= exitcode
== EXIT_SUCCESS
? stdout
: stderr
;
158 fputs(USAGE_HEADER
, out
);
159 fprintf(out
, _(" %s [options] <ldisc> <device>\n"), program_invocation_short_name
);
160 fputs(USAGE_OPTIONS
, out
);
162 fputs(_(" -d, --debug print verbose messages to stderr\n"), out
);
163 fputs(_(" -s, --speed <value> set serial line speed\n"), out
);
164 fputs(_(" -7, --sevenbits set character size to 7 bits\n"), out
);
165 fputs(_(" -8, --eightbits set character size to 8 bits\n"), out
);
166 fputs(_(" -n, --noparity set parity to none\n"), out
);
167 fputs(_(" -e, --evenparity set parity to even\n"), out
);
168 fputs(_(" -o, --oddparity set parity to odd\n"), out
);
169 fputs(_(" -1, --onestopbit set stop bits to one\n"), out
);
170 fputs(_(" -2, --twostopbits set stop bits to two\n"), out
);
171 fputs(_(" -i, --iflag [-]<iflag> set input mode flag\n"), out
);
173 fputs(USAGE_SEPARATOR
, out
);
174 fputs(USAGE_HELP
, out
);
175 fputs(USAGE_VERSION
, out
);
176 fputs(_("\nKnown <ldisc> names:\n"), out
);
177 print_table(out
, ld_discs
);
178 fputs(_("\nKnown <iflag> names:\n"), out
);
179 print_table(out
, ld_iflags
);
181 fprintf(out
, USAGE_MAN_TAIL("ldattach(8)"));
185 static int my_cfsetspeed(struct termios
*ts
, int speed
)
188 * -- cfsetspeed() is able to translate number to Bxxx constants
190 if (cfsetspeed(ts
, speed
) == 0)
193 /* Nonstandard speeds
194 * -- we have to bypass glibc and set the speed manually (because glibc
195 * checks for speed and supports Bxxx bit rates only)...
197 #ifdef _HAVE_STRUCT_TERMIOS_C_ISPEED
198 # define BOTHER 0010000 /* non standard rate */
199 dbg("using non-standard speeds");
200 ts
->c_ospeed
= ts
->c_ispeed
= speed
;
201 ts
->c_cflag
&= ~CBAUD
;
202 ts
->c_cflag
|= BOTHER
;
209 int main(int argc
, char **argv
)
213 int speed
= 0, bits
= '-', parity
= '-', stop
= '-';
214 int set_iflag
= 0, clr_iflag
= 0;
218 static const struct option opttbl
[] = {
219 {"speed", required_argument
, NULL
, 's'},
220 {"sevenbits", no_argument
, NULL
, '7'},
221 {"eightbits", no_argument
, NULL
, '8'},
222 {"noparity", no_argument
, NULL
, 'n'},
223 {"evenparity", no_argument
, NULL
, 'e'},
224 {"oddparity", no_argument
, NULL
, 'o'},
225 {"onestopbit", no_argument
, NULL
, '1'},
226 {"twostopbits", no_argument
, NULL
, '2'},
227 {"iflag", required_argument
, NULL
, 'i'},
228 {"help", no_argument
, NULL
, 'h'},
229 {"version", no_argument
, NULL
, 'V'},
230 {"debug", no_argument
, NULL
, 'd'},
234 setlocale(LC_ALL
, "");
235 bindtextdomain(PACKAGE
, LOCALEDIR
);
237 atexit(close_stdout
);
243 getopt_long(argc
, argv
, "dhV78neo12s:i:", opttbl
,
263 speed
= strtos32_or_err(optarg
, _("invalid speed argument"));
266 parse_iflag(optarg
, &set_iflag
, &clr_iflag
);
269 printf(UTIL_LINUX_VERSION
);
274 warnx(_("invalid option"));
279 if (argc
- optind
!= 2)
282 /* parse line discipline specification */
283 ldisc
= lookup_table(ld_discs
, argv
[optind
]);
285 ldisc
= strtos32_or_err(argv
[optind
], _("invalid line discipline argument"));
288 dev
= argv
[optind
+ 1];
289 if ((tty_fd
= open(dev
, O_RDWR
| O_NOCTTY
)) < 0)
290 err(EXIT_FAILURE
, _("cannot open %s"), dev
);
292 errx(EXIT_FAILURE
, _("%s is not a serial line"), dev
);
294 dbg("opened %s", dev
);
296 /* set line speed and format */
297 if (tcgetattr(tty_fd
, &ts
) < 0)
299 _("cannot get terminal attributes for %s"), dev
);
301 if (speed
&& my_cfsetspeed(&ts
, speed
) < 0)
302 errx(EXIT_FAILURE
, _("speed %d unsupported"), speed
);
306 ts
.c_cflag
&= ~CSTOPB
;
309 ts
.c_cflag
|= CSTOPB
;
318 ts
.c_cflag
= (ts
.c_cflag
& ~CSIZE
) | CS7
;
321 ts
.c_cflag
= (ts
.c_cflag
& ~CSIZE
) | CS8
;
330 ts
.c_cflag
&= ~(PARENB
| PARODD
);
333 ts
.c_cflag
|= PARENB
;
334 ts
.c_cflag
&= ~PARODD
;
337 ts
.c_cflag
|= (PARENB
| PARODD
);
345 ts
.c_cflag
|= CREAD
; /* just to be on the safe side */
346 ts
.c_iflag
|= set_iflag
;
347 ts
.c_iflag
&= ~clr_iflag
;
349 if (tcsetattr(tty_fd
, TCSAFLUSH
, &ts
) < 0)
351 _("cannot set terminal attributes for %s"), dev
);
353 dbg("set to raw %d %c%c%c: cflag=0x%x",
354 speed
, bits
, parity
, stop
, ts
.c_cflag
);
356 /* Attach the line discpline. */
357 if (ioctl(tty_fd
, TIOCSETD
, &ldisc
) < 0)
358 err(EXIT_FAILURE
, _("cannot set line discipline"));
360 dbg("line discipline set to %d", ldisc
);
362 /* Go into background if not in debug mode. */
363 if (!debug
&& daemon(0, 0) < 0)
364 err(EXIT_FAILURE
, _("cannot daemonize"));
366 /* Sleep to keep the line discipline active. */