Contents of /tags/mkinitrd-6_1_0/busybox/networking/slattach.c
Parent Directory | Revision Log
Revision 820 -
(show annotations)
(download)
Fri Apr 24 19:09:57 2009 UTC (15 years, 5 months ago) by niro
File MIME type: text/plain
File size: 5606 byte(s)
Fri Apr 24 19:09:57 2009 UTC (15 years, 5 months ago) by niro
File MIME type: text/plain
File size: 5606 byte(s)
tagged 'mkinitrd-6_1_0'
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_or_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) 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_or_warn(&state)) |
82 | exitcode = 1; |
83 | sleep(1); |
84 | |
85 | /* Restore line status */ |
86 | if (set_termios_state_or_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_or_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(EXIT_FAILURE); |
114 | } |
115 | } |
116 | |
117 | static void sig_handler(int signo UNUSED_PARAM) |
118 | { |
119 | restore_state_and_exit(EXIT_SUCCESS); |
120 | } |
121 | |
122 | int slattach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
123 | int slattach_main(int argc UNUSED_PARAM, 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 | bb_signals(0 |
179 | + (1 << SIGHUP) |
180 | + (1 << SIGINT) |
181 | + (1 << SIGQUIT) |
182 | + (1 << SIGTERM) |
183 | , sig_handler); |
184 | } |
185 | |
186 | /* Open tty */ |
187 | handle = open(*argv, O_RDWR | O_NDELAY); |
188 | if (handle < 0) { |
189 | char *buf = concat_path_file("/dev", *argv); |
190 | handle = xopen(buf, O_RDWR | O_NDELAY); |
191 | /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */ |
192 | free(buf); |
193 | } |
194 | |
195 | /* Save current tty state */ |
196 | save_state(); |
197 | |
198 | /* Configure tty */ |
199 | memcpy(&state, &saved_state, sizeof(state)); |
200 | if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */ |
201 | memset(&state.c_cc, 0, sizeof(state.c_cc)); |
202 | state.c_cc[VMIN] = 1; |
203 | state.c_iflag = IGNBRK | IGNPAR; |
204 | state.c_oflag = 0; |
205 | state.c_lflag = 0; |
206 | state.c_cflag = CS8 | HUPCL | CREAD |
207 | | ((opt & OPT_L_local) ? CLOCAL : 0) |
208 | | ((opt & OPT_F_noflow) ? 0 : CRTSCTS); |
209 | cfsetispeed(&state, cfgetispeed(&saved_state)); |
210 | cfsetospeed(&state, cfgetospeed(&saved_state)); |
211 | } |
212 | |
213 | if (opt & OPT_s_baud) { |
214 | cfsetispeed(&state, baud_code); |
215 | cfsetospeed(&state, baud_code); |
216 | } |
217 | |
218 | set_state(&state, encap); |
219 | |
220 | /* Exit now if option -e was passed */ |
221 | if (opt & OPT_e_quit) |
222 | return 0; |
223 | |
224 | /* If we're not requested to watch, just keep descriptor open |
225 | * until we are killed */ |
226 | if (!(opt & OPT_h_watch)) |
227 | while (1) |
228 | sleep(24*60*60); |
229 | |
230 | /* Watch line for hangup */ |
231 | while (1) { |
232 | if (ioctl(handle, TIOCMGET, &i) < 0 || !(i & TIOCM_CAR)) |
233 | goto no_carrier; |
234 | sleep(15); |
235 | } |
236 | |
237 | no_carrier: |
238 | |
239 | /* Execute command on hangup */ |
240 | if (opt & OPT_c_extcmd) |
241 | system(extcmd); |
242 | |
243 | /* Restore states and exit */ |
244 | restore_state_and_exit(EXIT_SUCCESS); |
245 | } |