I want to do the following things:
Child process run a program by exec()
Parent process read from STDIN and do something to the input
Pass the input to child process's default input stream.
I know that the child and the parent share the same STDIO, and I'm not familiar with pipe or how to make child read from other pipe.
Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
int fd[2];
pid_t pid = fork();
pipe(fd);
if (!pid) {
dup2(fd[0], STDIN_FILENO);
char arg_pipe_id[10];
sprintf(arg_pipe_id, "<&%d", fd[0]);
close(fd[1]);
// Error here, cannot use <&id or <id in this execl
execl("/bin/bash", "/bin/bash", "-i", arg_pipe_id, NULL);
} else {
char input[2048];
close(fd[0]);
while (fgets(input, 2048, stdin)) {
...
process the input...
...
if (condition) {
write(fd[1], input, strlen(input));
}
}
close(fd[1]);
kill(pid, SIGKILL);
wait(NULL);
}
}
I'd appreciate it if you could help me!
Related
I'm writing a program where I want to redirect command to another process programmatically.
So if I receive the command as argument, I want to receive the output on the parent process.
My code is:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char* argv[]) {
{
char msg[8]=“message”;
int pp[2];
if(pipe(pp)<0) {
printf("Error pipe");
exit(1);
}
if (!fork())
{
close(fd[0]);
//TODO...
} else {
close(fd[1]);
read(fd[0], msg, 8);
close(fd[0]);
}
}
I'm lost about the child part, where I execute the command and do the redirection. I'm using pipe to communicate between child process and parent process.
On the child side, I've closed the pipe side not used, then I don't know how to continue.
Can you help?
The steps are the following:
close pipe-read and stdout
dup() pipe-write to redirect pipe-write to stdout with fd=1
close initial pipe-write
execute the command, reading from argv the first argument
Your code becomes like that:
if (!fork())
{
close(pp[0]);
close(1);
dup(pp[1]);
close(pp[1]);
execlp(argv[1], argv[1],(char *)0);
exit(0)
}
I am trying to send message from parant.c to child.c and I am successfully receiving it in the child.c
My question is that how can I send message back to the parent using second pipe from child.c I want the exact sequence of code.
Here is my parent.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int fd[2];
char buf[] = "HELLO WORLD!", receive[100];
if (pipe(fd))
{
perror("pipe");
return -1;
}
switch (fork())
{
case -1:
perror("fork");
return -1;
case 0:
// child
close(fd[1]); // close write end
dup2(fd[0], STDIN_FILENO); // redirect stdin to read end
close(fd[0]); // close read end
execl("./child", NULL); // execute child
default:
// parent
close(fd[0]); // close read end
write(fd[1], buf, sizeof(buf)); // write to write end
close(fd[1]); // close write end
wait(NULL);
}
printf("\nEND~\n");
return 0;
}
I am sending buf ("Hello world") to the child by executing ./child file.
Here is my child.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int fd[2];
pid_t pid = fork();
char buf[100], child_msg[] = "From Child: Hello Parent";
if (pipe(fd))
{
perror("pipe");
return -1;
}
switch (pid)
{
case -1:
perror("fork");
return -1;
case 0:
read(STDIN_FILENO, buf, sizeof(buf));
printf("%s ", buf);
close(fd[1]);
default:
wait(NULL);
}
return 0;
}
I am receiving Hello world in this file. but now how can I send child_msg back to the parent? I don't how to do that. I am stuck at this for last 14 hours.
From main pipe:
pipe() creates a pipe, a unidirectional data channel ...
So, you need 2 pipes, i.e., you have to create 2 pipes in your main process that will also be inherited by the child process.
From your code, you are execing another program, in such cases you might
be better off with other IPCs and not pipe!
The 'create_andWrite' function should create a pipe and write a string to it. The child process which is created in the main should read from the pipe.
I only worked with pipes in one method(e.g. read and write are both in main) before and I'm really struggling with this one.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int creat_and_write(FILE *fd, char *string) {}
int main() {
int fd[2];
creat_and_write();
int p = fork;
}
These are my functions signatures so far
Pipes are one way of unidirectional IPC, used usually with fork() to pass data in a sort of vertical hierarchy.
Hope the example below is clear. and spot the usage of the 2 functions.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define READ_END 0
#define WRITE_END 1
// pipe uses file descriptors to communicate between processes not pointers to files.
int creat_and_write(int *fd, char *string) {
// first and formost we need a pipe.
if (pipe(fd) == -1) {
perror("pipe error");
exit(1);
}
// now the fd contains 2 file descriptors, one for reading and one for writing to the pipe.
// we fork a child process which will inherit most internals including the pipe's file descriptors.
pid_t pid = fork();
if (pid == -1)
{
perror("fork error");
exit(1);
}
else if (pid == 0)
{
// we're at the child process.
// now we can write to the write end of the pipe
write(fd[WRITE_END], string, strlen(string));
// good practice to close done end of the pipe. for a full cleanup.
close(fd[WRITE_END]);
}
else
{
// we're at the parent process.
// now we can read from the read end of the pipe
char buffer[strlen(string)];
read(fd[READ_END], buffer, 100);
close(fd[READ_END]);
printf("now at the parent process: %s\n", buffer);
}
return 0;
}
int main() {
int fd[2];
creat_and_write(fd, "msg from child process");
return 0;
}
I am using dup2(), pipe(), and fork() to process commands with input of another. The output from the ls is correctly passed into cat, and the terminal displays output, but it does not stop receiving input. In other words cat does not terminate, so I can continue typing.
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
int main() {
int pipefd[2], child_pid, grand_child;
pipe(pipefd);
child_pid = fork();
if (child_pid) {
waitpid(child_pid, NULL, 0);
/* Parent */
grand_child = fork();
if (!grand_child) {
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
close(pipefd[1]);
execlp("cat", "cat", NULL);
} else {
waitpid(grand_child, NULL, 0);
}
} else {
/* Child */
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
close(pipefd[0]);
execlp("ls", "ls", NULL);
}
return 0;
}
The parent still has the write side of the pipe open. cat is waiting for the parent to close it, and the parent is waiting for cat to terminate. You should close both sides of the pipe in the parent before you wait for the grand child.
I'm trying to execute the Linux command "ls -l | tail -n 2" with a simple pipe in a c code.
I added your tips and now this works but the output isn't exactly as it should be. It prints the output in a single line instead of two and waits for a user input to close.
here is the new code:
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "sys/wait.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void main()
{
char line[100];
pid_t pid;
int fd[2];
int status;
char* ls_arguments[] = {"ls", "-l", NULL};
char* tail_arguments[] = {"tail", "-n", "2", NULL};
pipe(fd);
pid = fork();
if(pid == 0)//ls client
{
close(1);
dup(fd[1]);
close(fd[0]);
execvp("ls", ls_arguments);
}
pid = fork();
if(pid == 0)//tail client
{
close(0);
close(fd[1]);
dup(fd[0]);
execvp("tail", tail_arguments);
}
wait(pid, 0, WNOHANG);
close(fd[0]);
close(fd[1]);
}
this should run the "ls -l" command and output to the pipe and the next "tail" client would get it as input and run the "tail -n 2" command and print out the final output but the terminal prints nothing. Any help?
First of all, there is not such wait function, here is what the man says:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
I think you meant to use waitpid.
Then, you child process doesn't finish because the pipe is still opened somewhere: in the parent. Indeed you should first close the descriptors and then wait for your childs process. I would write:
close(fd[0]);
close(fd[1]);
wait(NULL); // Wait for the first child to finish
wait(NULL); // Wait fot the second one
return 0;
}
Instead of:
wait(pid, 0, WNOHANG);
close(fd[0]);
close(fd[1]);
}