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