diff options
Diffstat (limited to 'networking/slattach.c')
-rw-r--r-- | networking/slattach.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/networking/slattach.c b/networking/slattach.c new file mode 100644 index 0000000..1c00fdd --- /dev/null +++ b/networking/slattach.c @@ -0,0 +1,240 @@ +/* + * Stripped down version of net-tools for busybox. + * + * Author: Ignacio Garcia Perez (iggarpe at gmail dot com) + * + * License: GPLv2 or later, see LICENSE file in this tarball. + * + * There are some differences from the standard net-tools slattach: + * + * - The -l option is not supported. + * + * - The -F options allows disabling of RTS/CTS flow control. + */ + +#include "libbb.h" + +/* Line discipline code table */ +static const char *const proto_names[] = { + "slip", /* 0 */ + "cslip", /* 1 */ + "slip6", /* 2 */ + "cslip6", /* 3 */ + "adaptive", /* 8 */ + NULL +}; + +struct globals { + int handle; + int saved_disc; + struct termios saved_state; +}; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define handle (G.handle ) +#define saved_disc (G.saved_disc ) +#define saved_state (G.saved_state ) +#define INIT_G() do {} while (0) + + +/* + * Save tty state and line discipline + * + * It is fine here to bail out on errors, since we haven modified anything yet + */ +static void save_state(void) +{ + /* Save line status */ + if (tcgetattr(handle, &saved_state) < 0) + bb_perror_msg_and_die("get state"); + + /* Save line discipline */ + if (ioctl(handle, TIOCGETD, &saved_disc) < 0) + bb_perror_msg_and_die("get discipline"); +} + +/* + * Restore state and line discipline for ALL managed ttys + * + * Restoring ALL managed ttys is the only way to have a single + * hangup delay. + * + * Go on after errors: we want to restore as many controlled ttys + * as possible. + */ +static void restore_state_and_exit(int exitcode) ATTRIBUTE_NORETURN; +static void restore_state_and_exit(int exitcode) +{ + struct termios state; + + /* Restore line discipline */ + if (ioctl(handle, TIOCSETD, &saved_disc) < 0) { + bb_perror_msg("set discipline"); + exitcode = 1; + } + + /* Hangup */ + memcpy(&state, &saved_state, sizeof(state)); + cfsetispeed(&state, B0); + cfsetospeed(&state, B0); + if (tcsetattr(handle, TCSANOW, &state) < 0) { + bb_perror_msg("set state"); + exitcode = 1; + } + + sleep(1); + + /* Restore line status */ + if (tcsetattr(handle, TCSANOW, &saved_state) < 0) { + bb_perror_msg_and_die("set state"); + } + + if (ENABLE_FEATURE_CLEAN_UP) + close(handle); + + exit(exitcode); +} + +/* + * Set tty state, line discipline and encapsulation + */ +static void set_state(struct termios *state, int encap) +{ + int disc; + + /* Set line status */ + if (tcsetattr(handle, TCSANOW, state) < 0) { + bb_perror_msg("set state"); + goto bad; + } + + /* Set line discliple (N_SLIP always) */ + disc = N_SLIP; + if (ioctl(handle, TIOCSETD, &disc) < 0) { + bb_perror_msg("set discipline"); + goto bad; + } + + /* Set encapsulation (SLIP, CSLIP, etc) */ + if (ioctl(handle, SIOCSIFENCAP, &encap) < 0) { + bb_perror_msg("set encapsulation"); + bad: + restore_state_and_exit(1); + } +} + +static void sig_handler(int signo) +{ + restore_state_and_exit(0); +} + +int slattach_main(int argc, char **argv); +int slattach_main(int argc, char **argv) +{ + int i, encap, opt; + struct termios state; + const char *proto = "cslip"; + const char *extcmd; /* Command to execute after hangup */ + const char *baud_str; + int baud_code = -1; /* Line baud rate (system code) */ + + enum { + OPT_p_proto = 1 << 0, + OPT_s_baud = 1 << 1, + OPT_c_extcmd = 1 << 2, + OPT_e_quit = 1 << 3, + OPT_h_watch = 1 << 4, + OPT_m_nonraw = 1 << 5, + OPT_L_local = 1 << 6, + OPT_F_noflow = 1 << 7, + }; + + INIT_G(); + + /* Parse command line options */ + opt = getopt32(argc, argv, "p:s:c:ehmLF", &proto, &baud_str, &extcmd); + /*argc -= optind;*/ + argv += optind; + + if (!*argv) + bb_show_usage(); + + encap = index_in_str_array(proto_names, proto); + + if (encap < 0) + bb_error_msg_and_die("invalid protocol %s", proto); + if (encap > 3) + encap = 8; + + /* We want to know if the baud rate is valid before we start touching the ttys */ + if (opt & OPT_s_baud) { + baud_code = tty_value_to_baud(xatoi(baud_str)); + if (baud_code < 0) + bb_error_msg_and_die("invalid baud rate"); + } + + /* Trap signals in order to restore tty states upon exit */ + if (!(opt & OPT_e_quit)) { + signal(SIGHUP, sig_handler); + signal(SIGINT, sig_handler); + signal(SIGQUIT, sig_handler); + signal(SIGTERM, sig_handler); + } + + /* Open tty */ + handle = open(*argv, O_RDWR | O_NDELAY); + if (handle < 0) { + char *buf = xasprintf("/dev/%s", *argv); + handle = xopen(buf, O_RDWR | O_NDELAY); + /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */ + free(buf); + } + + /* Save current tty state */ + save_state(); + + /* Confgure tty */ + memcpy(&state, &saved_state, sizeof(state)); + if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */ + memset(&state.c_cc, 0, sizeof(state.c_cc)); + state.c_cc[VMIN] = 1; + state.c_iflag = IGNBRK | IGNPAR; + state.c_oflag = 0; + state.c_lflag = 0; + state.c_cflag = CS8 | HUPCL | CREAD + | ((opt & OPT_L_local) ? CLOCAL : 0) + | ((opt & OPT_F_noflow) ? 0 : CRTSCTS); + } + + if (opt & OPT_s_baud) { + cfsetispeed(&state, baud_code); + cfsetospeed(&state, baud_code); + } + + set_state(&state, encap); + + /* Exit now if option -e was passed */ + if (opt & OPT_e_quit) + return 0; + + /* If we're not requested to watch, just keep descriptor open + * till we are killed */ + if (!(opt & OPT_h_watch)) + while (1) + sleep(24*60*60); + + /* Watch line for hangup */ + while (1) { + if (ioctl(handle, TIOCMGET, &i) < 0 || !(i & TIOCM_CAR)) + goto no_carrier; + sleep(15); + } + + no_carrier: + + /* Execute command on hangup */ + if (opt & OPT_c_extcmd) + system(extcmd); + + /* Restore states and exit */ + restore_state_and_exit(0); +} |