busybox/networking/slattach.c
James Byrne 6937487be7 libbb: reduce the overhead of single parameter bb_error_msg() calls
Back in 2007, commit 0c97c9d437 ("'simple' error message functions by
Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower
overhead call to bb_perror_msg() when only a string was being printed
with no parameters. This saves space for some CPU architectures because
it avoids the overhead of a call to a variadic function. However there
has never been a simple version of bb_error_msg(), and since 2007 many
new calls to bb_perror_msg() have been added that only take a single
parameter and so could have been using bb_simple_perror_message().

This changeset introduces 'simple' versions of bb_info_msg(),
bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and
bb_herror_msg_and_die(), and replaces all calls that only take a
single parameter, or use something like ("%s", arg), with calls to the
corresponding 'simple' version.

Since it is likely that single parameter calls to the variadic functions
may be accidentally reintroduced in the future a new debugging config
option WARN_SIMPLE_MSG has been introduced. This uses some macro magic
which will cause any such calls to generate a warning, but this is
turned off by default to avoid use of the unpleasant macros in normal
circumstances.

This is a large changeset due to the number of calls that have been
replaced. The only files that contain changes other than simple
substitution of function calls are libbb.h, libbb/herror_msg.c,
libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c,
networking/udhcp/common.h and util-linux/mdev.c additonal macros have
been added for logging so that single parameter and multiple parameter
logging variants exist.

The amount of space saved varies considerably by architecture, and was
found to be as follows (for 'defconfig' using GCC 7.4):

Arm:     -92 bytes
MIPS:    -52 bytes
PPC:   -1836 bytes
x86_64: -938 bytes

Note that for the MIPS architecture only an exception had to be made
disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h)
because it made these files larger on MIPS.

Signed-off-by: James Byrne <james.byrne@origamienergy.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 11:35:03 +02:00

233 lines
6.0 KiB
C

/* vi: set sw=4 ts=4: */
/*
* Stripped down version of net-tools for busybox.
*
* Author: Ignacio Garcia Perez (iggarpe at gmail dot com)
*
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
*
* 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.
*/
//config:config SLATTACH
//config: bool "slattach (6.2 kb)"
//config: default y
//config: select PLATFORM_LINUX
//config: help
//config: slattach configures serial line as SLIP network interface.
//applet:IF_SLATTACH(APPLET(slattach, BB_DIR_SBIN, BB_SUID_DROP))
/* shouldn't be NOEXEC: may sleep indefinitely */
//kbuild:lib-$(CONFIG_SLATTACH) += slattach.o
//usage:#define slattach_trivial_usage
//usage: "[-ehmLF] [-c SCRIPT] [-s BAUD] [-p PROTOCOL] SERIAL_DEVICE"
//usage:#define slattach_full_usage "\n\n"
//usage: "Configure serial line as SLIP network interface\n"
//usage: "\n -p PROT Protocol: slip, cslip (default), slip6, clisp6, adaptive"
//usage: "\n -s BAUD Line speed"
//usage: "\n -e Exit after initialization"
//usage: "\n -h Exit if carrier is lost (else never exits)"
//usage: "\n -c PROG Run PROG on carrier loss"
//usage: "\n -m Do NOT set raw 8bit mode"
//usage: "\n -L Enable 3-wire operation"
//usage: "\n -F Disable RTS/CTS flow control"
#include "libbb.h"
#include "common_bufsiz.h"
#include "libiproute/utils.h" /* invarg_1_to_2() */
struct globals {
int saved_disc;
struct termios saved_state;
} FIX_ALIASING;
#define G (*(struct globals*)bb_common_bufsiz1)
#define INIT_G() do { setup_common_bufsiz(); } while (0)
#define serial_fd 3
static int tcsetattr_serial_or_warn(struct termios *state)
{
int ret;
ret = tcsetattr(serial_fd, TCSANOW, state);
if (ret != 0) {
bb_simple_perror_msg("tcsetattr");
return 1; /* used as exitcode */
}
return ret; /* 0 */
}
static void restore_state_and_exit(int exitcode) NORETURN;
static void restore_state_and_exit(int exitcode)
{
struct termios state;
/* Restore line discipline */
if (ioctl_or_warn(serial_fd, TIOCSETD, &G.saved_disc)) {
exitcode = 1;
}
/* Hangup */
memcpy(&state, &G.saved_state, sizeof(state));
cfsetispeed(&state, B0);
cfsetospeed(&state, B0);
exitcode |= tcsetattr_serial_or_warn(&state);
sleep(1);
/* Restore line status */
if (tcsetattr_serial_or_warn(&G.saved_state))
exit(EXIT_FAILURE);
if (ENABLE_FEATURE_CLEAN_UP)
close(serial_fd);
exit(exitcode);
}
static void sig_handler(int signo UNUSED_PARAM)
{
restore_state_and_exit(EXIT_SUCCESS);
}
int slattach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int slattach_main(int argc UNUSED_PARAM, char **argv)
{
/* Line discipline code table */
static const char proto_names[] ALIGN1 =
"slip\0" /* 0 */
"cslip\0" /* 1 */
"slip6\0" /* 2 */
"cslip6\0" /* 3 */
"adaptive\0" /* 8 */
;
static const int int_N_SLIP = N_SLIP;
int encap, opt, fd;
struct termios state;
const char *proto = "cslip";
const char *extcmd; /* Command to execute after hangup */
const char *baud_str;
int baud_code = baud_code; /* for compiler */
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(argv, "^" "p:s:c:ehmLF" "\0" "=1",
&proto, &baud_str, &extcmd
);
/*argc -= optind;*/
argv += optind;
encap = index_in_strings(proto_names, proto);
if (encap < 0)
invarg_1_to_2(proto, "protocol");
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)
invarg_1_to_2(baud_str, "baud rate");
}
/* Open tty */
fd = open(*argv, O_RDWR | O_NDELAY);
if (fd < 0) {
char *buf = concat_path_file("/dev", *argv);
fd = xopen(buf, O_RDWR | O_NDELAY);
/* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */
free(buf);
}
xmove_fd(fd, serial_fd);
/* Save current tty state */
if (tcgetattr(serial_fd, &G.saved_state) != 0)
bb_simple_perror_msg_and_die("tcgetattr");
/* Save line discipline */
xioctl(serial_fd, TIOCGETD, &G.saved_disc);
/* Trap signals in order to restore tty states upon exit */
if (!(opt & OPT_e_quit)) {
bb_signals(0
+ (1 << SIGHUP)
+ (1 << SIGINT)
+ (1 << SIGQUIT)
+ (1 << SIGTERM)
, sig_handler);
}
/* Configure tty */
memcpy(&state, &G.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);
cfsetispeed(&state, cfgetispeed(&G.saved_state));
cfsetospeed(&state, cfgetospeed(&G.saved_state));
}
if (opt & OPT_s_baud) {
cfsetispeed(&state, baud_code);
cfsetospeed(&state, baud_code);
}
/* Set line status */
if (tcsetattr_serial_or_warn(&state))
goto bad;
/* Set line disclipline (N_SLIP always) */
if (ioctl_or_warn(serial_fd, TIOCSETD, (void*)&int_N_SLIP))
goto bad;
/* Set encapsulation (SLIP, CSLIP, etc) */
if (ioctl_or_warn(serial_fd, SIOCSIFENCAP, &encap))
goto bad;
/* Exit now if option -e was passed */
if (opt & OPT_e_quit)
return EXIT_SUCCESS;
/* If we're not requested to watch, just keep descriptor open
* until we are killed */
if (!(opt & OPT_h_watch))
while (1)
sleep(24*60*60);
/* Watch line for hangup */
while (1) {
int modem_stat;
if (ioctl(serial_fd, TIOCMGET, &modem_stat))
break;
if (!(modem_stat & TIOCM_CAR))
break;
sleep(15);
}
/* Execute command on hangup */
if (opt & OPT_c_extcmd)
system(extcmd);
/* Restore states and exit */
restore_state_and_exit(EXIT_SUCCESS);
bad:
restore_state_and_exit(EXIT_FAILURE);
}