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

Reply via email to