I am trying to have a process read both from a named pipe and some unnamed pipes. First I have a main process that creates a child process and then initializes a named pipe that waits for data from the terminal to send to the named pipe:
int main(){
signal(SIGINT, sigint);
if(fork()==0){
newProcess();
exit(0);
}
unlink(PIPE_NAME);
printf("Creating named pipe.\n");
if ((mkfifo(PIPE_NAME, O_CREAT|O_EXCL|0600)<0) && (errno!= EEXIST)) {
perror("Cannot create pipe: ");
exit(0);
}
printf("Named pipe created.\n");
int named_pipe_fd;
printf("Opening named pipe.\n");
if ((named_pipe_fd = open(PIPE_NAME, O_WRONLY)) < 0) {
perror("Cannot open pipe for writing: ");
exit(0);
}
printf("Named pipe open.\n");
char toSend[512];
//Sends data via the NAMED pipe to our child process
while(1){
scanf("%[^\n]%*c", toSend);
printf("[RaceSimulator] Sending (%s)\n",toSend);
write(named_pipe_fd, toSend, sizeof(toSend));
}
return 0;
}
The child process opens the named pipe into reading mode and creates an array full of file descriptors that wait for information to come their way. For now I have the unnamed pipes not created yet and so, their value in the array is -1:
void newProcess(){
//Initialize the pipes
for(int i=0;i<MAX;i++){
pipes[i]=-1;
}
//OPEN NAMED PIPE FOR READING
int fd;
if ((fd= open(PIPE_NAME, O_RDONLY)) < 0) {
perror("Cannot open pipe for reading: ");
exit(0);
}
pipes[0]=fd;
char received[512];
//Loop that waits for data to appear in the pipes
while(1){
fd_set read_set;
FD_ZERO(&read_set);
for (int channel=0;channel<MAX;channel++) {
FD_SET(pipes[channel], &read_set);
}
if (select(pipes[MAX-1]+1, &read_set, NULL, NULL, NULL) > 0 ) {
if (FD_ISSET(pipes[0], &read_set)) {
read(pipes[0],received,sizeof(received));
printf("[Named pipe] Received %s.\n",received);
}
//Unamed pipes are still not created!
for (int channel=1;channel<MAX;channel++) {
if (FD_ISSET(pipes[channel], &read_set)) {
read(pipes[channel],received,sizeof(received));
printf("[Unamed pipe] Received %s.\n",received);
}
}
}
}
}
The problem, is that when I write on the terminal, the terminal writes back only the printf of the main process. This means that nothing is being sent to the other side of the named pipe but I do not understand why. Here is the whole code (NOTE: this is a snippet, for legal reasons I cannot send the original code, also I know I have too many includes in this snippet :P):
#define PIPE_NAME "pipe"
#define MAX 5
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <sys/stat.h>
int pipes[MAX];
void clean(){
unlink(PIPE_NAME);
}
void sigint(int signum){
clean();
exit(0);
}
void newProcess(){
//Initialize the pipes
for(int i=0;i<MAX;i++){
pipes[i]=-1;
}
//OPEN NAMED PIPE FOR READING
int fd;
if ((fd= open(PIPE_NAME, O_RDONLY)) < 0) {
perror("Cannot open pipe for reading: ");
exit(0);
}
pipes[0]=fd;
char received[512];
//Loop that waits for data to appear in the pipes
while(1){
fd_set read_set;
FD_ZERO(&read_set);
for (int channel=0;channel<MAX;channel++) {
FD_SET(pipes[channel], &read_set);
}
if (select(pipes[MAX-1]+1, &read_set, NULL, NULL, NULL) > 0 ) {
if (FD_ISSET(pipes[0], &read_set)) {
read(pipes[0],received,sizeof(received));
printf("[Named pipe] Received %s.\n",received);
}
//Unamed pipes are still not created!
for (int channel=1;channel<MAX;channel++) {
if (FD_ISSET(pipes[channel], &read_set)) {
read(pipes[channel],received,sizeof(received));
printf("[Unamed pipe] Received %s.\n",received);
}
}
}
}
}
int main(){
signal(SIGINT, sigint);
if(fork()==0){
newProcess();
exit(0);
}
unlink(PIPE_NAME);
printf("Creating named pipe.\n");
if ((mkfifo(PIPE_NAME, O_CREAT|O_EXCL|0600)<0) && (errno!= EEXIST)) {
perror("Cannot create pipe: ");
exit(0);
}
printf("Named pipe created.\n");
int named_pipe_fd;
printf("Opening named pipe.\n");
if ((named_pipe_fd = open(PIPE_NAME, O_WRONLY)) < 0) {
perror("Cannot open pipe for writing: ");
exit(0);
}
printf("Named pipe open.\n");
char toSend[512];
//Sends data via the NAMED pipe to our child process
while(1){
scanf("%[^\n]%*c", toSend);
printf("[RaceSimulator] Sending (%s)\n",toSend);
write(named_pipe_fd, toSend, sizeof(toSend));
}
return 0;
}
Any help would be greatly appreciated!
The first argument to select should be the highest numbered file descriptor in the set. Since you've initialized them all to -1, except the zeroth, this call:
select(pipes[MAX-1]+1, &read_set, NULL, NULL, NULL)
will not work. You need to change that to:
select(fd+1, &read_set, NULL, NULL, NULL)
Or, once you've created the others, the highest among them.
Related
I am writing a simple code to implement the indirect input function for a unix/linux shell.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
extern void error(char* message);
void
cisshRedirectedInput(char* command[], char* inputFile)
{
//Try to implement the RedirectInput from here
pid_t pid;
int status;
int fd;
//For the child process
if ((pid=fork())==0)
{
//Try to input files, failing on an error
fd=open(inputFile,O_RDONLY);//To read input file
if(fd < 0)
{
error("sampleSh: error opening standard input file");
exit(1);
}
//use dup() to copy file
close(1);
if(dup(fd) < 0)
{
error("sampleSh: error duplicating standard input");
perror("dup()");
exit(1);
}
//Close file and exec()
close(fd);
execvp(command[0], command);
//If failure in any case
error("sampleSh: failure to execute command");
exit(1);
}
else
{
/* This is the parent process.
* Wait for the child to terminate.
*/
if(wait(&status) < 0)
{
error("sampleSh: error waiting for child.");
perror("wait");
}
if(status != 0)
error("sampleSh: command exited with nonzero error status.");
}
}
However, after compilation (no error reported), but when I try (fileList created already)
sort -r <fileList
The shell just stuck there without giving me answer, what is the problem please?
The standard input file descriptor is 0 (or STDIN_FILENO), not 1 (or STDOUT_FILENO).
Either use:
int fd = open(inputFile, O_RDONLY);
if (fd < 0) …
close(0);
if (dup(fd) < 0) …
close(fd);
Or:
int fd = open(inputFile, O_RDONLY);
if (fd < 0) …
if (dup2(fd, 0) < 0) …
close(fd);
It is good that your code does the close(fd) after duplicating to a standard I/O descriptor — that is almost always correct. It's also good that you are checking that the key system calls succeed. (There isn't much you can do if close() fails.)
This simple modification of your code (key change: use close(0); instead of close(1);) works for me. Did you null terminate your argument list?
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
static inline void error(char *message)
{
fprintf(stderr, "%s\n", message);
}
void
cisshRedirectedInput(char *command[], char *inputFile);
void
cisshRedirectedInput(char *command[], char *inputFile)
{
// Try to implement the RedirectInput from here
pid_t pid;
int status;
int fd;
// For the child process
if ((pid = fork()) == 0)
{
// Try to input files, failing on an error
fd = open(inputFile, O_RDONLY); // To read input file
if (fd < 0)
{
error("sampleSh: error opening standard input file");
exit(1);
}
// use dup() to copy file
close(0);
if (dup(fd) < 0)
{
error("sampleSh: error duplicating standard input");
perror("dup()");
exit(1);
}
// Close file and exec()
close(fd);
execvp(command[0], command);
// If failure in any case
error("sampleSh: failure to execute command");
exit(1);
}
else
{
/* This is the parent process.
* Wait for the child to terminate.
*/
if (wait(&status) < 0)
{
error("sampleSh: error waiting for child.");
perror("wait");
}
if (status != 0)
error("sampleSh: command exited with nonzero error status.");
}
}
int main(void)
{
char *args[] = { "sort", "-r", 0 };
cisshRedirectedInput(args, "fileList");
return 0;
}
Input file:
bash-assoc-arrays.sh
cissh.c
fileList
kwargs.py
makefile
posixver.h
rangeinc.c
select.c
spc.py
testcsv.py
uncrustify.bug
yield.py
Output:
yield.py
uncrustify.bug
testcsv.py
spc.py
select.c
rangeinc.c
posixver.h
makefile
kwargs.py
fileList
cissh.c
bash-assoc-arrays.sh
I am having a trouble using fifos, i want the parent to create 2 fifos and wait for child to write its user entered date, time and system date and time along with uid to fifo 1 and once it has received this parent has to then opens a log file and writes the contents to log file and fifo2 as well. and the child will read the fifo2 and display the result
#include<stdio.h>
#include<fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<time.h>
int main()
{
int pid;
char buff[64];
int ret,ret2;
FILE *cfp;
char fifoName[]="/tmp/testfifo23";
char fifoName2[]="/tmp/testfifo22";
FILE *cfp2;
FILE *pfp2;
char array[36],bufftime[36],buffread[64];
FILE *pfp,*pfp2;
//Time Calculation
time_t rawtime;
time (&rawtime);
struct tm *timeinfo = localtime (&rawtime);
strftime(array, sizeof(array)-1, "%d.%m.%y %H:%M:%S", timeinfo);
//
if((pid=fork())>=0)
{
if(pid==0) //child Process
{
ret2 = mknod(fifoName, S_IFIFO | 0600, 0);
if(ret < 0)
{
printf("Unable to create fifos");
exit(0);
}
ret2 = mknod(fifoName2, S_IFIFO | 0600, 0);
if(ret2 < 0)
{
printf("Unable to create fifos");
exit(0);
}
}
else
{
sleep(3);
printf("Enter The date");
if((fgets(buff,8,stdin)!=NULL))
{
printf("Job done %s",buff);
}
printf("\n Enter The time");
if((fgets(bufftime,8,stdin)!=NULL))
{
printf("\nJob done %s",bufftime);
}
cfp = fopen(fifoName,"w");
if(cfp == NULL)
{
printf("Unable to open fifo for writing");
exit(0);
}
ret=fprintf(cfp,"%s %s %s %u",buff,bufftime,array,getuid());
// fflush(cfp);
unlink(fifoName);
//close(fifoName);
cfp2= fopen(fifoName2,"r");
if(cfp2 == NULL)
{
printf("Unable to open fifo for reading");
exit(0);
}
ret=fscanf(cfp2,"%s",&buffread);
if(ret < 0)
printf("Error reading from named pipe");
fclose(cfp2);
printf("%s",buffread);
unlink(fifoName); /* Delete the created fifo */
unlink(fifoName2);
exit(0);
}
else
{
printf("Error Occured");
}
return 0;
}
// Enter code here
In the code you have submitted, the child process only opens two named pipes and exists. If you indent your code properly you will realise the problem. Also you would like to use "pipe()" for such application.
Question asked again and code modified...
I need to create three programs named as program0 program1 and program2 in linux.
Program0:Creates a parent with two child processes and executes program 1 and program 2 with its childs waits them to finish and close.
Program1:Takes a file name from the user and writes text to the file.It finishes writing when CTNL+D pressed and creates a pipe.After that by using cat command it writes file to stdout and uses dup() to create pipe which has file in it.
Program2:It reads filename from the pipe with the help of dup() and then executes wc command.
So far I managed to create all programs and I have no compling errors.Program 0 executes both programs.Program1 is also working and sends file to the pipe but program2 cannot read it from the pipe is prints weird symbols..
When I try to read from the pipe within the program1 it works(see the deactivated code in program1) but same code is not working if I put it inside program2.
So what how can I make program2 to read from the pipe after that I will try to execute wc command in program2 but first I should be able to see that its taking file input from the stdout so how?
I know its kinda long but please help me guys...
Program 0
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#define MAX 999
int main()
{
pid_t pid1, pid2;
pid1 = fork();
if(pid1<0)
{
fprintf(stderr,"Fork basarisiz");
exit(-1);
}
else if (pid1 ==0)/*child prosesleri*/
{
printf("program1\n");
execlp("./program1","program1",NULL);
execlp("./program2","program2",NULL);
}
else /*parent procsesleri */
{
wait(NULL);
pid2 = fork();
if(pid2<0)
{
fprintf(stderr,"Fork basarisiz");
exit(-1);
}
else if (pid2 ==0)/*child prosesleri*/
{
printf("\n");
printf("Program 2\n");
printf("\n");
execlp("./program2","program2",NULL);
//printf("\n");
}
else
{
}
/////////////////////////////////////////////////////////////////////////
wait(NULL);
printf("\n");
printf("Parent:Two child processes have successfully been created\n");
printf("Parent:Two child processes have successfully been terminated\n");
printf("Parent:This process will now terminate\n");
printf("\n");
exit(0);
}
}
Program 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX 999
int main()
{
char c[10000];
char file[10000];
int words;
printf("Child1:A text file will be created\n");
printf("Child1:Enter the name of the file\n");
scanf("%123s",file);
strcat(file,".txt");
FILE * pf;
pf = fopen(file, "w" );
if (!pf)
fprintf( stderr, "I couldn't open the file.\n" );
else
{
printf("Child1: Input a number of text lines ended, each ended by a CR (carriage return).\n");
/////////////////////////////
do
{
if (NULL != fgets(c, sizeof(c), stdin))
{
if (0 == strcmp(c, ".\n"))
{
break;
}
fprintf(pf, "%s", c);
}
else
{
if (0 != ferror(stdin))
{
fprintf(stderr, "An error occured while reading from stdin\n");
}
else
{
printf("Child1: Finish the input by CNTL^D\n");
}
break;
}
} while (1);
/////////////////////////////
}
printf("\nChild1:The file %s is succesfully created and saved in the current dictionary\n",file);
//////////////////////////////////////////////
/////////////////////////pipe///////////////
fclose(pf); // close file
char ch;
int outcount = 0;
int fd[2], nbytes;
pid_t childpid;
int i;
char f2[2];
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{ printf("\nChild1:The file written to pipe with cat\n");
close(1) ;
dup(fd[1]);
close(fd[0]);
execlp("/bin/cat", "cat", file,NULL);
}
else
{
wait(NULL);
//close(0) ;
//dup(fd[0]) ;
//close(fd[1]);
//nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
//printf("%s\n",readbuffer);
}
return(0);
}
Program 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd[2],nbytes;
pid_t childpid;
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
}
else
{
close(0) ;
dup(fd[0]) ;
close(fd[1]);
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("%s\n",readbuffer);
}
return(0);
}
You may want to check the man pages for execve(2) (for starting cat) and dup2(2) (for overriding stdin and stdout as needed) for this one. execve will overwrite the currently executing program by a different one (same PID, same file descriptors), while dup2 will allow you re-define any of the standard file descriptors to point into any file descriptor you provide to it (such as any of the ends of your pipe).
I am very new to C and am trying to learn how to use pipes to transfer data from a parent process to a child process and vice versa in a Unix environment. In the code below, I receive a command line argument and build a char array based on the argument's value. I then use pipes to pass the char array to a child which will execute a program called vc. This program returns a number result based on the char array. My question is how can I use a second pipe to get the result back to the parent? Also, once the parent has it, how can I print it to the screen since the parent is set to send output to the child? Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc,char *argv[])
{
int
pfildes[2],
pid,
argNumber;
char
buffer[256],
charString[1024];
//Check for arguments
if(argc != 2) {
printf("No command line arguements given.\n");
argNumber=10; //default
}
else
argNumber=atoi(argv[1]);
//***********************************
//Build charString based on argNumber
//***********************************
//create pipes
if(pipe(pfildes) == -1) {
//error occured when creating pipe
perror("demo");
exit(1);
}
//create child process
if((pid=fork()) < 0) {
//error occured when forking child
perror("demo");
exit(1);
}
else if(pid > 0) {
//parent process
close(pfildes[0]);
dup2(pfildes[1],1);
printf("%s", charString);
close(pfildes[1]);
perror("demo");
_exit(1);
}
else {
//child process
close(pfildes[1]);
dup2(pfildes[0],0);
execlp("/usr/bin/vc","vc", NULL);
close(pfildes[0]);
perror("demo");
exit(1);
}
while(wait(NULL) >0);
return 0;
}
You can use socketpair() instead of pipe() to generate a bidirectional communication channel between the parent and child process:
//...
if (socketpair(PF_UNIX, SOCK_STREAM, 0, pfildes) == -1) {
//error occured when socket pair
perror("demo: socketpair");
exit(1);
}
//..
In the child process, you can dup() one of the pair into both input and output before calling exec():
//...
else {
//child process
close(pfildes[1]);
dup2(pfildes[0],0);
dup2(pfildes[0],1);
dup2(pfildes[0],2);
close(pfildes[0]);
execlp("/usr/bin/vc","vc", NULL);
perror("demo: child exec");
exit(1);
}
//...
In the parent process, you can create a FILE * from a file descriptor using fdopen(), so you don't need to dup() over your existing stdout file descriptor:
//...
else if(pid > 0) {
//parent process
close(pfildes[0]);
FILE *to_child = fdopen(dup(pfildes[1]), "w");
FILE *from_child = fdopen(dup(pfildes[1]), "r");
close(pfildes[1]);
fprintf(to_child, "%s", charString);
while (fgets(buf, sizeof(buf), from_child) != NULL) {
//...do something with output
}
//...
} else { //...
I need to write program that have construction like this:
Parent makes fifo, then fork()
child 1 reads message from stdin and writes it to named pipe (FIFO)
then in parent process I need to create pipe (unnamed) and another fork()
child number 2 reades from FIFO, counts length of message and send number to parent via pipe(unnamed).
I created a simple program with one fork where child can communicate with parent:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO "/tmp/my_fifo"
int main()
{
pid_t fork_result;
int pipe_fd;
int res;
char writer[3];
char reader[3];
res = mkfifo(FIFO,0777);
if (res == 0)
{
printf("FIFO created!\n");
fork_result = fork();
if (fork_result == -1)
{
fprintf(stderr, "fork error");
exit(EXIT_FAILURE);
}
if (fork_result == 0)
{
printf("CHILD 1\n");
pipe_fd = open(FIFO, O_WRONLY | O_NONBLOCK);
scanf("%s", writer);
res = write(pipe_fd,writer,3);
if (res == -1)
{
fprintf(stderr,"error writing fifo\n");
exit(EXIT_FAILURE);
}
(void)close(pipe_fd);
exit(EXIT_SUCCESS);
}
else
{
printf("PARENT\n");
pipe_fd = open(FIFO, O_RDONLY);
res = read(pipe_fd, reader, 3);
printf("reader: 0: %c\n",reader[0]);
printf("reader: 1: %c\n",reader[1]);
printf("reader: 2: %c\n",reader[2]);
(void)close(res);
}
}
else
{
printf("deleting fifo... run program again!\n");
unlink(FIFO);
}
exit(EXIT_SUCCESS);
}
and it is working very well. So I created code that have architecture described above:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO "/tmp/my_fifo"
int main()
{
pid_t fork_result;
pid_t fork_result2;
int pipe_fd;
int res;
char writer[3];
char reader[3];
res = mkfifo(FIFO,0777);
if (res == 0)
{
printf("FIFO created!\n");
fork_result = fork();
if (fork_result == -1)
{
fprintf(stderr, "fork error");
exit(EXIT_FAILURE);
}
if (fork_result == 0)
{
printf("CHILD 1\n");
pipe_fd = open(FIFO, O_WRONLY | O_NONBLOCK);
scanf("%s", writer);
res = write(pipe_fd,writer,3);
if (res == -1)
{
fprintf(stderr,"error writing to fifo\n");
exit(EXIT_FAILURE);
}
(void)close(pipe_fd);
exit(EXIT_SUCCESS);
}
else
{
printf("PARENt 1\n");
//don't forget pipe!
fork_result = fork();
pipe_fd = open(FIFO, O_RDONLY);
if (fork_result == 0)
{
printf("CHILD 2\n");
res = read(pipe_fd, reader, 3);
printf("Odczytano: 0: %c\n",reader[0]);
printf("Odczytano: 1: %c\n",reader[1]);
printf("Odczytano: 2: %c\n",reader[2]);
(void)close(res);
}
}
}
else
{
printf("deleting fifo\n");
unlink(FIFO);
}
exit(EXIT_SUCCESS);
}
Running sequence is like this:
PARENT 1
CHILD 1
CHILD 2
so in Parent 1 I'm opening FIFO to read, in child 1 I'm writing to FIFO and child 2 should read it. I mean in code because when I run it I can't even write anything to FIFO. In blocks in scanf("%s", writer); which worked in first program.
Am I using open() correctly? Do I need to use getpid() somewhere? Why it's blocking when I try to write to fifo.
The problem is that CHILD1 is opening the fifo with O_NONBLOCK, which will fail (with EWOULDBLOCK or EAGAIN) if no other process has the fifo open for reading. Now in the first program, the parent continues running after the fork and opens the fifo for reading before the child gets going and opens the write end, so it works. But in the second case, the parent does an extra fork first, which slows it down just enough that CHILD1 gets to its open command before PARENT or CHILD2 has opened the fifo for reading, so the CHILD1 open fails.
Get rid of the O_NONBLOCK and it works just fine (though you do open the fifo for reading in both PARENT and CHILD2, which is probably not what you want).
You have another issue if you want to read from the keyboard. If you run this from the shell, PARENT will exit immediately (more or less), so the shell will go back to reading commands from the keyboard, which means that CHILD1 and the shell will be fighting over the input. If on the other hand, you do what you originally describe and have PARENT wait reading from a pipe from CHILD2, it should do what you want.
Isn't it because you use twice the same variable fork_result? As you created another variable fork_result2, which you don't use, it is probably unintended.
I don't know if this will solve your problem, but at least using fork_result2 at the second fork would make it easier to understand...