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;
+
+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;
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);
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
+ }
}
+ 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) {
_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox