[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 | *
|
---|
| 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_and_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) ATTRIBUTE_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_and_warn(&state))
|
---|
| 82 | exitcode = 1;
|
---|
| 83 | sleep(1);
|
---|
| 84 |
|
---|
| 85 | /* Restore line status */
|
---|
| 86 | if (set_termios_state_and_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_and_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(1);
|
---|
| 114 | }
|
---|
| 115 | }
|
---|
| 116 |
|
---|
| 117 | static void sig_handler(int signo)
|
---|
| 118 | {
|
---|
| 119 | restore_state_and_exit(0);
|
---|
| 120 | }
|
---|
| 121 |
|
---|
| 122 | int slattach_main(int argc, char **argv);
|
---|
| 123 | int slattach_main(int argc, 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 | signal(SIGHUP, sig_handler);
|
---|
| 179 | signal(SIGINT, sig_handler);
|
---|
| 180 | signal(SIGQUIT, sig_handler);
|
---|
| 181 | signal(SIGTERM, sig_handler);
|
---|
| 182 | }
|
---|
| 183 |
|
---|
| 184 | /* Open tty */
|
---|
| 185 | handle = open(*argv, O_RDWR | O_NDELAY);
|
---|
| 186 | if (handle < 0) {
|
---|
| 187 | char *buf = concat_path_file("/dev", *argv);
|
---|
| 188 | handle = xopen(buf, O_RDWR | O_NDELAY);
|
---|
| 189 | /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */
|
---|
| 190 | free(buf);
|
---|
| 191 | }
|
---|
| 192 |
|
---|
| 193 | /* Save current tty state */
|
---|
| 194 | save_state();
|
---|
| 195 |
|
---|
| 196 | /* Configure tty */
|
---|
| 197 | memcpy(&state, &saved_state, sizeof(state));
|
---|
| 198 | if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */
|
---|
| 199 | memset(&state.c_cc, 0, sizeof(state.c_cc));
|
---|
| 200 | state.c_cc[VMIN] = 1;
|
---|
| 201 | state.c_iflag = IGNBRK | IGNPAR;
|
---|
| 202 | state.c_oflag = 0;
|
---|
| 203 | state.c_lflag = 0;
|
---|
| 204 | state.c_cflag = CS8 | HUPCL | CREAD
|
---|
| 205 | | ((opt & OPT_L_local) ? CLOCAL : 0)
|
---|
| 206 | | ((opt & OPT_F_noflow) ? 0 : CRTSCTS);
|
---|
| 207 | }
|
---|
| 208 |
|
---|
| 209 | if (opt & OPT_s_baud) {
|
---|
| 210 | cfsetispeed(&state, baud_code);
|
---|
| 211 | cfsetospeed(&state, baud_code);
|
---|
| 212 | }
|
---|
| 213 |
|
---|
| 214 | set_state(&state, encap);
|
---|
| 215 |
|
---|
| 216 | /* Exit now if option -e was passed */
|
---|
| 217 | if (opt & OPT_e_quit)
|
---|
| 218 | return 0;
|
---|
| 219 |
|
---|
| 220 | /* If we're not requested to watch, just keep descriptor open
|
---|
| 221 | * until we are killed */
|
---|
| 222 | if (!(opt & OPT_h_watch))
|
---|
| 223 | while (1)
|
---|
| 224 | sleep(24*60*60);
|
---|
| 225 |
|
---|
| 226 | /* Watch line for hangup */
|
---|
| 227 | while (1) {
|
---|
| 228 | if (ioctl(handle, TIOCMGET, &i) < 0 || !(i & TIOCM_CAR))
|
---|
| 229 | goto no_carrier;
|
---|
| 230 | sleep(15);
|
---|
| 231 | }
|
---|
| 232 |
|
---|
| 233 | no_carrier:
|
---|
| 234 |
|
---|
| 235 | /* Execute command on hangup */
|
---|
| 236 | if (opt & OPT_c_extcmd)
|
---|
| 237 | system(extcmd);
|
---|
| 238 |
|
---|
| 239 | /* Restore states and exit */
|
---|
| 240 | restore_state_and_exit(0);
|
---|
| 241 | }
|
---|