diff --git a/include/applets.h b/include/applets.h index 0f378bbeb..8a33f5432 100644 --- a/include/applets.h +++ b/include/applets.h @@ -296,6 +296,7 @@ USE_FEATURE_SH_IS_HUSH(APPLET_NOUSAGE(sh, hush, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_FEATURE_SH_IS_LASH(APPLET_NOUSAGE(sh, lash, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_FEATURE_SH_IS_MSH(APPLET_NOUSAGE(sh, msh, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha1sum)) +USE_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_SLEEP(APPLET_NOFORK(sleep, sleep, _BB_DIR_BIN, _BB_SUID_NEVER, sleep)) USE_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, softlimit)) USE_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sort)) diff --git a/include/usage.h b/include/usage.h index 7d09feb05..2baa495ac 100644 --- a/include/usage.h +++ b/include/usage.h @@ -2991,6 +2991,20 @@ USE_FEATURE_RUN_PARTS_FANCY("\n -l Prints names of all matching files even when " -s Don't output anything, status code shows success\n" \ " -w Warn about improperly formatted SHA1 checksum lines") +#define slattach_trivial_usage \ + "[-cehmLF] [-s speed] [-p protocol] DEVICEs" +#define slattach_full_usage \ + "Attach network interface(s) to serial line(s)\n" \ + "\nOptions:" \ + "\n -p Set protocol (slip, cslip, slip6, clisp6 or adaptive)" \ + "\n -s Set line speed" \ + "\n -e Exit after initializing device" \ + "\n -h Exit when the carrier is lost" \ + "\n -c Execute a command when the line is hung up" \ + "\n -m Do NOT initialize the line in raw 8 bits mode" \ + "\n -L Enable 3-wire operation" \ + "\n -F Disable RTS/CTS flow control" \ + #define sleep_trivial_usage \ USE_FEATURE_FANCY_SLEEP("[") "N" USE_FEATURE_FANCY_SLEEP("]...") #define sleep_full_usage \ diff --git a/networking/Config.in b/networking/Config.in index 13ad13f9a..77b5d2558 100644 --- a/networking/Config.in +++ b/networking/Config.in @@ -548,6 +548,12 @@ config ROUTE help Route displays or manipulates the kernel's IP routing tables. +config SLATTACH + bool "slattach" + default n + help + slattach is a small utility to attach network interfaces to serial lines. + config TELNET bool "telnet" default n diff --git a/networking/Kbuild b/networking/Kbuild index 0f4ab7ba6..23968a833 100644 --- a/networking/Kbuild +++ b/networking/Kbuild @@ -27,6 +27,7 @@ lib-$(CONFIG_PING) += ping.o lib-$(CONFIG_PING6) += ping.o lib-$(CONFIG_PSCAN) += pscan.o lib-$(CONFIG_ROUTE) += route.o +lib-$(CONFIG_SLATTACH) += slattach.o lib-$(CONFIG_TELNET) += telnet.o lib-$(CONFIG_TELNETD) += telnetd.o lib-$(CONFIG_TFTP) += tftp.o diff --git a/networking/slattach.c b/networking/slattach.c new file mode 100644 index 000000000..1c00fddb6 --- /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); +}