]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/ldattach.c
Merge branch 'libeconf' of https://github.com/thkukuk/util-linux
[thirdparty/util-linux.git] / sys-utils / ldattach.c
CommitLineData
1e8d11c4
TS
1/* line discipline loading daemon
2 * open a serial device and attach a line discipline on it
3 *
4 * Usage:
5 * ldattach GIGASET_M101 /dev/ttyS0
6 *
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 * =====================================================================
13 */
14
28e91b83
SK
15#include <errno.h>
16#include <fcntl.h>
17#include <getopt.h>
1e8d11c4 18#include <stdio.h>
28e91b83 19#include <stdlib.h>
1e8d11c4 20#include <string.h>
1e8d11c4 21#include <sys/ioctl.h>
28e91b83
SK
22#include <sys/stat.h>
23#include <sys/types.h>
f8132752 24#include <termios.h>
1e8d11c4 25#include <unistd.h>
1e8d11c4 26
becc79d5 27#include "c.h"
8596f639 28#include "all-io.h"
fcba4577 29#include "nls.h"
7b2d3de4 30#include "strutils.h"
efb8854f 31#include "closestream.h"
fcba4577 32
8596f639
KZ
33#include <signal.h>
34#include <sys/socket.h>
35#include <linux/if.h>
36
37#include <linux/tty.h> /* for N_GSM0710 */
38
39#ifdef LINUX_GSMMUX_H
40# include <linux/gsmmux.h> /* Add by guowenxue */
41#else
42struct gsm_config
43{
44 unsigned int adaption;
45 unsigned int encapsulation;
46 unsigned int initiator;
47 unsigned int t1;
48 unsigned int t2;
49 unsigned int t3;
50 unsigned int n2;
51 unsigned int mru;
52 unsigned int mtu;
53 unsigned int k;
54 unsigned int i;
55 unsigned int unused[8]; /* Padding for expansion without
56 breaking stuff */
57};
58# define GSMIOC_GETCONF _IOR('G', 0, struct gsm_config)
59# define GSMIOC_SETCONF _IOW('G', 1, struct gsm_config)
60#endif
61
1e8d11c4 62#ifndef N_GIGASET_M101
f8132752 63# define N_GIGASET_M101 16
1e8d11c4
TS
64#endif
65
d5f36dec
TS
66#ifndef N_PPS
67# define N_PPS 18
68#endif
69
58c17460
TS
70#ifndef N_GSM0710
71# define N_GSM0710 21
72#endif
73
8596f639
KZ
74#define MAXINTROPARMLEN 32
75
f8132752
KZ
76/* attach a line discipline ioctl */
77#ifndef TIOCSETD
78# define TIOCSETD 0x5423
1e8d11c4
TS
79#endif
80
1e8d11c4
TS
81static int debug = 0;
82
7b549aff 83struct ld_table {
28e91b83
SK
84 const char *name;
85 int value;
7b549aff
KZ
86};
87
1e8d11c4 88/* currently supported line disciplines, plus some aliases */
28e91b83
SK
89static const struct ld_table ld_discs[] = {
90 { "TTY", N_TTY },
91 { "SLIP", N_SLIP },
92 { "MOUSE", N_MOUSE },
93 { "PPP", N_PPP },
94 { "STRIP", N_STRIP },
95 { "AX25", N_AX25 },
96 { "X25", N_X25 },
97 { "6PACK", N_6PACK },
98 { "R3964", N_R3964 },
99 { "IRDA", N_IRDA },
100 { "HDLC", N_HDLC },
101 { "SYNC_PPP", N_SYNC_PPP },
102 { "SYNCPPP", N_SYNC_PPP },
103 { "HCI", N_HCI },
58c17460 104 { "GIGASET_M101", N_GIGASET_M101 },
a8023b9a
SK
105 { "M101", N_GIGASET_M101 },
106 { "GIGASET", N_GIGASET_M101 },
58c17460
TS
107 { "PPS", N_PPS },
108 { "GSM0710", N_GSM0710},
8596f639 109 { NULL, 0 }
1e8d11c4
TS
110};
111
b091b880
TS
112/* known c_iflag names */
113static const struct ld_table ld_iflags[] =
114{
115 { "IGNBRK", IGNBRK },
116 { "BRKINT", BRKINT },
117 { "IGNPAR", IGNPAR },
118 { "PARMRK", PARMRK },
119 { "INPCK", INPCK },
120 { "ISTRIP", ISTRIP },
121 { "INLCR", INLCR },
122 { "IGNCR", IGNCR },
123 { "ICRNL", ICRNL },
124 { "IUCLC", IUCLC },
125 { "IXON", IXON },
126 { "IXANY", IXANY },
127 { "IXOFF", IXOFF },
128 { "IMAXBEL", IMAXBEL },
129 { "IUTF8", IUTF8 },
28e91b83 130 { NULL, 0 }
b091b880
TS
131};
132
d91757a0 133static void dbg(char *fmt, ...)
3a134012
SK
134{
135 va_list args;
136
137 if (debug == 0)
138 return;
139 fflush(NULL);
3a134012 140 va_start(args, fmt);
31f85fce
SK
141#ifdef HAVE_VWARNX
142 vwarnx(fmt, args);
143#else
144 fprintf(stderr, "%s: ", program_invocation_short_name);
3a134012 145 vfprintf(stderr, fmt, args);
3a134012 146 fprintf(stderr, "\n");
31f85fce
SK
147#endif
148 va_end(args);
3a134012 149 fflush(NULL);
3a134012
SK
150}
151
7b549aff 152static int lookup_table(const struct ld_table *tab, const char *str)
1e8d11c4 153{
28e91b83 154 const struct ld_table *t;
1e8d11c4 155
28e91b83
SK
156 for (t = tab; t && t->name; t++)
157 if (!strcasecmp(t->name, str))
158 return t->value;
159 return -1;
1e8d11c4
TS
160}
161
28e91b83 162static void print_table(FILE * out, const struct ld_table *tab)
1e8d11c4 163{
28e91b83
SK
164 const struct ld_table *t;
165 int i;
166
167 for (t = tab, i = 1; t && t->name; t++, i++) {
b5225af3
TS
168 fprintf(out, " %-12s", t->name);
169 if (!(i % 5))
28e91b83
SK
170 fputc('\n', out);
171 }
7b549aff
KZ
172}
173
b091b880
TS
174static int parse_iflag(char *str, int *set_iflag, int *clr_iflag)
175{
28e91b83 176 int iflag;
7b2d3de4 177 char *s;
28e91b83
SK
178
179 for (s = strtok(str, ","); s != NULL; s = strtok(NULL, ",")) {
180 if (*s == '-')
181 s++;
7b2d3de4 182 if ((iflag = lookup_table(ld_iflags, s)) < 0)
20a39982 183 iflag = strtos32_or_err(s, _("invalid iflag"));
28e91b83
SK
184 if (s > str && *(s - 1) == '-')
185 *clr_iflag |= iflag;
186 else
187 *set_iflag |= iflag;
b091b880 188 }
28e91b83
SK
189 dbg("iflag (set/clear): %d/%d", *set_iflag, *clr_iflag);
190 return 0;
b091b880
TS
191}
192
193
5118d1be 194static void __attribute__((__noreturn__)) usage(void)
7b549aff 195{
5118d1be 196 FILE *out = stdout;
b5b28b43 197
a8023b9a
SK
198 fputs(USAGE_HEADER, out);
199 fprintf(out, _(" %s [options] <ldisc> <device>\n"), program_invocation_short_name);
a8023b9a 200
451dbcfa
BS
201 fputs(USAGE_SEPARATOR, out);
202 fputs(_("Attach a line discipline to a serial line.\n"), out);
203
204 fputs(USAGE_OPTIONS, out);
a8023b9a
SK
205 fputs(_(" -d, --debug print verbose messages to stderr\n"), out);
206 fputs(_(" -s, --speed <value> set serial line speed\n"), out);
8596f639
KZ
207 fputs(_(" -c, --intro-command <string> intro sent before ldattach\n"), out);
208 fputs(_(" -p, --pause <seconds> pause between intro and ldattach\n"), out);
a8023b9a
SK
209 fputs(_(" -7, --sevenbits set character size to 7 bits\n"), out);
210 fputs(_(" -8, --eightbits set character size to 8 bits\n"), out);
211 fputs(_(" -n, --noparity set parity to none\n"), out);
212 fputs(_(" -e, --evenparity set parity to even\n"), out);
213 fputs(_(" -o, --oddparity set parity to odd\n"), out);
214 fputs(_(" -1, --onestopbit set stop bits to one\n"), out);
215 fputs(_(" -2, --twostopbits set stop bits to two\n"), out);
216 fputs(_(" -i, --iflag [-]<iflag> set input mode flag\n"), out);
5ff20423 217
a8023b9a 218 fputs(USAGE_SEPARATOR, out);
f45f3ec3 219 printf(USAGE_HELP_OPTIONS(25));
158e4182 220
28e91b83
SK
221 fputs(_("\nKnown <ldisc> names:\n"), out);
222 print_table(out, ld_discs);
158e4182
KZ
223 fputs(USAGE_SEPARATOR, out);
224
28e91b83
SK
225 fputs(_("\nKnown <iflag> names:\n"), out);
226 print_table(out, ld_iflags);
158e4182 227
f45f3ec3 228 printf(USAGE_MAN_TAIL("ldattach(8)"));
5118d1be 229 exit(EXIT_SUCCESS);
1e8d11c4
TS
230}
231
f8132752
KZ
232static int my_cfsetspeed(struct termios *ts, int speed)
233{
234 /* Standard speeds
235 * -- cfsetspeed() is able to translate number to Bxxx constants
236 */
237 if (cfsetspeed(ts, speed) == 0)
238 return 0;
239
240 /* Nonstandard speeds
28e91b83
SK
241 * -- we have to bypass glibc and set the speed manually (because glibc
242 * checks for speed and supports Bxxx bit rates only)...
f8132752 243 */
963413a1 244#if _HAVE_STRUCT_TERMIOS_C_ISPEED
28e91b83 245# define BOTHER 0010000 /* non standard rate */
f8132752
KZ
246 dbg("using non-standard speeds");
247 ts->c_ospeed = ts->c_ispeed = speed;
248 ts->c_cflag &= ~CBAUD;
249 ts->c_cflag |= BOTHER;
250 return 0;
251#else
252 return -1;
253#endif
254}
255
8596f639
KZ
256static void handler(int s)
257{
31f85fce 258 dbg("got SIG %i -> exiting", s);
8596f639
KZ
259 exit(EXIT_SUCCESS);
260}
261
262static void gsm0710_set_conf(int tty_fd)
263{
264 struct gsm_config c;
265
266 /* Add by guowenxue */
267 /* get n_gsm configuration */
268 ioctl(tty_fd, GSMIOC_GETCONF, &c);
269 /* we are initiator and need encoding 0 (basic) */
270 c.initiator = 1;
271 c.encapsulation = 0;
272 /* our modem defaults to a maximum size of 127 bytes */
273 c.mru = 127;
274 c.mtu = 127;
275 /* set the new configuration */
276 ioctl(tty_fd, GSMIOC_SETCONF, &c);
277 /* Add by guowenxue end*/
278}
279
1e8d11c4
TS
280int main(int argc, char **argv)
281{
28e91b83
SK
282 int tty_fd;
283 struct termios ts;
284 int speed = 0, bits = '-', parity = '-', stop = '-';
285 int set_iflag = 0, clr_iflag = 0;
286 int ldisc;
287 int optc;
28e91b83 288 char *dev;
8596f639
KZ
289 int intropause = 1;
290 char *introparm = NULL;
291
28e91b83
SK
292 static const struct option opttbl[] = {
293 {"speed", required_argument, NULL, 's'},
294 {"sevenbits", no_argument, NULL, '7'},
295 {"eightbits", no_argument, NULL, '8'},
296 {"noparity", no_argument, NULL, 'n'},
297 {"evenparity", no_argument, NULL, 'e'},
298 {"oddparity", no_argument, NULL, 'o'},
299 {"onestopbit", no_argument, NULL, '1'},
300 {"twostopbits", no_argument, NULL, '2'},
301 {"iflag", required_argument, NULL, 'i'},
302 {"help", no_argument, NULL, 'h'},
303 {"version", no_argument, NULL, 'V'},
304 {"debug", no_argument, NULL, 'd'},
8596f639
KZ
305 {"intro-command", no_argument, NULL, 'c'},
306 {"pause", no_argument, NULL, 'p'},
28e91b83
SK
307 {NULL, 0, NULL, 0}
308 };
309
8596f639
KZ
310 signal(SIGKILL, handler);
311 signal(SIGINT, handler);
312
28e91b83
SK
313 setlocale(LC_ALL, "");
314 bindtextdomain(PACKAGE, LOCALEDIR);
315 textdomain(PACKAGE);
25b7045e 316 close_stdout_atexit();
28e91b83
SK
317
318 /* parse options */
28e91b83 319 if (argc == 0)
5118d1be
RM
320 errx(EXIT_FAILURE, _("bad usage"));
321
28e91b83 322 while ((optc =
8596f639 323 getopt_long(argc, argv, "dhV78neo12s:i:c:p:", opttbl,
28e91b83
SK
324 NULL)) >= 0) {
325 switch (optc) {
326 case 'd':
3a134012 327 debug = 1;
28e91b83
SK
328 break;
329 case '1':
330 case '2':
331 stop = optc;
332 break;
333 case '7':
334 case '8':
335 bits = optc;
336 break;
337 case 'n':
338 case 'e':
339 case 'o':
340 parity = optc;
341 break;
342 case 's':
20a39982 343 speed = strtos32_or_err(optarg, _("invalid speed argument"));
28e91b83 344 break;
8596f639
KZ
345 case 'p':
346 intropause = strtou32_or_err(optarg, _("invalid pause argument"));
347 if (intropause > 10)
348 errx(EXIT_FAILURE, "invalid pause: %s", optarg);
349 break;
350 case 'c':
351 introparm = optarg;
352 break;
28e91b83
SK
353 case 'i':
354 parse_iflag(optarg, &set_iflag, &clr_iflag);
355 break;
2c308875 356
28e91b83 357 case 'V':
2c308875 358 print_version(EXIT_SUCCESS);
28e91b83 359 case 'h':
5118d1be 360 usage();
28e91b83 361 default:
677ec86c 362 errtryhelp(EXIT_FAILURE);
28e91b83
SK
363 }
364 }
365
5118d1be
RM
366 if (argc - optind != 2) {
367 warnx(_("not enough arguments"));
368 errtryhelp(EXIT_FAILURE);
369 }
28e91b83
SK
370 /* parse line discipline specification */
371 ldisc = lookup_table(ld_discs, argv[optind]);
7b2d3de4 372 if (ldisc < 0)
20a39982 373 ldisc = strtos32_or_err(argv[optind], _("invalid line discipline argument"));
28e91b83 374
5687494a
TS
375 /* ldisc specific option settings */
376 if (ldisc == N_GIGASET_M101) {
377 /* device specific defaults for line speed and data format */
158e4182
KZ
378 if (speed == 0)
379 speed = 115200;
380 if (bits == '-')
381 bits = '8';
382 if (parity == '-')
383 parity = 'n';
384 if (stop == '-')
385 stop = '1';
5687494a
TS
386 }
387
28e91b83
SK
388 /* open device */
389 dev = argv[optind + 1];
390 if ((tty_fd = open(dev, O_RDWR | O_NOCTTY)) < 0)
391 err(EXIT_FAILURE, _("cannot open %s"), dev);
392 if (!isatty(tty_fd))
393 errx(EXIT_FAILURE, _("%s is not a serial line"), dev);
394
395 dbg("opened %s", dev);
396
397 /* set line speed and format */
398 if (tcgetattr(tty_fd, &ts) < 0)
399 err(EXIT_FAILURE,
400 _("cannot get terminal attributes for %s"), dev);
401 cfmakeraw(&ts);
402 if (speed && my_cfsetspeed(&ts, speed) < 0)
403 errx(EXIT_FAILURE, _("speed %d unsupported"), speed);
404
405 switch (stop) {
1e8d11c4 406 case '1':
28e91b83
SK
407 ts.c_cflag &= ~CSTOPB;
408 break;
1e8d11c4 409 case '2':
28e91b83
SK
410 ts.c_cflag |= CSTOPB;
411 break;
ba64bbd2
SK
412 case '-':
413 break;
414 default:
415 abort();
28e91b83
SK
416 }
417 switch (bits) {
1e8d11c4 418 case '7':
28e91b83
SK
419 ts.c_cflag = (ts.c_cflag & ~CSIZE) | CS7;
420 break;
1e8d11c4 421 case '8':
28e91b83
SK
422 ts.c_cflag = (ts.c_cflag & ~CSIZE) | CS8;
423 break;
ba64bbd2
SK
424 case '-':
425 break;
426 default:
427 abort();
28e91b83
SK
428 }
429 switch (parity) {
1e8d11c4 430 case 'n':
28e91b83
SK
431 ts.c_cflag &= ~(PARENB | PARODD);
432 break;
1e8d11c4 433 case 'e':
28e91b83
SK
434 ts.c_cflag |= PARENB;
435 ts.c_cflag &= ~PARODD;
436 break;
1e8d11c4 437 case 'o':
28e91b83
SK
438 ts.c_cflag |= (PARENB | PARODD);
439 break;
ba64bbd2
SK
440 case '-':
441 break;
442 default:
443 abort();
1e8d11c4 444 }
28e91b83
SK
445
446 ts.c_cflag |= CREAD; /* just to be on the safe side */
447 ts.c_iflag |= set_iflag;
448 ts.c_iflag &= ~clr_iflag;
449
450 if (tcsetattr(tty_fd, TCSAFLUSH, &ts) < 0)
451 err(EXIT_FAILURE,
452 _("cannot set terminal attributes for %s"), dev);
453
454 dbg("set to raw %d %c%c%c: cflag=0x%x",
455 speed, bits, parity, stop, ts.c_cflag);
456
8596f639
KZ
457 if (introparm && *introparm)
458 {
459 dbg("intro command is '%s'", introparm);
460 if (write_all(tty_fd, introparm, strlen(introparm)) != 0)
461 err(EXIT_FAILURE,
462 _("cannot write intro command to %s"), dev);
463
464 if (intropause) {
465 dbg("waiting for %d seconds", intropause);
466 sleep(intropause);
467 }
468 }
469
5687494a 470 /* Attach the line discipline. */
28e91b83
SK
471 if (ioctl(tty_fd, TIOCSETD, &ldisc) < 0)
472 err(EXIT_FAILURE, _("cannot set line discipline"));
473
474 dbg("line discipline set to %d", ldisc);
475
5687494a 476 /* ldisc specific post-attach actions */
8596f639
KZ
477 if (ldisc == N_GSM0710)
478 gsm0710_set_conf(tty_fd);
479
28e91b83
SK
480 /* Go into background if not in debug mode. */
481 if (!debug && daemon(0, 0) < 0)
482 err(EXIT_FAILURE, _("cannot daemonize"));
483
484 /* Sleep to keep the line discipline active. */
485 pause();
486
487 exit(EXIT_SUCCESS);
1e8d11c4 488}