Pipe cannot read Enter key (C , Linux) - c

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.

Related

Use read() to get the name of a file from a pipe and open() it in c

This is all done on a linux machine.
I have a pipe, fp, sending from the parent to the child the name of a file using a buffer.
The buffer is:
char buf[20];
the child has the following code:
{
//we are in the child
close(fp[1]);
int fd;
read(fp[0],buf,20);
if((fd=(open(buf, O_RDONLY)))==-1) exit(1);
else exit(0);
close(fp[0]);
}
Even if I type in the name of a file that exists, I'm getting the exit status of 1. So...
this unfortunately doesn't work. The issue is that the buff itself not only does '\n', but also also plenty of '\0', all of which don't actually exist in the name of real file. I've tried replacing the '\n' with a '\0' but that also doesn't work. How can I solve this?
Here's the whole code.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
int main(){
int fp[2];
if (pipe(fp) < 0){
printf("error creating pipe\n");
exit(-1);
}
int id;
char buf[20];
id=fork();
//father process here --------------------------------
if (id!=0){
close(fp[0]); //closing read
printf("program name: ");
fflush(stdout);
read(STDIN_FILENO,buf,20);
write(fp[1],buf,20);
int waitstatus, exitcode;
wait(&waitstatus);
//check if exited correctly
if (WIFEXITED(waitstatus))
exitcode = WEXITSTATUS(waitstatus);
else
{
printf("Bad exit\n");
return 0;
}
if (exitcode==1) printf("error, file doesn't exist\n");
else printf("file does exist\n");
close(fp[1]);
}
//child process here --------------------
else{
close(fp[1]); //closing write
int fd;
read(fp[0],buf,20);
//write(STDOUT_FILENO, buf, 20);
if((fd=(open(buf, O_RDONLY)))==-1) exit(1);
exit(0);
close(fp[0]);
}
}
You send the full buf which contains a newline and other indeterminate values. You need to remove the newline and I suggest that you only send what you need on the receiving end.
printf("program name: ");
fflush(stdout);
if(fgets(buf, sizeof buf, stdin)==NULL) return 1;
size_t len = strlen(buf);
buf[len - 1] = '\0'; // remove the newline
write(fp[1], buf, len); // only send what you actually need

How can i print every string in C pipes

How can i print every string in C pipes i am stuck.
output like this
Received string: spike
Received string: spike
Received string: spike
but i want like this
Received string: spike
Received string: tom
Received string: jerry
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
char string[3][10] = {
"spike",
"tom",
"jerry"};
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));
for (int i = 0; i < 3; i++)
{
printf("Received string: %s \n", readbuffer);
}
}
return (0);
}
You've made several mistakes.
First of all, the child doesn't write the correct thing into the pipe.
Then you read() a 80 byte buffer, which will contain all 3 strings (asuming you've fixed issue 1). But since you write one byte more than the string is long, you'll have a zero byte in the middle of your readbuffer. Any attempt to print that will simply stop at that zero byte.
It'll be important to add error handling. You can never ever assume that a read or write will be successful.
I've modified your code a little, such that it works better (but not right yet):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
/* added newlines to separate the entries when printing */
char string[3][10] = {
"spike\n",
"tom\n",
"jerry\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 */
/* Added a loop here, so all 3 entries are written */
for (int i = 0; i < 3; ++i) {
write(fd[1], string[i], (strlen(string[i])));
}
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
/* Read in a string from the pipe */
/* no loop needed here for now
But you'd need to read until you reach EOF.
I leave that as an exercise
*/
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
readbuffer[nbytes] = '\0';
printf("Received string: %s \n", readbuffer);
}
return(0);
}

How to pipe stdin to a child and execl cat in C

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;
}

How to send a simple string between two programs using pipes?

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

How to output to a file with information from a pipe in C?

I'm confused about what I'm doing wrong when I'm attempting to output to a file after I've execed a second program.
Say I have input file that has the following names:
Marty B. Beach 7 8
zachary b. Whitaker 12 23
Ivan sanchez 02 15
Jim Toolonganame 9 03
After my programs finish, it will convert the student's names to their usernames and output it to a file such as this:
mbb0708
zbw1223
is0215
jt0903
Currently as my program stands, it outputs nothing to the file and the terminal seems to be in an infinite loop despite self testing my converter program before and making sure it outputs names correctly to stdout.
I'm not sure what I'm doing wrong here? First time programming with pipes. I know have to make use of the read and write commands extract the data, but with the dup2 command is that necessary for the read command alone?
manager.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc, char** argv)
{
pid_t pid;
int nbytes;
/*Buffer to hold data from pipe*/
char buffer[BUFSIZ + 1];
/*Pipe Information*/
int commpipe[2];
if(pipe(commpipe))
{
fprintf(stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
if((pid = fork()) == -1)
{
fprintf(stderr,"Fork error. Exiting.\n");
exit(1);
}
else if(pid == 0)
{
/*This is the child process. Close our copy of the write end of the file descriptor.*/
close(commpipe[1]);
/* Connect the read end of the pipe to standard input*/
dup2(commpipe[0], STDIN_FILENO);
/*Program will convert the Student's name to their respective names*/
execl("converter","converter",NULL);
/*Exit if failure appears*/
exit(EXIT_FAILURE);
}
else
{
FILE *file;
file = fopen("usernames.txt","a+"); //append a file(add text to a file or create a file it does not exist)
/*Close or copy of the read end of the file descriptor */
//close(commpipe[1]);
nbytes = write(commpipe[1], buffer, BUFSIZ);
//Read from pipe here first?
//Output to usernames.txt the usernames of the user from the pipe.
fprintf(file, "%s", buffer);
/*Wait for the child process to finish*/
waitpid(pid, NULL, 0);
}
return 0;
}
One problem is that after manager has sent all the data to converter, the manager is not closing commpipe[1]. Because of that, converter will never get EOF on stdin so will not exit.
Most likely manager isn't getting any data back from converter due to buffering. Some implementations of stdio use full-buffer buffering (as opposed to line-buffering) when not writing to a terminal. Once you fix the previous error and get the process to close, that will flush stdout. You can also consider adding fflush(stdout) after your puts line.
Have a look at the OpenGroup site, there's an example that looks similar to yours. I suggest you get the sample working first with some hard coded. Once that is working, add the code to read and write the results.
I made some minor changes to get the example working:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
int main(int argc, char** argv){
int fildes[2];
const int BSIZE = 100;
char buf[BSIZE];
ssize_t nbytes;
int status;
status = pipe(fildes);
if (status == -1 ) {
/* an error occurred */
printf("Error!\n");
exit(-1);
}
printf("Forking!\n");
switch (fork()) {
case -1: /* Handle error */
printf("Broken Handle :(\n");
break;
case 0: /* Child - reads from pipe */
printf("Child!\n");
close(fildes[1]); /* Write end is unused */
nbytes = read(fildes[0], buf, BSIZE); /* Get data from pipe */
/* At this point, a further read would see end of file ... */
assert(nbytes < BSIZE); /* Prevent buffer overflow */
buf[nbytes] = '\0'; /* buf won't be NUL terminated */
printf("Child received %s", buf);
close(fildes[0]); /* Finished with pipe */
fflush(stdout);
exit(EXIT_SUCCESS);
default: /* Parent - writes to pipe */
printf("Parent!\n");
close(fildes[0]); /* Read end is unused */
write(fildes[1], "Hello world\n", 12); /* Write data on pipe */
close(fildes[1]); /* Child will see EOF */
/* Note that the Parent should wait for a response from the
child here, because the child process will be terminated once
the parent exits */
exit(EXIT_SUCCESS);
}
return 0;
}
As I understand, your converter program reads lines from stdin and writes them to stdout. As a pipe is a uni-directional entity, you will need TWO of them to communicate with the manager - one to send data to the converter and one to receive output from it.
Maybe you should consider enhancing the converter to take (as optional arguments) the name of an input and output file.

Resources