PATCH] microcom enhancements and fixes
Bernhard Fischer
rep.dot.nop at gmail.com
Fri Jan 18 08:41:50 UTC 2008
On Wed, Jan 16, 2008 at 10:02:10PM -0800, Steve Bradshaw wrote:
> Hello,
>
> I have made some modifications to microcom to make it
> more useful to me. In particular, I needed to send
> a ^C and a Break to the remote device (Cisco router).
>
> Here are the more detailed changes:
> . Catch common signals to clean up the lock file
> and TTY modes.
> . Allow stdin to not be a TTY so pipes can be used.
> . Save both TTY settings before changing them to
> make cleanup easier.
> . Clear ISIG so that control characters (e.g., ^C,
> ^Z, ^U, etc) are passed through to the device.
> Turn off IEXTEN and BRKINT. Enable HUPCL and
> CREAD.
> . Set the device communications mode to 8-1-N.
> . Removed the stdin flush calls at the start and end.
> I don't think that they are needed.
> . Removed ignore of SIGINT. If user is a TTY,
> there won't be a SIGINT because ISIG is now
> cleared. If user is not a TTY (e.g., a pipe),
> then SIGINT should stop the program (now that
> SIGINT is caught).
> . Send data from the device to the user's stdout
> rather than the stdin so that the program output
> can be redirected.
> . Translate ^@ into a line break.
>
> Here's the patch:
>
>diff -ur busybox-1.8.2.orig/miscutils/microcom.c busybox-1.8.2.new/miscutils/microcom.c
>--- busybox-1.8.2.orig/miscutils/microcom.c 2007-11-09 17:40:53.000000000 -0800
>+++ busybox-1.8.2.new/miscutils/microcom.c 2008-01-16 18:44:44.715294000 -0800
>@@ -9,19 +9,30 @@
> */
> #include "libbb.h"
>
>+static volatile int gotSig;
Should this be in globals?
>+
>+static void
>+sigCatch(int signo)
>+{
>+ gotSig = signo;
>+}
>+
> int microcom_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
> int microcom_main(int argc, char **argv)
> {
> struct pollfd pfd[2];
>+ int outfd[2];
> #define sfd (pfd[1].fd)
> char *device_lock_file = NULL;
> const char *s;
> const char *opt_s = "9600";
> unsigned speed;
> int len;
>+ int usr_is_tty;
bool or smalluint is smaller?
> int exitcode = 1;
> struct termios tio0, tiosfd, tio;
>
>+ // Process the command arguments
> getopt32(argv, "s:", &opt_s);
> argc -= optind;
> argv += optind;
>@@ -29,13 +40,21 @@
> bb_show_usage();
> speed = xatou(opt_s);
>
>- // try to create lock file in /var/lock
>+ // Create the lock file name
> s = bb_basename(argv[0]);
> if (!s[0]) {
> errno = ENODEV;
> bb_perror_msg_and_die("can't lock device");
> }
> device_lock_file = xasprintf("/var/lock/LCK..%s", s);
>+
>+ // Orderly exit to remove lock file and restore tty settings
>+ sig_catch(SIGHUP, sigCatch);
>+ sig_catch(SIGINT, sigCatch);
>+ sig_catch(SIGTERM, sigCatch);
>+ sig_catch(SIGPIPE, sigCatch);
>+
>+ // Acquire the lock file
> sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644);
> if (sfd < 0) {
> if (ENABLE_FEATURE_CLEAN_UP)
>@@ -55,76 +74,101 @@
> close(sfd);
> }
>
>- // open device
>+ // Open device, save current tty settings
> sfd = open(argv[0], O_RDWR);
open_or_warn()
> if (sfd < 0) {
> bb_perror_msg("can't open device");
> goto unlock_and_exit;
> }
>-
>- // put stdin to "raw mode", handle one character at a time
>- tcgetattr(STDIN_FILENO, &tio0);
>- tio = tio0;
>- tio.c_lflag &= ~(ICANON|ECHO);
>- tio.c_iflag &= ~(IXON|ICRNL);
>- tio.c_oflag &= ~(ONLCR);
>- tio.c_cc[VMIN] = 1;
>- tio.c_cc[VTIME] = 0;
>- if (tcsetattr(STDIN_FILENO, TCSANOW, &tio)) {
>- bb_perror_msg("can't tcsetattr for %s", "stdin");
>+ if (tcgetattr(sfd, &tiosfd)) {
>+ bb_perror_msg("can't tcgetattr for %s", "device");
>+ goto unlock_and_exit;
>+ }
>+ usr_is_tty = isatty(STDIN_FILENO);
>+ if (usr_is_tty && tcgetattr(STDIN_FILENO, &tio0)) {
>+ bb_perror_msg("can't tcgetattr for %s", "stdin");
> goto unlock_and_exit;
> }
>
>- /* same thing for modem (plus: set baud rate) - TODO: make CLI option */
>- tcgetattr(sfd, &tiosfd);
>+ // Put device in "raw mode", handle one character at a time.
>+ // TODO: make CLI option
> tio = tiosfd;
>- tio.c_lflag &= ~(ICANON|ECHO);
>- tio.c_iflag &= ~(IXON|ICRNL);
>+ tio.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
>+ tio.c_iflag &= ~(BRKINT|IXON|ICRNL);
> tio.c_oflag &= ~(ONLCR);
>- tio.c_cc[VMIN] = 1;
>+ tio.c_cflag &= ~(CSIZE|CSTOPB|PARENB);
>+ tio.c_cflag |= (CS8|CREAD|HUPCL); // set 8-1-none
>+ tio.c_cc[VMIN] = 1;
> tio.c_cc[VTIME] = 0;
>- cfsetispeed(&tio, tty_value_to_baud(speed));
>+ cfsetispeed(&tio, tty_value_to_baud(speed)); // set baudrate
> cfsetospeed(&tio, tty_value_to_baud(speed));
> if (tcsetattr(sfd, TCSANOW, &tio)) {
> bb_perror_msg("can't tcsetattr for %s", "device");
>- goto unlock_and_exit;
>+ goto cleanup_and_exit;
> }
>
>- // disable SIGINT
>- signal(SIGINT, SIG_IGN);
>+ // Now put the user "raw more" if it's a tty
>+ if (usr_is_tty) {
>+ tio = tio0;
>+ tio.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
>+ tio.c_iflag &= ~(BRKINT|IXON|ICRNL);
>+ tio.c_oflag &= ~(ONLCR);
>+ tio.c_cc[VMIN] = 1;
>+ tio.c_cc[VTIME] = 0;
>+ if (tcsetattr(STDIN_FILENO, TCSANOW, &tio)) {
>+ bb_perror_msg("can't tcsetattr for %s", "stdin");
>+ goto cleanup_and_exit;
>+ }
>+ }
>
>- // drain stdin
>- tcflush(STDIN_FILENO, TCIFLUSH);
>- printf("connected to '%s' (%d bps), exit with ctrl-X...\r\n", argv[0], speed);
>+ printf("connected to '%s' (%d bps), exit with ctrl-X...\r\n",
>+ argv[0], speed);
>
> // main loop: check with poll(), then read/write bytes across
>+ exitcode = 0;
>+ outfd[0] = sfd;
>+ outfd[1] = STDOUT_FILENO;
> pfd[0].fd = STDIN_FILENO;
> pfd[0].events = POLLIN;
>- /*pfd[1].fd = sfd;*/
> pfd[1].events = POLLIN;
>+ if (gotSig)
>+ goto cleanup_and_exit;
>+
> while (1) {
> int i;
> safe_poll(pfd, 2, -1);
> for (i = 0; i < 2; ++i) {
>+ if (gotSig)
>+ goto cleanup_and_exit;
> if (pfd[i].revents & POLLIN) {
>- len = read(pfd[i].fd, bb_common_bufsiz1, COMMON_BUFSIZE);
>- if (len > 0) {
>- if (!i && 24 == bb_common_bufsiz1[0])
>- goto done; // ^X exits
>- write(pfd[1-i].fd, bb_common_bufsiz1, len);
>+ char *buf = bb_common_bufsiz1;
>+ if ((len = read(pfd[i].fd, buf, COMMON_BUFSIZE)) <= 0)
>+ goto cleanup_and_exit;
>+ if (!i) { // Process stdin:
>+ again:
>+ if (24 == buf[0]) // ^X exits
>+ goto cleanup_and_exit;
>+ if (0 == buf[0]) { // ^@ sends Break
>+ tcsendbreak(outfd[i], 0);
>+ if (--len <= 0)
>+ continue;
>+ buf++;
>+ goto again; // next byte
>+ }
> }
Can you reuse some libbb func for (parts of) the block above?
>+ if (write(outfd[i], buf, len) != len)
>+ goto cleanup_and_exit;
> }
> }
> }
>- done:
>- tcsetattr(sfd, TCSANOW, &tiosfd);
>- tcsetattr(STDIN_FILENO, TCSANOW, &tio0);
>- tcflush(STDIN_FILENO, TCIFLUSH);
>
>+ cleanup_and_exit:
>+ // Restore tty modes
>+ if (usr_is_tty)
>+ tcsetattr(STDIN_FILENO, TCSANOW, &tio0);
>+ tcsetattr(sfd, TCSANOW, &tiosfd);
> if (ENABLE_FEATURE_CLEAN_UP)
> close(sfd);
>- exitcode = 0;
>-
> unlock_and_exit:
> // delete lock file
> if (device_lock_file) {
More information about the busybox
mailing list