[1765] | 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 | *
|
---|
[2725] | 7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree.
|
---|
[1765] | 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 |
|
---|
[3232] | 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 |
|
---|
[1765] | 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;
|
---|
[2725] | 36 | } FIX_ALIASING;
|
---|
[1765] | 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 )
|
---|
[2725] | 41 | #define INIT_G() do { } while (0)
|
---|
[1765] | 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 |
|
---|
[2725] | 59 | static int set_termios_state_or_warn(struct termios *state)
|
---|
[1765] | 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 | */
|
---|
[2725] | 80 | static void restore_state_and_exit(int exitcode) NORETURN;
|
---|
[1765] | 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);
|
---|
[2725] | 94 | if (set_termios_state_or_warn(&state))
|
---|
[1765] | 95 | exitcode = 1;
|
---|
| 96 | sleep(1);
|
---|
| 97 |
|
---|
| 98 | /* Restore line status */
|
---|
[2725] | 99 | if (set_termios_state_or_warn(&saved_state))
|
---|
[1765] | 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 */
|
---|
[2725] | 115 | if (set_termios_state_or_warn(state))
|
---|
[1765] | 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:
|
---|
[2725] | 126 | restore_state_and_exit(EXIT_FAILURE);
|
---|
[1765] | 127 | }
|
---|
| 128 | }
|
---|
| 129 |
|
---|
[2725] | 130 | static void sig_handler(int signo UNUSED_PARAM)
|
---|
[1765] | 131 | {
|
---|
[2725] | 132 | restore_state_and_exit(EXIT_SUCCESS);
|
---|
[1765] | 133 | }
|
---|
| 134 |
|
---|
[2725] | 135 | int slattach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
---|
| 136 | int slattach_main(int argc UNUSED_PARAM, char **argv)
|
---|
[1765] | 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";
|
---|
[2725] | 150 | const char *extcmd; /* Command to execute after hangup */
|
---|
[1765] | 151 | const char *baud_str;
|
---|
[2725] | 152 | int baud_code = -1; /* Line baud rate (system code) */
|
---|
[1765] | 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)) {
|
---|
[2725] | 191 | bb_signals(0
|
---|
| 192 | + (1 << SIGHUP)
|
---|
| 193 | + (1 << SIGINT)
|
---|
| 194 | + (1 << SIGQUIT)
|
---|
| 195 | + (1 << SIGTERM)
|
---|
| 196 | , sig_handler);
|
---|
[1765] | 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);
|
---|
[2725] | 222 | cfsetispeed(&state, cfgetispeed(&saved_state));
|
---|
| 223 | cfsetospeed(&state, cfgetospeed(&saved_state));
|
---|
[1765] | 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 */
|
---|
[2725] | 257 | restore_state_and_exit(EXIT_SUCCESS);
|
---|
[1765] | 258 | }
|
---|