Jeff Abrahamson on Mon, 26 Aug 2002 16:40:19 +0200 |
I've been hitting my head on the wall for several hours now. I wrote a simple program, mostly cribbed from Stevens (APUE), to let me run a process and talk to it. As my example, I just use dc. I want to type "1 2 +p" to it and see it say "3". I know I could have buffering issues, but that would be an improvement. Eventually, it'll be my own program I talk to and I can turn off buffering. As it happens, dc just sits there defunct before I first write to it, so when I do write I get a SIGPIPE. I can see this by breaking in gdb at the fgets(...stdin) at line 74. So I'm guessing dc's stdin is closed. I've attached the sample program, it may be compiled with gcc -g -O2 -Wall -W test-fork.c -o test-fork Anyone see what I'm doing wrong? Thanks much in advance for any tips. -- Jeff Jeff Abrahamson <http://www.purple.com/jeff/> #include <errno.h> #include <fcntl.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> #include <unistd.h> static void sig_pipe(int signo) { signo=0; printf("SIGPIPE caught.\n"); exit(-2); } void set_blocking(int fd) { int val; if((val = fcntl(fd, F_GETFL, 0)) == -1) return; if (val & O_NONBLOCK) { val &= ~O_NONBLOCK; fcntl(fd, F_SETFL, val); } } void set_nonblocking(int fd) { int val; if((val = fcntl(fd, F_GETFL, 0)) == -1) return; if (!(val & O_NONBLOCK)) { val |= O_NONBLOCK; fcntl(fd, F_SETFL, val); } } int fd_pair(int fd[2]) { int ret; ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); /* ret = pipe(fd); */ if (ret == 0) { set_nonblocking(fd[0]); set_nonblocking(fd[1]); } return ret; } #define BUF_SIZE 1024 void talk_to_subprocess(int f_in, int f_out) { char buf[BUF_SIZE]; int num; char *str, buf2[BUF_SIZE]; while(fgets(buf, BUF_SIZE, stdin)) { str = " ==> Writing '"; write(STDOUT_FILENO, str, strlen(str)); write(1, buf, strlen(buf)); write(f_out, buf, strlen(buf)); str = "' to subprocess.\n"; write(STDOUT_FILENO, str, strlen(str)); num = read(f_in, buf, BUF_SIZE); buf[num] = '\0'; sprintf(buf2, " --> num = %d, read '%s'.\n", num, buf); write(STDOUT_FILENO, buf2, strlen(buf2)); printf("%s\n", buf); } printf("Finished talking to sub-process.\n"); return; } pid_t piped_child(char **command, int *f_in, int *f_out) { pid_t pid; int to_child_pipe[2]; int from_child_pipe[2]; if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) { fprintf(stderr, "pipe: %s\n", strerror(errno)); exit(-1); } pid = fork(); if (pid < 0) { fprintf(stderr, "fork: %s\n", strerror(errno)); exit(-1); } if (pid == 0) { /* child */ close(to_child_pipe[1]); close(from_child_pipe[0]); if(to_child_pipe[0] != STDIN_FILENO) { if(dup2(to_child_pipe[0], STDIN_FILENO) < 0) { fprintf(stderr, "Failed to dup/close : %s\n", strerror(errno)); exit(-1); } close(to_child_pipe[0]); } if(from_child_pipe[1] != STDOUT_FILENO) { if(dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { fprintf(stderr, "Failed to dup/close : %s\n", strerror(errno)); exit(-1); } close(from_child_pipe[1]); } set_blocking(STDIN_FILENO); /* if (blocking_io) { set_blocking(STDOUT_FILENO); } */ execvp(command[0], command); fprintf(stderr, "Failed to exec %s : %s\n", command[0], strerror(errno)); exit(-1); } /* parent */ if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) { fprintf(stderr, "Failed to close : %s\n", strerror(errno)); exit(-1); } *f_out = to_child_pipe[1]; *f_in = from_child_pipe[0]; return pid; } pid_t do_cmd(char *cmd, int *f_in, int *f_out) { char *args[100]; int argc=0; pid_t ret; char *tok; cmd = strdup(cmd); if (!cmd) goto oom; for (tok=strtok(cmd," "); tok; tok=strtok(NULL," ")) { args[argc++] = tok; } args[argc++] = "."; args[argc] = NULL; ret = piped_child(args,f_in,f_out); if(ret) talk_to_subprocess(*f_in, *f_out); return ret; oom: fprintf(stderr, "Out of memory.\n"); return 0; } int main(int argc,char *argv[]) { pid_t pid; int f_in,f_out; char *shell_cmd = "/usr/bin/dc"; argc = 0; argv = (char **)0; if(signal(SIGPIPE, sig_pipe) == SIG_ERR) fprintf(stderr, "signal SIGPIPE error.\n"); pid = do_cmd(shell_cmd,&f_in,&f_out); return 0; /* optimist! */ } Attachment:
pgp8uizcJcI2z.pgp
|
|