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