slattach: new applet.
authorDenis Vlasenko <vda.linux@googlemail.com>
Wed, 20 Jun 2007 15:23:03 +0000 (15:23 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Wed, 20 Jun 2007 15:23:03 +0000 (15:23 -0000)
include/applets.h
include/usage.h
networking/Config.in
networking/Kbuild
networking/slattach.c [new file with mode: 0644]

index 0f378bbeb6572c661c4d69b543874801ed0c3a71..8a33f543223c9b172279feca9f2f2192ce4f09b4 100644 (file)
@@ -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))
index 7d09feb05b85b1493d81e2b382280156148a8195..2baa495ac3bbc40387b8f9da92e4690f6f3b304a 100644 (file)
@@ -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 \
index 13ad13f9afbeed2651962d3baa00be207733f57b..77b5d2558c784443cfe236c00761fede8df58f1a 100644 (file)
@@ -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
index 0f4ab7ba6dfc4f5f33d8932cb5aabd89be33e01b..23968a83316d313009fc1afac8a9fe327edd741b 100644 (file)
@@ -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 (file)
index 0000000..1c00fdd
--- /dev/null
@@ -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);
+}