I'm trying to print a 2D table to my terminal using this code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <sys/wait.h>
char getch()
{
char ch;
struct termios old, new;
tcgetattr(0, &old); // grab old terminal i/o settings
new = old; // new settings = old settings
new.c_lflag &= ~ICANON; // disable buffered i/o
new.c_lflag &= ~ECHO; //set echo mode
tcsetattr(0, TCSANOW, &new); // use these new terminal i/o settings now
ch = getchar();
tcsetattr(0, TCSANOW, &old); //restore old settings
return ch;
}
void readPBM(char *output)
{
char tmp[1024];
int fd[2] = {0,0};
int pid;
//Open the pipe for inter-process communication
pipe(&fd[0]);
//Fork and test if we are child or parent process
pid = fork();
if(pid) //Parent process
{
wait(NULL); //Wait for child's end
close(fd[1]);//Close pipe's write stream
close(0);//Close stdin
dup(fd[0]);//Duplicate stdout
close(fd[0]);//Close old stdout
strcpy(output, "");// Init output at 0
while(fgets(tmp, 1024, stdin) != NULL) //Put remaining entry in output
{
strcat(output, tmp);
}
}
else if(pid == 0) //Child process
{
close(fd[0]);//Close pipe's read stream
close(1);//Close stdout
dup(fd[1]);//Duplicate stdin
close(fd[1]);//Close old stdin
printf("A random string ...\n");
}
else //Print error if fork failed
{
printf("Error creating a new process");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[])
{
int i, j;
char *str = NULL;
char c;
str = malloc(512 * sizeof(char*));
readPBM(str);
printf("%s", str);
fflush(stdout);
c = getch();
}
I have a UNIX implementation of getch().
My problem is that my program is waiting for an input to print the table. I tried to fflush(stdout) and to disable terminal buffering with ICANON but it's still not working.
PS: it's not working neither with getchar, scanf, ...
EDIT: So I came up to this minimal example; it seems to be pipe-related.
My problem is that my program is waiting for an input to print the table.
This is because you forgot to terminate the child process when it has done its work, so after printing A random string ... to the pipe it continues, returning from readPBM() and eventually executing the c = getch() at the end of main(). The remedy is to call exit(0) at the end of the if(pid == 0) //Child process block.
Related
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
static struct termios old, new;
/* Initialize new terminal i/o settings */
void initTermios(int echo)
{
tcgetattr(0, &old); /* grab old terminal i/o settings */
new = old; /* make new settings same as old settings */
new.c_lflag &= ~ICANON; /* disable buffered i/o */
new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
}
/* Restore old terminal i/o settings */
void resetTermios(void)
{
tcsetattr(0, TCSANOW, &old);
}
/* Read 1 character - echo defines echo mode */
char getch_(int echo)
{
char ch;
initTermios(echo);
ch = getchar();
resetTermios();
return ch;
}
/* Read 1 character without echo */
char getch(void)
{
return getch_(0);
}
/* Read 1 character with echo */
char getche(void)
{
return getch_(1);
}
void INThandler(int);
void INThandler(int sig)
{
char c;
signal(sig, SIG_IGN);
printf("\n Ctrl+c foi detetado, clique y para confirmar \n");
c = getchar();
if(c == 'y' || c == 'Y')
exit(0);
else
signal(SIGINT, INThandler);
getchar();
}
int main()
{
signal(SIGINT, INThandler);
int fd[2];
char readbuffer[80];
pipe(fd);
int pid = fork();
char ch;
if(pid < 0)
{
printf("\n Erro");
exit(1);
}
else if(pid == 0)
{
close(fd[0]);
do
{
ch = getch();
write(fd[1], &ch, sizeof(ch));
} while(ch != '\n');
getchar();
}
else
{
close(fd[1]);
while(1)
{
read(fd[0], readbuffer, sizeof(readbuffer));
char upper = toupper(readbuffer[0]);
char down = tolower(readbuffer[0]);
if(readbuffer[0] != upper)
{
printf("%c \n", upper);
}
else
{
printf("%c \n", down);
}
}
}
return(0);
}
So basically this is a task that is: Using communication between processes, convert automatically upper letters to small letters, and small letters to upper letters, without them appearing in input. Basically I don't see my input just the output. And when CTRL+C is hit, the program should recognize it and ask for a confirmation by asking the user to type "y".
My program runs, but when I remove the \n from "printf("%c \n", upper);" and from "printf("%c \n", down);" the program starts acting weird... When I remove it I have to hit enter to see the output, but with it it appears automatically just like I wanted... Can someone explain me why?
I am using ubuntu.
printf doesn't actually print to stdout immediately -- it just puts characters into an output buffer to be flushed to stdout at some later point. That "later point" is generally whenever a newline is printed if the output is a terminal, but you can change that with setbuf:
setbuf(stdout, 0); // set stdout to unbuffered
after which every call to printf will immediately flush the buffer. Alternately, you can use fflush(stdout) to flush the buffer at any specific point in your program.
Problem
I'm trying to pipe contents from the main routine to a execvp'd bash shell. I'm encountering a problem where when I write "exit" into the subshell, it doesn't tell me that the pipe is really broken. It should be though - right? The process died and thus the pipe fd should also return an EOF or a SIGPIPE. It doesn't, however, and just keeps on reading/writing like normal.
Code
The code is attached here:
/************************************************************
* Includes:
* ioctl - useless(?)
* termios, tcsetattr, tcgetattr - are for setting the
* noncanonical, character-at-a-time terminal.
* fork, exec - creating the child process for part 2.
* pthread, pipe - creating the pipe process to communicate
* with the child shell.
* kill - to exit the process
* atexit - does some cleanups. Used in termios, tcsetattr,
* tcgetattr.
************************************************************/
#include <sys/ioctl.h> // ioctl
#include <termios.h> // termios, tcsetattr, tcgetattr
#include <unistd.h> // fork, exec, pipe
#include <sys/wait.h> // waitpid
#include <pthread.h> // pthread
#include <signal.h> // kill
#include <stdlib.h> // atexit
#include <stdio.h> // fprintf and other utility functions
#include <getopt.h> // getopt
/**********************
* GLOBALS
**********************/
pid_t pid;
/**********************
* CONSTANTS
**********************/
static const int BUFFER_SIZE = 16;
static const int STDIN_FD = 0;
static const int STDOUT_FD = 1;
static const int STDERR_FD = 2;
// these attributes are reverted to later
struct termios saved_attributes;
// to revert the saved attributes
void
reset_input_mode (void) {
tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes);
}
// to set the input mode to correct non-canonical mode.
void
set_input_mode (void) {
struct termios tattr;
/* Make sure stdin is a terminal. */
if (!isatty (STDIN_FILENO))
{
fprintf (stderr, "Not a terminal.\n");
exit (EXIT_FAILURE);
}
/* Save the terminal attributes so we can restore them later. */
tcgetattr (STDIN_FILENO, &saved_attributes);
atexit (reset_input_mode);
/* Set the funny terminal modes. */
tcgetattr (STDIN_FILENO, &tattr);
tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
tattr.c_cc[VMIN] = 1;
tattr.c_cc[VTIME] = 0;
tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr);
}
// pthread 1 will read from pipe_fd[0], which
// is really the child's pipe_fd[1](stdout).
// It then prints out the contents.
void* thread_read(void* arg){
int* pipe_fd = ((int *) arg);
int read_fd = pipe_fd[0];
int write_fd = pipe_fd[1];
char c;
while(1){
int bytes_read = read(read_fd, &c, 1);
if(bytes_read > 0){
putchar(c);
}
else{
close(read_fd);
close(write_fd);
fprintf(stdout, "The read broke.");
fflush(stdout);
break;
}
}
}
// pthread 2 will write to child_pipe_fd[1], which
// is really the child's stdin.
// but in addition to writing to child_pipe_fd[1],
// we must also print to stdout what our
// argument was into the terminal. (so pthread 2
// does extra).
void* thread_write(void* arg){
set_input_mode();
int* pipe_args = ((int *) arg);
int child_read_fd = pipe_args[0];
int child_write_fd = pipe_args[1];
int parent_read_fd = pipe_args[2];
int parent_write_fd = pipe_args[3];
char c;
while(1) {
int bytes_read = read(STDIN_FD, &c, 1);
write(child_write_fd, &c, bytes_read);
putchar(c);
if(c == 0x04){
// If an EOF has been detected, then
// we need to close the pipes.
close(child_write_fd);
close(child_read_fd);
close(parent_write_fd);
close(parent_read_fd);
kill(pid, SIGHUP);
break;
}
}
}
int main(int argc, char* argv[]) {
/***************************
* Getopt process here for --shell
**************************/
int child_pipe_fd[2];
int parent_pipe_fd[2];
pipe(child_pipe_fd);
pipe(parent_pipe_fd);
// We need to spawn a subshell.
pid = fork();
if(pid < 0){
perror("Forking was unsuccessful. Exiting");
exit(EXIT_FAILURE);
}
else if(pid == 0){ // is the child.
// We dup the fd and close the pipe.
close(0); // close stdin. child's pipe should read.
dup(child_pipe_fd[0]); // pipe_fd[0] is the read. Make read the stdin.
close(child_pipe_fd[0]);
close(1); // close stdout
dup(parent_pipe_fd[1]); // pipe_fd[1] is the write. Make write the stdout.
close(parent_pipe_fd[1]);
char* BASH[] = {"/bin/bash", NULL};
execvp(BASH[0], BASH);
}
else{ // is the parent
// We dup the fd and close the pipe.
//
// create 2 pthreads.
// pthread 1 will read from pipe_fd[0], which
// is really the child's pipe_fd[1](stdout).
// It then prints out the contents.
//
// pthread 2 will write to pipe_fd[1], which
// is really the child's pipe_fd[0](stdin)
// but in addition to writing to pipe_fd[1],
// we must also print to stdout what our
// argument was into the terminal. (so pthread 2
// does extra).
//
// We also need to take care of signal handling:
signal(SIGINT, sigint_handler);
/*signal(SIGPIPE, sigpipe_handler);*/
int write_args[] = {child_pipe_fd[0], child_pipe_fd[1],
parent_pipe_fd[0], parent_pipe_fd[1]};
pthread_t t[2];
pthread_create(t, NULL, thread_read, parent_pipe_fd);
pthread_create(t+1, NULL, thread_write, write_args);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
int status;
if (waitpid(pid, &status, 0) == -1) {
perror("Waiting for child failed.");
exit(EXIT_FAILURE);
}
printf("Subshell exited with the error code %d", status);
exit(0);
}
return 0;
}
The program basically pipes inputs from the terminal into the subshell and tries to execute them and return the outputs. To write to the pipe, I have a pthread that writes the stdin inputs into the subshell. To read to the pipe, I have a pthread that reads the pipe to the parent. To detect the broken pipe via the subshell dying(calling exit), I detect the EOF character from the read thread.
My attempts
I added a check for the 0x04 character(EOF), I checked for read_bytes == 0 or read_bytes < 0. It seems that it never gets the memo unless I explicitly close the pipes on the writing end. It only meets the EOF character if I send the character ^D(which, in my code, handles via closing all pipes of the child & parent).
Any comments would be appreciated! Thank you.
Your parent process is holding copies of the child's file descriptors. Thus, even after the child has exited, those FDs are still open -- so the other ends of those pipelines remain open as well, preventing any SIGPIPE.
Modify your code as follows:
else {
// pid >0; this is the parent
close(child_pipe_fd[0]); // ADD THIS LINE
close(parent_pipe_fd[1]); // ADD THIS LINE
I a beginner and I am writing a bi-direction communication programme in C, Linux for assignment submission. However, I've test and found that "enter" key is not readable via pipe as it contains 0 byte. If I accidentally press enter before normal characters are typed, the 2 screens turn to deadlock and cannot communicate. I tried getchar() or check the byte=0, but I don't know which position I should put the command to make it works. Any Ideas? Thanks
(Below is sender, I want the programme can send and receive msg)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main()
{ char pipename1[] = "/tmp/pipe1"; /* pathname of the named pipe */
char buf1[80];
char pipename2[] = "/tmp/pipe2"; /* pathname of the named pipe */
char buf2[80];
int i, n1,n2, fd1, fd2;
mkfifo(pipename1,0666);
printf("Please run receiver in other putty. \n");
fd1 = open(pipename1,O_WRONLY);
fd2 = open(pipename2,O_RDONLY);
while(1){
printf("Please enter a message. <To check message, press Enter>\n");
n1 = read(STDIN_FILENO,buf1,80); /* read a line */
if (n1 <= 0) break;
buf1[--n1] = 0;
write(fd1,buf1,n1); /* send the string */
while ((n2 = read(fd2,buf2,80)) > 0) { /* read from pipe */
buf2[n2] = 0;
printf("\n <player2> [%s] \n",buf2,n2);
break;}
}
close(fd1);
close(fd2);
unlink(pipename1);
unlink(pipename2);
exit(0); }
(Edited) Actually I created another end to read msg, code is below
int main()
{ char pipename1[] = "/tmp/pipe1"; /* pathname of the named pipe */
char buf1[80];
char pipename2[] = "/tmp/pipe2"; /* pathname of the named pipe */
char buf2[80];
int i, n1,n2, fd1, fd2;
mkfifo(pipename2,0666); /* make file with the file name defined in pipename1, 0666 is permission every one can read & write */
printf("Please run receiver programme in another browser\n");
fd1 = open(pipename1,O_RDWR);
fd2 = open(pipename2,O_RDWR);
while(1){
printf("<Please enter a message.\n");
n2 = read(STDIN_FILENO,buf2,80); /* read a line */
if (n2 <= 0) break;
buf2[--n2] = 0;
write(fd2,buf2,n2); /* send the string */
while ((n1 = read(fd1,buf1,80)) > 0) { /* read from pipe */
buf1[n1] = 0;
printf("\n <player1>[%s]\n",buf1,n1);
break;}
}
close(fd1);
close(fd2);
exit(0);
}
The problem is that you write to the pipe (using fd1) but you don't read from it. Instead you open a totally unrelated filed and attempt to read from it.
A named pipe in the file-system is the single file initialized by mkfifo, and as all other pipes it has a write-end and a read-end, and both ends are accessed by opening the same file.
In the code below, I am simply trying to send a file via stdin to a child process which will exec the cat OS command. The code compiles fine. Here is how I call it from the command line:
$ ./uniquify < words.txt
However, when I run it I get a seg fault error. I am really having a hard time understanding how the flow if information is supposed to work through pipes to children. I am trying to make the code as simple as possible, so I can understand it, but it is not yet making sense. Any help would be appreciated.
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#define NUM_CHILDREN 2
int main(int argc, char *argv[])
{
pid_t catPid;
int writeFds[NUM_CHILDREN];
int catFds[2];
int c = 0;
FILE *writeToChildren[NUM_CHILDREN];
//create a pipe
(void) pipe(catFds);
if ((catPid = fork()) < 0) {
perror("cat fork failed");
exit(1);
}
//this is the child case
if (catPid == 0) {
//close the write end of the pipe
close(catFds[1]);
//close stdin?
close(0);
//duplicate the read side of the pipe
dup(catFds[0]);
//exec cat
execl("/bin/cat", "cat", (char *) 0);
perror("***** exec of cat failed");
exit(20);
}
else { //this is the parent case
//close the read end of the pipe
close(catFds[0]);
int p[2];
//create a pipe
pipe(p);
writeToChildren[c] = fdopen(p[1], "w");
} //only the the parent continues from here
//close file descriptor so the cat child can exit
close(catFds[1]);
char words[NUM_CHILDREN][50];
//read through the input file two words at a time
while (fscanf(stdin, "%s %s", words[0], words[1]) != EOF) {
//loop twice passing one of the words to each rev child
for (c = 0; c < NUM_CHILDREN; c++) {
fprintf(writeToChildren[c], "%s\n", words[c]);
}
}
//close all FILEs and fds by sending and EOF
for (c = 0; c < NUM_CHILDREN; c++) {
fclose(writeToChildren[c]);
close(writeFds[c]);
}
int status = 0;
//wait on all children
for (c = 0; c < (NUM_CHILDREN + 1); c++) {
wait(&status);
}
return 0;
}
Since your question seems to be about understanding how pipes and forks work, I hope below programs can help you. Please notice that this is for illustration only. It wouldn't qualify for commercial implementation, but I wanted to keep it short!
You can compile the two programs as follows:
cc pipechild.c -o pipechild
cc pipeparent.c -o pipeparent
Then execute with ./pipeparent
pipeparent.c source
/* pipeparent.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define MESSAGE "HELLO!\n"
#define INBUFSIZE 80
#define RD 0 // Read end of pipe
#define WR 1 // Write end of pipe
int main(void)
{
int ptocpipe[2]; // Parent-to-child pipe
int ctoppipe[2]; // Chile-to-parent pipe
pid_t childpid; // Process ID of child
char inbuf[80]; // Input from child
int rd; // read() return
int rdup; // dup():ed stdin for child
int wdup; // dup():ed stdout for child
char *eol; // End of line
// Create pipe for writing to child
if (pipe(ptocpipe) < 0) {
fprintf(stderr, "pipe(ptocpipe) failed!\n");
return 2;
}
// Create pipe for writing back to parent
if (pipe(ctoppipe) < 0) {
fprintf(stderr, "pipe(ctoppipe) failed!\n");
return 2;
}
// Verify that one of the pipes are working by filling it first
// in one end and then reading it from the other. The OS will
// buffer the contents for us. Note, this is not at all necessary,
// it's just to illustrate how it works!
write(ptocpipe[WR], MESSAGE, strlen(MESSAGE));
read(ptocpipe[RD], inbuf, INBUFSIZE);
if (strlen(inbuf) != strlen(MESSAGE)) {
fprintf(stderr, "Failed to flush the toilet!\n");
return 6;
} else {
printf("Wrote to myself: %s", inbuf);
}
// Next, we want to launch some interactive program which
// replies with exactly one line to each line we send to it,
// until it gets tired and returns EOF to us.
// First, we must clone ourselves by using fork(). Then the
// child process must be replaced by the interactive program.
// Problem is: How do we cheat the program to read its stdin
// from us, and send its stdout back to us?
switch (childpid = fork()) {
case -1: // Error
fprintf(stderr, "Parent: fork() failed!\n");
return 3;
case 0: // Child process
// Close the ends we don't need. If not, we might
// write back to ourselves!
close(ptocpipe[WR]);
close(ctoppipe[RD]);
// Close stdin
close(0);
// Create a "new stdin", which WILL be 0 (zero)
if ((rdup = dup(ptocpipe[RD])) < 0) {
fprintf(stderr, "Failed dup(stdin)\n");
return 4;
}
// Close stdout
close(1);
// Create a "new stdout", which WILL be 1 (one)
if ((wdup = dup(ctoppipe[WR])) < 0) {
fprintf(stderr, "Failed dup(stdout)\n");
return 5;
}
// For debugging, verify stdin and stdout
fprintf(stderr, "rdup: %d, wdup %d\n", rdup, wdup);
// Overload current process by the interactive
// child process which we want to execute.
execlp("./pipechild", "pipechild", (char *) NULL);
// Getting here means we failed to launch the child
fprintf(stderr, "Parent: execl() failed!\n");
return 4;
}
// This code is executed by the parent only!
// Close the ends we don't need, to avoid writing back to ourself
close(ptocpipe[RD]);
close(ctoppipe[WR]);
// Write one line to the child and expect a reply, or EOF.
do {
write(ptocpipe[WR], MESSAGE, strlen(MESSAGE));
if ((rd = read(ctoppipe[RD], inbuf, INBUFSIZE)) > 0) {
// Chop off ending EOL
if ((eol = rindex(inbuf, '\n')) != NULL)
*eol = '\0';
printf("Parent: Read \"%s\" from child.\n", inbuf);
}
} while (rd > 0);
fprintf(stderr, "Parent: Child done!\n");
return 0;
}
pipechild.c source
/* pipechild.c
* Note - This is only for illustration purpose!
* To be stable, we should catch/ignore signals,
* and use select() to read.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#define MAXCOUNT 5 // Maximum input lines toread
#define INBUFSIZE 80 // Buffer size
int main(void)
{
char buff[INBUFSIZE];
int remains = MAXCOUNT;
pid_t mypid;
char *eol;
mypid = getpid(); // Process-ID
fprintf(stderr, "Child %d: Started!\n", mypid);
// For each line read, write one tostdout.
while (fgets(buff, INBUFSIZE, stdin) && remains--) {
// Chop off ending EOL
if ((eol = rindex(buff, '\n')) != NULL)
*eol = '\0';
// Debug to console
fprintf(stderr, "Child %d: I got %s. %d remains.\n",
mypid, buff, 1 + remains);
// Reply to parent
sprintf(buff, "Child %d: %d remains\n", mypid, 1 + remains);
write(1, buff, strlen(buff));
}
fprintf(stderr, "Child %d: I'm done!\n", mypid);
return 0;
}
I tried searching on the net, but there are hardly any resources. A small example would suffice.
EDIT
I mean, two different C programs communicating with each other. One program should send "Hi" and the other should receive it. Something like that.
A regular pipe can only connect two related processes. It is created by a process and will vanish when the last process closes it.
A named pipe, also called a FIFO for its behavior, can be used to connect two unrelated processes and exists independently of the processes; meaning it can exist even if no one is using it. A FIFO is created using the mkfifo() library function.
Example
writer.c
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd;
char * myfifo = "/tmp/myfifo";
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
/* write "Hi" to the FIFO */
fd = open(myfifo, O_WRONLY);
write(fd, "Hi", sizeof("Hi"));
close(fd);
/* remove the FIFO */
unlink(myfifo);
return 0;
}
reader.c
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
{
int fd;
char * myfifo = "/tmp/myfifo";
char buf[MAX_BUF];
/* open, read, and display the message from the FIFO */
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
close(fd);
return 0;
}
Note: Error checking was omitted from the above code for simplicity.
From Creating Pipes in C, this shows you how to fork a program to use a pipe. If you don't want to fork(), you can use named pipes.
In addition, you can get the effect of prog1 | prog2 by sending output of prog1 to stdout and reading from stdin in prog2. You can also read stdin by opening a file named /dev/stdin (but not sure of the portability of that).
/*****************************************************************************
Excerpt from "Linux Programmer's Guide - Chapter 6"
(C)opyright 1994-1995, Scott Burkett
*****************************************************************************
MODULE: pipe.c
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
char string[] = "Hello, world!\n";
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* Send "string" through the output side of pipe */
write(fd[1], string, (strlen(string)+1));
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
/* Read in a string from the pipe */
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s", readbuffer);
}
return(0);
}
dup2( STDIN_FILENO, newfd )
And read:
char reading[ 1025 ];
int fdin = 0, r_control;
if( dup2( STDIN_FILENO, fdin ) < 0 ){
perror( "dup2( )" );
exit( errno );
}
memset( reading, '\0', 1025 );
while( ( r_control = read( fdin, reading, 1024 ) ) > 0 ){
printf( "<%s>", reading );
memset( reading, '\0', 1025 );
}
if( r_control < 0 )
perror( "read( )" );
close( fdin );
But, I think that fcntl can be a better solution
echo "salut" | code
What one program writes to stdout can be read by another via stdin. So simply, using c, write prog1 to print something using printf() and prog2 to read something using scanf(). Then just run
./prog1 | ./prog2
Here's a sample:
int main()
{
char buff[1024] = {0};
FILE* cvt;
int status;
/* Launch converter and open a pipe through which the parent will write to it */
cvt = popen("converter", "w");
if (!cvt)
{
printf("couldn't open a pipe; quitting\n");
exit(1)
}
printf("enter Fahrenheit degrees: " );
fgets(buff, sizeof (buff), stdin); /*read user's input */
/* Send expression to converter for evaluation */
fprintf(cvt, "%s\n", buff);
fflush(cvt);
/* Close pipe to converter and wait for it to exit */
status=pclose(cvt);
/* Check the exit status of pclose() */
if (!WIFEXITED(status))
printf("error on closing the pipe\n");
return 0;
}
The important steps in this program are:
The popen() call which establishes the association between a child process and a pipe in the parent.
The fprintf() call that uses the pipe as an ordinary file to write to the child process's stdin or read from its stdout.
The pclose() call that closes the pipe and causes the child process to terminate.
This answer might be helpful for a future Googler.
#include <stdio.h>
#include <unistd.h>
int main(){
int p, f;
int rw_setup[2];
char message[20];
p = pipe(rw_setup);
if(p < 0){
printf("An error occured. Could not create the pipe.");
_exit(1);
}
f = fork();
if(f > 0){
write(rw_setup[1], "Hi from Parent", 15);
}
else if(f == 0){
read(rw_setup[0],message,15);
printf("%s %d\n", message, r_return);
}
else{
printf("Could not create the child process");
}
return 0;
}
You can find an advanced two-way pipe call example here.
First, have program 1 write the string to stdout (as if you'd like it to appear in screen). Then the second program should read a string from stdin, as if a user was typing from a keyboard. then you run:
$ program_1 | program_2