1 year ago
#356324
unami
Can't send input to a process over a pty in C
I'm trying to run a process (/usr/bin/calc) on the master/main side, and interact with it on the slave/secondary side, but for some reason, the calc process isn't reading input from the main end of the pty.
I've got the main and secondary sides in 2 files running separately, here's the gist of what each does:
main:
- calls openpty() to get the main file descriptor (mfd) and the secondary name (sname)
- forks
- parent: displays the mfd, sfd, and sname, then loops to keep the mfd open
- child: dup2's the mfd to stdin/out/err (
dup2(mfd, STDIN_FILENO);
), then calls execvp() to run the calc process
secondary:
- takes the sname as an input (ie, /dev/pts/5), and calls open() on it to open the secondary end of the pty
- forks
- parent: in a never-ending while loop, reads input from stdin and writes it to the sfd
- child: in a never-ending while loop, reads input from sfd and writes to stdout
What I'm seeing:
- initially I see the output of the calc cmd on the secondary side, which is what I expected
And that's it. After that, I try typing on the secondary side (to send back to the main side, as input for the calc cmd), but I don't believe calc is reading it as input.
As a sanity test, I wrote a new program for the main side, which opened the pty, forked, and in one process, wrote a string to the mfd (for the sfd to display), and in the other, read from the mfd and displayed the input on the screen. This worked exactly as expected - the secondary side read/displayed everything the main side wrote to the pty, and everything I typed in on the secondary side displayed on the main side, so I'm able to read/write to the pty without any problem, but for some reason when I try to run calc, it doesn't seem to be receiving what I'm sending it over the pty.
This is my first time doing most of this (first time working with a pty, first time forking, first time calling exec), so I plead ignorance. Any idea what I might be doing wrong? I can post my code if needed, but it's all pretty straight-forward (that's the frustrating part - it seems so straight-forward, and yet still doesn't work :-/ ).
Here is the code, as requested - main, followed by the secondary side of the pty.
main:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pty.h>
#include <termios.h>
#include <errno.h>
struct termios tty;
#define PTSNAME_SIZE 1024
int main(void) {
int mfd, sfd, i = 1;
char *cmd[] = {"/usr/bin/calc", NULL};
char sname[PTSNAME_SIZE];
pid_t pid;
memset(sname, 0, PTSNAME_SIZE);
errno = 0;
// open the pseudoterminal
if (openpty(&mfd, &sfd, sname, NULL, NULL) == -1) {
perror("error calling openpty\r\n");
return errno;
}
if (tcgetattr(mfd, &tty) == -1) {
perror("tcgetattr");
return -1;
}
tty.c_lflag &= ~ECHO;
if (tcsetattr(mfd, TCSANOW, &tty) != 0) {
perror("tcsetattr");
return -1;
}
close(sfd);
// in the parent, write data
// in the child, read data
pid = fork();
switch(pid) {
case -1:
perror("error forking\r\n");
return errno;
break;
case 0:
// child
// set stdin/out/err to the mfd
dup2(mfd, STDIN_FILENO);
dup2(mfd, STDOUT_FILENO);
dup2(mfd, STDERR_FILENO);
close(mfd);
// and start a process - the output from this cmd should go to the secondary end
// of the pty, and anything written on that end should come back as input to the process
execvp(cmd[0], cmd);
break;
default:
// parent
printf("main %d, secondary %d, sname %s\r\n", mfd, sfd, sname);
for (i = 0; ; i++) {
sleep(2);
}
}
return 0;
}
Secondary:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pty.h>
#include <termios.h>
#include <errno.h>
struct termios tty;
int main(int argc, char *argv[]) {
int sfd, rc, i = 1;
char buf[256];
pid_t pid;
errno = 0;
if (argc > 1)
sfd = open(argv[1], O_RDWR);
else {
perror("invalid syntax - must specify /dev/pts/x\r\n");
return errno;
}
if (sfd > 0) {
pid = fork();
switch(pid) {
case -1:
perror("error forking\r\n");
return errno;
break;
case 0:
// child
// read data sent from mfd
while (1) {
memset(buf, 0, sizeof(buf));
rc = read(sfd, buf, sizeof(buf));
if (rc > 0) {
printf("%d. Rec'd this from ptym (rc=%d): %s\r\n", i++, rc, buf);
} else {
perror("error reading on sfd\r\n");
}
}
break;
default:
//parent
while(1) {
memset(buf, 0, sizeof(buf));
// read input from stdin
rc = read(STDIN_FILENO, buf, sizeof(buf));
if (rc > 0) {
buf[strlen(buf)-1] = 0;
printf("sending to mfd: %s, len=%ld", buf, strlen(buf));
// write data to sfd
write(sfd, buf, strlen(buf));
fflush(NULL);
} else {
perror("error reading on sfd\r\n");
}
}
break;
}
} else {
perror("open(sfd) failed\r\n");
return errno;
}
return 0;
}
c
linux
stdin
pty
execvp
0 Answers
Your Answer