source: branches/2.2.5/mindi-busybox/networking/slattach.c @ 1765

Last change on this file since 1765 was 1765, checked in by Bruno Cornec, 13 years ago

Update to busybox 1.7.2

  • Property svn:eol-style set to native
File size: 5.3 KB
Line 
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
19struct 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 */
36static 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
46static 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 */
67static void restore_state_and_exit(int exitcode) ATTRIBUTE_NORETURN;
68static 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 */
97static 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
117static void sig_handler(int signo)
118{
119    restore_state_and_exit(0);
120}
121
122int slattach_main(int argc, char **argv);
123int 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}
Note: See TracBrowser for help on using the repository browser.