1 | /* vi: set sw=4 ts=4: */
|
---|
2 | /*
|
---|
3 | * Stripped down version of net-tools for busybox.
|
---|
4 | *
|
---|
5 | * Author: Ignacio Garcia Perez (iggarpe at gmail dot com)
|
---|
6 | *
|
---|
7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
---|
8 | *
|
---|
9 | * There are some differences from the standard net-tools slattach:
|
---|
10 | *
|
---|
11 | * - The -l option is not supported.
|
---|
12 | *
|
---|
13 | * - The -F options allows disabling of RTS/CTS flow control.
|
---|
14 | */
|
---|
15 |
|
---|
16 | //usage:#define slattach_trivial_usage
|
---|
17 | //usage: "[-cehmLF] [-s SPEED] [-p PROTOCOL] DEVICE"
|
---|
18 | //usage:#define slattach_full_usage "\n\n"
|
---|
19 | //usage: "Attach network interface(s) to serial line(s)\n"
|
---|
20 | //usage: "\n -p PROT Set protocol (slip, cslip, slip6, clisp6 or adaptive)"
|
---|
21 | //usage: "\n -s SPD Set line speed"
|
---|
22 | //usage: "\n -e Exit after initializing device"
|
---|
23 | //usage: "\n -h Exit when the carrier is lost"
|
---|
24 | //usage: "\n -c PROG Run PROG when the line is hung up"
|
---|
25 | //usage: "\n -m Do NOT initialize the line in raw 8 bits mode"
|
---|
26 | //usage: "\n -L Enable 3-wire operation"
|
---|
27 | //usage: "\n -F Disable RTS/CTS flow control"
|
---|
28 |
|
---|
29 | #include "libbb.h"
|
---|
30 | #include "libiproute/utils.h" /* invarg() */
|
---|
31 |
|
---|
32 | struct globals {
|
---|
33 | int handle;
|
---|
34 | int saved_disc;
|
---|
35 | struct termios saved_state;
|
---|
36 | } FIX_ALIASING;
|
---|
37 | #define G (*(struct globals*)&bb_common_bufsiz1)
|
---|
38 | #define handle (G.handle )
|
---|
39 | #define saved_disc (G.saved_disc )
|
---|
40 | #define saved_state (G.saved_state )
|
---|
41 | #define INIT_G() do { } while (0)
|
---|
42 |
|
---|
43 |
|
---|
44 | /*
|
---|
45 | * Save tty state and line discipline
|
---|
46 | *
|
---|
47 | * It is fine here to bail out on errors, since we haven modified anything yet
|
---|
48 | */
|
---|
49 | static void save_state(void)
|
---|
50 | {
|
---|
51 | /* Save line status */
|
---|
52 | if (tcgetattr(handle, &saved_state) < 0)
|
---|
53 | bb_perror_msg_and_die("get state");
|
---|
54 |
|
---|
55 | /* Save line discipline */
|
---|
56 | xioctl(handle, TIOCGETD, &saved_disc);
|
---|
57 | }
|
---|
58 |
|
---|
59 | static int set_termios_state_or_warn(struct termios *state)
|
---|
60 | {
|
---|
61 | int ret;
|
---|
62 |
|
---|
63 | ret = tcsetattr(handle, TCSANOW, state);
|
---|
64 | if (ret < 0) {
|
---|
65 | bb_perror_msg("set state");
|
---|
66 | return 1; /* used as exitcode */
|
---|
67 | }
|
---|
68 | return 0;
|
---|
69 | }
|
---|
70 |
|
---|
71 | /*
|
---|
72 | * Restore state and line discipline for ALL managed ttys
|
---|
73 | *
|
---|
74 | * Restoring ALL managed ttys is the only way to have a single
|
---|
75 | * hangup delay.
|
---|
76 | *
|
---|
77 | * Go on after errors: we want to restore as many controlled ttys
|
---|
78 | * as possible.
|
---|
79 | */
|
---|
80 | static void restore_state_and_exit(int exitcode) NORETURN;
|
---|
81 | static void restore_state_and_exit(int exitcode)
|
---|
82 | {
|
---|
83 | struct termios state;
|
---|
84 |
|
---|
85 | /* Restore line discipline */
|
---|
86 | if (ioctl_or_warn(handle, TIOCSETD, &saved_disc) < 0) {
|
---|
87 | exitcode = 1;
|
---|
88 | }
|
---|
89 |
|
---|
90 | /* Hangup */
|
---|
91 | memcpy(&state, &saved_state, sizeof(state));
|
---|
92 | cfsetispeed(&state, B0);
|
---|
93 | cfsetospeed(&state, B0);
|
---|
94 | if (set_termios_state_or_warn(&state))
|
---|
95 | exitcode = 1;
|
---|
96 | sleep(1);
|
---|
97 |
|
---|
98 | /* Restore line status */
|
---|
99 | if (set_termios_state_or_warn(&saved_state))
|
---|
100 | exit(EXIT_FAILURE);
|
---|
101 | if (ENABLE_FEATURE_CLEAN_UP)
|
---|
102 | close(handle);
|
---|
103 |
|
---|
104 | exit(exitcode);
|
---|
105 | }
|
---|
106 |
|
---|
107 | /*
|
---|
108 | * Set tty state, line discipline and encapsulation
|
---|
109 | */
|
---|
110 | static void set_state(struct termios *state, int encap)
|
---|
111 | {
|
---|
112 | int disc;
|
---|
113 |
|
---|
114 | /* Set line status */
|
---|
115 | if (set_termios_state_or_warn(state))
|
---|
116 | goto bad;
|
---|
117 | /* Set line discliple (N_SLIP always) */
|
---|
118 | disc = N_SLIP;
|
---|
119 | if (ioctl_or_warn(handle, TIOCSETD, &disc) < 0) {
|
---|
120 | goto bad;
|
---|
121 | }
|
---|
122 |
|
---|
123 | /* Set encapsulation (SLIP, CSLIP, etc) */
|
---|
124 | if (ioctl_or_warn(handle, SIOCSIFENCAP, &encap) < 0) {
|
---|
125 | bad:
|
---|
126 | restore_state_and_exit(EXIT_FAILURE);
|
---|
127 | }
|
---|
128 | }
|
---|
129 |
|
---|
130 | static void sig_handler(int signo UNUSED_PARAM)
|
---|
131 | {
|
---|
132 | restore_state_and_exit(EXIT_SUCCESS);
|
---|
133 | }
|
---|
134 |
|
---|
135 | int slattach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
---|
136 | int slattach_main(int argc UNUSED_PARAM, char **argv)
|
---|
137 | {
|
---|
138 | /* Line discipline code table */
|
---|
139 | static const char proto_names[] ALIGN1 =
|
---|
140 | "slip\0" /* 0 */
|
---|
141 | "cslip\0" /* 1 */
|
---|
142 | "slip6\0" /* 2 */
|
---|
143 | "cslip6\0" /* 3 */
|
---|
144 | "adaptive\0" /* 8 */
|
---|
145 | ;
|
---|
146 |
|
---|
147 | int i, encap, opt;
|
---|
148 | struct termios state;
|
---|
149 | const char *proto = "cslip";
|
---|
150 | const char *extcmd; /* Command to execute after hangup */
|
---|
151 | const char *baud_str;
|
---|
152 | int baud_code = -1; /* Line baud rate (system code) */
|
---|
153 |
|
---|
154 | enum {
|
---|
155 | OPT_p_proto = 1 << 0,
|
---|
156 | OPT_s_baud = 1 << 1,
|
---|
157 | OPT_c_extcmd = 1 << 2,
|
---|
158 | OPT_e_quit = 1 << 3,
|
---|
159 | OPT_h_watch = 1 << 4,
|
---|
160 | OPT_m_nonraw = 1 << 5,
|
---|
161 | OPT_L_local = 1 << 6,
|
---|
162 | OPT_F_noflow = 1 << 7
|
---|
163 | };
|
---|
164 |
|
---|
165 | INIT_G();
|
---|
166 |
|
---|
167 | /* Parse command line options */
|
---|
168 | opt = getopt32(argv, "p:s:c:ehmLF", &proto, &baud_str, &extcmd);
|
---|
169 | /*argc -= optind;*/
|
---|
170 | argv += optind;
|
---|
171 |
|
---|
172 | if (!*argv)
|
---|
173 | bb_show_usage();
|
---|
174 |
|
---|
175 | encap = index_in_strings(proto_names, proto);
|
---|
176 |
|
---|
177 | if (encap < 0)
|
---|
178 | invarg(proto, "protocol");
|
---|
179 | if (encap > 3)
|
---|
180 | encap = 8;
|
---|
181 |
|
---|
182 | /* We want to know if the baud rate is valid before we start touching the ttys */
|
---|
183 | if (opt & OPT_s_baud) {
|
---|
184 | baud_code = tty_value_to_baud(xatoi(baud_str));
|
---|
185 | if (baud_code < 0)
|
---|
186 | invarg(baud_str, "baud rate");
|
---|
187 | }
|
---|
188 |
|
---|
189 | /* Trap signals in order to restore tty states upon exit */
|
---|
190 | if (!(opt & OPT_e_quit)) {
|
---|
191 | bb_signals(0
|
---|
192 | + (1 << SIGHUP)
|
---|
193 | + (1 << SIGINT)
|
---|
194 | + (1 << SIGQUIT)
|
---|
195 | + (1 << SIGTERM)
|
---|
196 | , sig_handler);
|
---|
197 | }
|
---|
198 |
|
---|
199 | /* Open tty */
|
---|
200 | handle = open(*argv, O_RDWR | O_NDELAY);
|
---|
201 | if (handle < 0) {
|
---|
202 | char *buf = concat_path_file("/dev", *argv);
|
---|
203 | handle = xopen(buf, O_RDWR | O_NDELAY);
|
---|
204 | /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */
|
---|
205 | free(buf);
|
---|
206 | }
|
---|
207 |
|
---|
208 | /* Save current tty state */
|
---|
209 | save_state();
|
---|
210 |
|
---|
211 | /* Configure tty */
|
---|
212 | memcpy(&state, &saved_state, sizeof(state));
|
---|
213 | if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */
|
---|
214 | memset(&state.c_cc, 0, sizeof(state.c_cc));
|
---|
215 | state.c_cc[VMIN] = 1;
|
---|
216 | state.c_iflag = IGNBRK | IGNPAR;
|
---|
217 | state.c_oflag = 0;
|
---|
218 | state.c_lflag = 0;
|
---|
219 | state.c_cflag = CS8 | HUPCL | CREAD
|
---|
220 | | ((opt & OPT_L_local) ? CLOCAL : 0)
|
---|
221 | | ((opt & OPT_F_noflow) ? 0 : CRTSCTS);
|
---|
222 | cfsetispeed(&state, cfgetispeed(&saved_state));
|
---|
223 | cfsetospeed(&state, cfgetospeed(&saved_state));
|
---|
224 | }
|
---|
225 |
|
---|
226 | if (opt & OPT_s_baud) {
|
---|
227 | cfsetispeed(&state, baud_code);
|
---|
228 | cfsetospeed(&state, baud_code);
|
---|
229 | }
|
---|
230 |
|
---|
231 | set_state(&state, encap);
|
---|
232 |
|
---|
233 | /* Exit now if option -e was passed */
|
---|
234 | if (opt & OPT_e_quit)
|
---|
235 | return 0;
|
---|
236 |
|
---|
237 | /* If we're not requested to watch, just keep descriptor open
|
---|
238 | * until we are killed */
|
---|
239 | if (!(opt & OPT_h_watch))
|
---|
240 | while (1)
|
---|
241 | sleep(24*60*60);
|
---|
242 |
|
---|
243 | /* Watch line for hangup */
|
---|
244 | while (1) {
|
---|
245 | if (ioctl(handle, TIOCMGET, &i) < 0 || !(i & TIOCM_CAR))
|
---|
246 | goto no_carrier;
|
---|
247 | sleep(15);
|
---|
248 | }
|
---|
249 |
|
---|
250 | no_carrier:
|
---|
251 |
|
---|
252 | /* Execute command on hangup */
|
---|
253 | if (opt & OPT_c_extcmd)
|
---|
254 | system(extcmd);
|
---|
255 |
|
---|
256 | /* Restore states and exit */
|
---|
257 | restore_state_and_exit(EXIT_SUCCESS);
|
---|
258 | }
|
---|