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
busybox@busybox.net
http://busybox.net/cgi-bin/mailman/listinfo/busybox

Reply via email to