Upload Tizen:Base source
[framework/base/util-linux-ng.git] / sys-utils / ldattach.c
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
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <getopt.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include <errno.h>
24 #include <termios.h>
25 #include <unistd.h>
26 #include <err.h>
27
28 #include "nls.h"
29
30 #define dbg(format, arg...) \
31         do { if (debug) fprintf(stderr , "%s:" format "\n" , progname , ## arg); } while (0)
32
33 #ifndef N_GIGASET_M101
34 # define N_GIGASET_M101 16
35 #endif
36
37 #ifndef N_PPS
38 # define N_PPS 18
39 #endif
40
41 #ifndef ARRAY_SIZE
42 # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
43 #endif
44
45 /* attach a line discipline ioctl */
46 #ifndef TIOCSETD
47 # define TIOCSETD   0x5423
48 #endif
49
50 static const char *progname;
51 static int debug = 0;
52
53 /* currently supported line disciplines, plus some aliases */
54 static const struct ld_entry { const char *s; int v; }
55 ld_table[] = {
56         { "TTY",        N_TTY },
57         { "SLIP",       N_SLIP },
58         { "MOUSE",      N_MOUSE },
59         { "PPP",        N_PPP },
60         { "STRIP",      N_STRIP },
61         { "AX25",       N_AX25 },
62         { "X25",        N_X25 },
63         { "6PACK",      N_6PACK },
64         { "R3964",      N_R3964 },
65         { "IRDA",       N_IRDA },
66         { "HDLC",       N_HDLC },
67         { "SYNC_PPP",   N_SYNC_PPP },
68         { "SYNCPPP",    N_SYNC_PPP },
69         { "HCI",        N_HCI },
70         { "GIGASET_M101",       N_GIGASET_M101 },
71         { "GIGASET",    N_GIGASET_M101 },
72         { "M101",       N_GIGASET_M101 },
73         { "PPS",        N_PPS },
74 };
75
76 /* look up line discipline code */
77 static int lookup_ld(const char *s)
78 {
79     size_t i;
80
81     for (i = 0; i < ARRAY_SIZE(ld_table); i++)
82         if (!strcasecmp(ld_table[i].s, s))
83             return ld_table[i].v;
84     return -1;
85 }
86
87 static void __attribute__((__noreturn__)) usage(int exitcode)
88 {
89     size_t i;
90
91     fprintf(stderr,
92             _("\nUsage: %s [ -dhV78neo12 ] [ -s <speed> ] <ldisc> <device>\n"),
93             progname);
94     fputs(_("\nKnown <ldisc> names:\n"), stderr);
95     for (i = 0; i < ARRAY_SIZE(ld_table); i++)
96         fprintf(stderr, "  %s\n", ld_table[i].s);
97     exit(exitcode);
98 }
99
100 static int my_cfsetspeed(struct termios *ts, int speed)
101 {
102         /* Standard speeds
103          * -- cfsetspeed() is able to translate number to Bxxx constants
104          */
105         if (cfsetspeed(ts, speed) == 0)
106                 return 0;
107
108         /* Nonstandard speeds
109          * -- we have to bypass glibc and set the speed manually (because
110          *    glibc checks for speed and supports Bxxx bit rates only)...
111          */
112 #ifdef _HAVE_STRUCT_TERMIOS_C_ISPEED
113 # define BOTHER 0010000               /* non standard rate */
114         dbg("using non-standard speeds");
115         ts->c_ospeed = ts->c_ispeed = speed;
116         ts->c_cflag &= ~CBAUD;
117         ts->c_cflag |= BOTHER;
118         return 0;
119 #else
120         return -1;
121 #endif
122 }
123
124 int main(int argc, char **argv)
125 {
126     int tty_fd;
127     struct termios ts;
128     int speed = 0, bits = '-', parity = '-', stop = '-';
129     int ldisc;
130     int optc;
131     char *end;
132     char *dev;
133     static const struct option opttbl[] = {
134         {"speed", 1, 0, 's'},
135         {"sevenbits", 0, 0, '7'},
136         {"eightbits", 0, 0, '8'},
137         {"noparity", 0, 0, 'n'},
138         {"evenparity", 0, 0, 'e'},
139         {"oddparity", 0, 0, 'o'},
140         {"onestopbit", 0, 0, '1'},
141         {"twostopbits", 0, 0, '2'},
142         {"help", 0, 0, 'h'},
143         {"version", 0, 0, 'V'},
144         {"debug", 0, 0, 'd'},
145         {0, 0, 0, 0}
146     };
147
148
149     setlocale(LC_ALL, "");
150     bindtextdomain(PACKAGE, LOCALEDIR);
151     textdomain(PACKAGE);
152
153     /* parse options */
154     progname = program_invocation_short_name;
155
156     if (argc == 0)
157         usage(EXIT_SUCCESS);
158     while ((optc = getopt_long(argc, argv, "dhV78neo12s:", opttbl, NULL)) >= 0) {
159         switch (optc) {
160         case 'd':
161             debug++;
162             break;
163         case '1':
164         case '2':
165             stop = optc;
166             break;
167         case '7':
168         case '8':
169             bits = optc;
170             break;
171         case 'n':
172         case 'e':
173         case 'o':
174             parity = optc;
175             break;
176         case 's':
177             speed = strtol(optarg, &end, 10);
178             if (*end || speed <= 0)
179                 errx(EXIT_FAILURE, _("invalid speed: %s"), optarg);
180             break;
181         case 'V':
182             printf(_("ldattach from %s\n"), PACKAGE_STRING);
183             break;
184         case 'h':
185             usage(EXIT_SUCCESS);
186         default:
187             warnx(_("invalid option"));
188             usage(EXIT_FAILURE);
189         }
190     }
191
192     if (argc - optind != 2)
193         usage(EXIT_FAILURE);
194
195     /* parse line discipline specification */
196     if ((ldisc = lookup_ld(argv[optind])) < 0) {
197         ldisc = strtol(argv[optind], &end, 0);
198         if (*end || ldisc < 0)
199             errx(EXIT_FAILURE, _("invalid line discipline: %s"), argv[optind]);
200     }
201
202     /* open device */
203     dev = argv[optind+1];
204     if ((tty_fd = open(dev, O_RDWR|O_NOCTTY)) < 0)
205         err(EXIT_FAILURE, _("cannot open %s"), dev);
206     if (!isatty(tty_fd))
207         errx(EXIT_FAILURE, _("%s is not a serial line"), dev);
208
209     dbg("opened %s", dev);
210
211     /* set line speed and format */
212     if (tcgetattr(tty_fd, &ts) < 0)
213         err(EXIT_FAILURE, _("cannot get terminal attributes for %s"), dev);
214     cfmakeraw(&ts);
215     if (speed && my_cfsetspeed(&ts, speed) < 0)
216         errx(EXIT_FAILURE, _("speed %d unsupported"), speed);
217     switch (stop) {
218     case '1':
219         ts.c_cflag &= ~CSTOPB;
220         break;
221     case '2':
222         ts.c_cflag |= CSTOPB;
223         break;
224     }
225     switch (bits) {
226     case '7':
227         ts.c_cflag = (ts.c_cflag & ~CSIZE) | CS7;
228         break;
229     case '8':
230         ts.c_cflag = (ts.c_cflag & ~CSIZE) | CS8;
231         break;
232     }
233     switch (parity) {
234     case 'n':
235         ts.c_cflag &= ~(PARENB|PARODD);
236         break;
237     case 'e':
238         ts.c_cflag |= PARENB;
239         ts.c_cflag &= ~PARODD;
240         break;
241     case 'o':
242         ts.c_cflag |= (PARENB|PARODD);
243         break;
244     }
245     ts.c_cflag |= CREAD;        /* just to be on the safe side */
246     if (tcsetattr(tty_fd, TCSAFLUSH, &ts) < 0)
247         err(EXIT_FAILURE, _("cannot set terminal attributes for %s"), dev);
248
249     dbg("set to raw %d %c%c%c: cflag=0x%x",
250         speed, bits, parity, stop, ts.c_cflag);
251
252     /* Attach the line discpline. */
253     if (ioctl(tty_fd, TIOCSETD, &ldisc) < 0)
254         err(EXIT_FAILURE, _("cannot set line discipline"));
255
256     dbg("line discipline set to %d", ldisc);
257
258     /* Go into background if not in debug mode. */
259     if (!debug && daemon(0, 0) < 0)
260         err(EXIT_FAILURE, _("cannot daemonize"));
261
262     /* Sleep to keep the line discipline active. */
263     pause();
264
265     exit(EXIT_SUCCESS);
266 }