You should initialize the termios structure more completely, e.g. cflags, VMIN and VTIME, as in this working code, or like this using the perror() syscall:
rc = tcgetattr(sfd, &tty);
if (rc < 0) {
perror("failed to get attr");
exit (-2);
}
savetty = tty; /* preserve original settings for restoration */
spd = B115200;
cfsetospeed(&tty, (speed_t)spd);
cfsetispeed(&tty, (speed_t)spd);
cfmakeraw(&tty);
tty.c_cc[VMIN] = 1; /* wait for at least 1 char */
tty.c_cc[VTIME] = 10; /* or 1 sec after a char */
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS; /* no HW flow control */
tty.c_cflag |= CLOCAL | CREAD;
rc = tcsetattr(sfd, TCSANOW, &tty);
if (rc < 0) {
perror("failed to set attr");
exit (-3);
}
You should also be testing every return code from all syscalls, especially when you encounter issues.
Looking over your code again, the first argument to tcgetattr() is obviously incorrect:
tcgetattr(0, &orig_termios);
Defensive coding (e.g. validating parameters and checking return calls) is helpful in catching these types of silly mistakes that can consume a lot of debugging time.
ADDENDUM
I think I understand why the code seemed to work in the first situation, when started "manually" from the shell.
The file descriptor value of 0 is the value of STDIN_FILENO.
So the tcgetattr(0, &orig_termios)
statement would retrieve the termios values for stdin. (Initially I assumed you always got an undetected error return, so the structure would be returned unmodified.) Presumably you executed this on an embedded system, where the console is a serial port (and the returned values for stdin are a serial port's).
When I ran this code on a PC, cflags is provided with the CREAD flag disabled, and that should have caused a problem later. Note that setting cflags was one of my recommendations. VMIN and VTIME are returned as 8 and 4 respectively, but those unusual values would not have been fatal like the CREAD flag. There are other unusual termios values from the stdin video console, and a few would be corrected by your (minimal) initialization code or, since non-canonical mode is used, most of the unusual values are irrelevant.