I'm trying to make a named pipe on c under linux using the mkfifo command. But when I run the program, I either get a "no such file or directory" error or absolutely nothing (console doesn't display anything)
Here is my code :
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define MAX_LINE 80
int main(int argc, char** argv) {
int create;
//mkfifo("/tmp/myfifo", 0666);
create = mkfifo("tmp/myfifo", 0666);
if (create==-1)
{
printf("error%s", strerror(errno));
}
char line[MAX_LINE];
int pipe;
pipe = open("/tmp/myfifo", O_WRONLY);
if (pipe==-1)
{printf("error");
}
printf("Enter line: ");
fgets(line, MAX_LINE, stdin);
write(pipe, line, strlen(line));
sleep (100);
close(pipe);
return 0;
}
I am still learning, and I don't understand what i'm doing wrong. Thanks for your help.
For a named pipe to be useful, somebody has to read it and somebody has to write it. Usually this will be 2 separate programs. Your program is the writer. Where is the reader?
If there is no reader, it is normal for the program to block on the O_WRONLY open. So when your program appears to be doing nothing, it's really just doing this:
pipe = open("/tmp/myfifo", O_WRONLY);
which waits for a reader to show up.
In another terminal, run cat /tmp/myfifo. The presence of a reader will allow the writer to make progress. Your program will wake up and move on to the Enter line prompt, and what you enter will be read by the cat and written to the second terminal.
The other problem is an inconsistency in your filenames. In one place you wrote "tmp/myfifo" without a leading slash, so you are trying to create the named pipe in a tmp directory that is inside the current working directory. If that tmp directory doesn't exist, No such file or directory will be the result.
Related
I have the following code(there's a bunch of extra headers that were used in other parts of the code that I removed since they don't have anything to do with my issue). I have also removed the error checking for fork and pipe for brevity:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
void compile(char *fullname)
{
int pid = fork();
int pipe_send_output[2];
pipe(pipe_send_output);
if (pid == 0)
{
close(pipe_send_output[0]);
dup2(pipe_send_output[1], STDERR_FILENO); // redirect output of gcc to the pipe
execlp("gcc", "gcc", "-Wall", fullname, NULL);
printf("execlp error");
}
else
{
close(pipe_send_output[1]);
dup2(STDIN_FILENO, pipe_send_output[0]); // redirect from pipe to stdin
close(pipe_send_output[0]);
exit(0);
}
}
int main(){
compile("folder/small.c");
}
The compile function is supposed to create a new process which compiles some c file using gcc, and then sends the output(errors and warnings) to the parent process, to be printed. To do this I redirected STDERR to the write end of the pipe, and then in the parent process redirected the read end to stdin. I can't for the life of me figure out why it's not displaying anything. If I remove the redirection of stderr to the pipe, then plenty of stuff it outputed, so the issue isn't gcc not outputting anything. I tried to replace the redirection to stdin with reading from the pipe and then printing it, but that has the same result. A couple of time this did print one or 2 characters, which is even more confusing. This is the code that replaces the second call to dup2 for printing:
char buffer[1024];
while(read(pipe_send_output[0], buffer, 1024)) printf("%s", buffer);
I've looked everywhere on google and on the man page and still don't have a clue what's wrong.
Disclaimer:This is part of a project for a lab at university. The code that I wrote follows the blueprint from the materials my professor provided, and makes perfect sense to me. Any hint on what the issue may be is appreciated.
So I have an exercise to do, and one part of this exercise requires us to execute a command passed as an argument, be able to pass it some strings on stdin, and get its output on stdout and stderr.
How I did it, I need to redirect the stdout and stderr (of the child, which is gonna call an exec) to a couple of pipes (other end of the pipes is held open by the parent).
I managed to do it, when I ask it to execute bash and send it "ls", it gives me what i want, where i want it. Same with cat and others.
Problem is, when I try executing awk or sed, nothing is ever written on the pipe. Ever.
If i leave stdout untouched, it does print it how it should. But as soon as i redirect the stdout, nothing.
I tried everything, select(), wait(), sleep() (even though it's not allowed). Nothing seems to work.
I made a minimum working example of what i mean (clearly, it lacks of conventions and mindful writing, as free() and close(), but it does it's job) which Is the one I'm attaching. The code works when i call it like this:
./program $(which bash)
It prompts for something, i write "ls" and it gives me the result expected
but when i try
./program $(which awk) '{print $0;}'
I get nothing at all
Here's the code (minimum working example):
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
int main(int argc, char* argv[]){
int fdStdinP[2],fdStdoutP[2];
char *string,*array[3];
array[0]=argv[1];
array[1]=argv[2];
array[2]=0;
pipe(fdStdinP);
pipe(fdStdoutP);
int pid=fork();
if(pid==0){
close(fdStdinP[1]);
close(fdStdoutP[0]);
dup2(fdStdinP[0],0);
close(fdStdinP[0]);
dup2(fdStdoutP[1],1);
close(fdStdoutP[1]);
//as suggested, the file descriptors are now closed
execvp(argv[1],array);
perror("");
return 0;
}
close(fdStdinP[0]);
close(fdStdoutP[1];
string=calloc(1024,sizeof(char));
read(0,string,1024);
write(fdStdinP[1],string,1024);
free(string);
string=calloc(1024,sizeof(char));
read(fdStdoutP[0],string,1024);
printf("I have read:%s",string);
return 0;
}
Thank you for your time.
Awk continues to wait for input and buffers its output, so appears to hang. Closing the sending end will tell awk that it's input has ended so that it will end and flush its output.
write(fdStdinP[1],string,1024);
close(fdStdinP[1]); // just added this line.
More specifically, the program is supposed to emulate the bash command cat file| grep $keyword > file.
What I've done is: In the parent I read every character from the file and format them into lines which I then send to the named pipe, then in the child write the lines containing the keyword into the original file.
However, I receive a segmentation fault error when attempting to read the second character from the original file, which I assume is because the parent is waiting for the child to write in the original file instead of instead of reading the contents of said file.
Any help with the implementation/explanation of why exactly the error occurs would be great.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
char key[20], *c,line[40];
int fd,fd_r,fd_w,fd_fr,fd_fw,counter=0;
int main(){
pid_t pid;
mkfifo("fifo1",0777);
fgets(key,10,stdin);
int k=0;
if ((pid=fork()) < 0)
perror("err_fork");
if(pid){ //PARENT
printf("%d\n",fd_r=open("prog.c",O_RDONLY));
printf("%d\n",fd_fw=open("fifo1",O_WRONLY));
while(read(fd_r,c,1)){
line[k++]=(*c);
while(read(fd_r,c,1) && ((*c)!='\n'))
line[k++]=(*c);
line[k]=0;
write(fd_fw,line,strlen(line)+1);
memset(line,0,sizeof(line));
}
close(fd_r);
close(fd_fw);
}
else{ //CHILD
printf("%d\n",fd_w=open("prog.c",O_WRONLY));
printf("%d\n",fd_fr=open("fifo1",O_RDONLY));
while(read(fd_fr,line,sizeof(line))){
c=strstr(line,key);
if(c)
write(fd_w,line,strlen(line)+1);
}
close(fd_w);
close(fd_fr);
}
unlink("fifo1");
}
You're segfaulting because you're trying to read a byte into c. However, c is an uninitialized global pointer and thus it's equal to NULL. Trying to read data at that location is therefore an invalid use of memory.
What you do instead is declare
char c;
and then
read(fd_r,&c,1)
I am using a library that prints all kind of crappy messages to stdout. I try to keep a clean output on my program, but that makes it impossible.
Any idea?
You can close() the stdout socket and then open a new socket to /dev/null (assuming pretty much anything but windows here).
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int newfd;
printf("good things come...\n");
close(1);
newfd = open("/dev/null", O_WRONLY);
if (newfd != 1) {
fprintf(stderr, "uh oh... we didn't duplicate the socket properly\n");
exit(1);
}
printf("...to those that wait()\n");
}
And then running this you get:
$ ./test
good things come...
Note the no final line from printf.
[but I agree with the comments: using libraries that show signs of bad-things is probably a bad-choice for other reasons beyond the first one you spot]
I want to use a pair of Unix FIFOs in such manner that:
a client sends to a server a file name and
the server returns to the client: the number of words, lines and bytes from the given file.
Could you please help?
client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int nr,s2c,c2s,c,d,e;
char a[20];
c2s=open("fifo1",O_WRONLY);
s2c=open("fifo2",O_RDONLY);
printf("give file name \n");
scanf("%s",a);
nr=strlen(a);
write(c2s,&nr,sizeof(int));
write(c2s,&a,sizeof(nr));
read(s2c,&c,sizeof(int));
read(s2c,&d,sizeof(int));
read(s2c,&e,sizeof(int));
close(c2s);
close(s2c);
return 0;
}
server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int nr,s2c,c2s,c,d,e;
char a[20];
FILE* f;
c2s=open("fifo1",O_RDONLY);
s2c=open("fifo2",O_WRONLY);
read(c2s,&nr,sizeof(int));
read(c2s,&a,sizeof(nr));
f=fopen(a,"r");
if(fork()==0)
{
printf("result is: \n");
execl("/usr/bin/wc","wc",c,d,e,NULL);
}
wait(0);
write(s2c,&c,sizeof(int));
write(s2c,&d,sizeof(int));
write(s2c,&e,sizeof(int));
close(c2s);
close(s2c);
printf("\n FINISH \n");
return 0;
}
I have done some improvements but still it doesn't work properly.
In the fork'ed part of the server, redirect the standard input and output of wc with
dup2(c2s, STDIN_FILENO);
dup2(s2c, STDOUT_FILENO);
Then exec it with
execl("/usr/bin/wc", "wc", NULL);
Don't pass the file descriptors as arguments to execl. It expects strings (char const*), not int.
See dup2 in the POSIX standard to understand how this works.
Note that wc writes strings of characters to its output. You are trying to read them as if they are binary numbers. This will lead to confusion - especially as you do not check that the read calls worked correctly.
Actually, general comment - you should check many more of your system calls.
You also have to ensure that your processes do not block when opening the FIFOs. You should be OK; you have the processes open 'fifo1' for reading and writing, and then 'fifo2'. I think that forces a correct order on things.
You only write 4-letter file names correctly on the pipe.