PATCH] microcom enhancements and fixes

Steven Bradshaw shbradshaw at gmail.com
Mon Jan 21 21:35:49 UTC 2008


I have made some additional changes based on
input from Bernhard Fischer and Vladimir Dronnikov
to reduce stack and code size.

Vladimir had some concern about the compatibility
of removing the input flushes.  I don't think that they
are needed and removing them is less code, so this
patch removes them.  If that's a problem, then just
leave them in.

Steve


diff -r -u 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-21 12:25:17.000000000 -0800
@@ -9,33 +9,49 @@
  */
 #include "libbb.h"

+static volatile int signalled;
+
+static void
+sig_catcher(int signo)
+{
+	signalled = signo;
+}
+
 int microcom_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int microcom_main(int argc, char **argv)
 {
+	struct termios tio0, tiosfd;
 	struct pollfd pfd[2];
-#define sfd (pfd[1].fd)
-	char *device_lock_file = NULL;
-	const char *s;
+	char  *device_lock_file;
 	const char *opt_s = "9600";
-	unsigned speed;
-	int len;
-	int exitcode = 1;
-	struct termios tio0, tiosfd, tio;
+	const char *str;
+	int  sfd;
+	int  exitcode = 1;
+	bool usr_is_tty;

+	// Process the command arguments
 	getopt32(argv, "s:", &opt_s);
 	argc -= optind;
 	argv += optind;
 	if (!argv[0])
 		bb_show_usage();
-	speed = xatou(opt_s);

-	// try to create lock file in /var/lock
-	s = bb_basename(argv[0]);
-	if (!s[0]) {
+	// Create the lock file name
+	str = bb_basename(argv[0]);
+	if (!str[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.
+	// Need to do this before lock is created.
+	sig_catch(SIGHUP,  sig_catcher);
+	sig_catch(SIGINT,  sig_catcher);
+	sig_catch(SIGTERM, sig_catcher);
+	sig_catch(SIGPIPE, sig_catcher);
+
+	// Acquire the lock file
+	device_lock_file = xasprintf("/var/lock/LCK..%s", str);
 	sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644);
 	if (sfd < 0) {
 		if (ENABLE_FEATURE_CLEAN_UP)
@@ -48,83 +64,117 @@
 	} else {
 		// %4d to make mgetty happy. It treats 4-bytes lock files as binary,
 		// not text, PID. Making 5+ char file. Brrr...
-		s = xasprintf("%4d\n", getpid());
-		write(sfd, s, strlen(s));
+		str = xasprintf("%4d\n", getpid());
+		write(sfd, str, strlen(str));
 		if (ENABLE_FEATURE_CLEAN_UP)
-			free((char*)s);
+			free((char*)str);
 		close(sfd);
 	}

-	// open device
-	sfd = open(argv[0], O_RDWR);
-	if (sfd < 0) {
-		bb_perror_msg("can't open device");
+	// Open device.
+	sfd = open_or_warn(argv[0], O_RDWR);
+	if (sfd < 0)
 		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");
+	// Confiure the device and the user's tty (if it is a tty).
+	// Make sure can get both sets of settings before making
+	// changes so that valid settings are restored.
+	if (tcgetattr(sfd, &tiosfd)) {
+		bb_perror_msg("can't tcgetattr for %s", "device");
 		goto unlock_and_exit;
 	}
-
-	/* same thing for modem (plus: set baud rate) - TODO: make CLI option */
-	tcgetattr(sfd, &tiosfd);
-	tio = tiosfd;
-	tio.c_lflag &= ~(ICANON|ECHO);
-	tio.c_iflag &= ~(IXON|ICRNL);
-	tio.c_oflag &= ~(ONLCR);
-	tio.c_cc[VMIN] = 1;
-	tio.c_cc[VTIME] = 0;
-	cfsetispeed(&tio, tty_value_to_baud(speed));
-	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;
+	usr_is_tty = isatty(STDIN_FILENO); // remember for cleanup
+	if (usr_is_tty) {
+		// Configure the user tty
+		struct termios tio;
+
+		if (tcgetattr(STDIN_FILENO, &tio0)) {
+			bb_perror_msg("can't tcgetattr for %s", "stdin");
+			goto unlock_and_exit;
+		}
+		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;
+		}
+	}
+	{	// Configure the device tty
+		struct termios tio;
+		speed_t speed = tty_value_to_baud(xatou(opt_s));
+
+		tio = tiosfd;
+		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;
+
+		// Set 8 bits, 1 stop, no parity
+		// Set input & output baudrates
+		tio.c_cflag &= ~(CSIZE|CSTOPB|PARENB);
+		tio.c_cflag |=  (CS8|CREAD|HUPCL);
+		cfsetispeed(&tio, speed);
+		cfsetospeed(&tio, speed);
+
+		if (tcsetattr(sfd, TCSANOW, &tio)) {
+			bb_perror_msg("can't tcsetattr for %s", "device");
+			goto cleanup_and_exit;
+		}
 	}

-	// disable SIGINT
-	signal(SIGINT, SIG_IGN);
-
-	// 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' (%s bps), exit with ctrl-X...\r\n",
+			argv[0], opt_s);

 	// main loop: check with poll(), then read/write bytes across
+	exitcode = 0;
 	pfd[0].fd = STDIN_FILENO;
 	pfd[0].events = POLLIN;
-	/*pfd[1].fd = sfd;*/
+	pfd[1].fd = sfd;
 	pfd[1].events = POLLIN;
-	while (1) {
+
+	while (!signalled) {
 		int i;
 		safe_poll(pfd, 2, -1);
 		for (i = 0; i < 2; ++i) {
 			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;
+				int len = read(pfd[i].fd, buf, COMMON_BUFSIZE);
+				if (len <= 0)
+					goto cleanup_and_exit;
+				if (i) { // Process device input
+					if (write(STDOUT_FILENO, buf, len) != len)
+						goto cleanup_and_exit;
+				}
+				else {   // Process stdin
+ again:
+					if (24 == buf[0])   // ^X exits
+						goto cleanup_and_exit;
+					if (0  == buf[0]) { // ^@ sends Break
+						tcsendbreak(sfd, 0);
+						if (--len <= 0)
+							continue; // for() loop
+						buf++;
+						goto again;   // next byte
+					}
+					if (write(sfd, 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