Unix redirect command programmatically - c

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

Related

I want to create two communication between parent and child residing in different C files using ordinary pipes (IPC)

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!

C exec() use a pipe as default input stream

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!

Redirection of stdin and stdout via pipes in C works for external programmes but not for recursive call

I am trying to communicate with forked child processes via pipe redirection of stdin and stdout in C. I already managed to get this to work for shell commands (like ls, for example) executed in child processes. However, I wasn't able to recursively execute the same program and redirect the output (printed by printf(), fprintf() to stdout, ...) via the pipes from the child process to the parent (in this test to stdout of the parent), although this works fine for ls or similar commands.
Here's how I tried to approach this:
I create a pipe, the reading end is for the parent, the child process should write to the writing end.
The Process forks, both processes close the unused end, respectively.
The writing end of the pipe is redirected to STDOUT_FILENO and closed
The child process executes the program recursively (it is called ./to2)
As mentioned, this does work if I execute ls in the child process, but not if I try to call the same program recursively. Here's my test program where I tried to get this to work:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <netdb.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
static void usage(void){
fprintf(stderr,"RIP");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]){
if(argc > 1){
dprintf(STDOUT_FILENO,"Please work\n");
printf("\n THIS IS A MESSAGE FROM THE CHILD \n");
fputs("Pretty Please!\n",stdout);
fflush(stdout);
exit(EXIT_SUCCESS);
}
int p1[2];
if(-1 == pipe(p1)) {
fprintf(stderr,"pipe\n");
fprintf(stderr,"%s\n",strerror(errno));
usage();
}
int f = fork();
if(f == 0){
close(p1[0]);
if(dup2(p1[1],STDOUT_FILENO) < 0){
fprintf(stderr,"dup2\n");
usage();
}
close(p1[1]);
//I want this to work:
//execlp("./to2", "./to2", "-e");
//This works fine:
execlp("ls", "ls");
exit(EXIT_SUCCESS);
} else if (f == -1) {
usage();
} else {
close(p1[1]);
int w = -1;
if(-1 == wait(&w)) usage();
char b[12];
memset(b,0,12);
read(p1[0],&b,12);
char reading_buf[1];
while(read(p1[0], reading_buf, 1) > 0){
write(1, reading_buf, STDOUT_FILENO);
}
close(p1[0]);
}
}
For testing purposes, the function is called recursively with additional arguments, while the parent program is called without additional arguments (hence the if(argc>1)).
In the final program, endless recursion is being avoided by other means.
Did I understand something wrongly? I am pretty confused by the fact that the only thing that doesn't seem to work is redirecting the output of my own
program...
Thank you very much in advance, any help or ideas are greatly appreciated.
The primary problem is precisely as outlined in the comments — you are not calling execlp() correctly (nor ls in the alternative). You must make the last argument on those function calls into an explicit null pointer, as shown in this code, which is a mostly mildly edited version of what's in the question:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
static void usage(void)
{
fprintf(stderr, "RIP\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
dprintf(STDOUT_FILENO, "Please work\n");
printf("THIS IS A MESSAGE FROM THE CHILD\n");
fputs("Pretty Please!\n", stdout);
fflush(stdout);
exit(EXIT_SUCCESS);
}
int p1[2];
if (-1 == pipe(p1))
{
fprintf(stderr, "pipe: %s\n", strerror(errno));
usage();
}
int f = fork();
if (f == 0)
{
close(p1[0]);
if (dup2(p1[1], STDOUT_FILENO) < 0)
{
fprintf(stderr, "dup2: %s\n", strerror(errno));
usage();
}
close(p1[1]);
execlp(argv[0], argv[0], "-e", (char *)0);
fprintf(stderr, "failed to exec %s again\n", argv[0]);
exit(EXIT_FAILURE);
}
else if (f == -1)
{
usage();
}
else
{
close(p1[1]);
char b[13];
memset(b, 0, 13);
if (read(p1[0], &b, 12) < 0)
{
fprintf(stderr, "Failed to read from pipe (%s)\n", strerror(errno));
exit(EXIT_FAILURE);
}
int len = strcspn(b, "\n");
printf("M1 [%.*s]\n", len, b);
char reading_buf[1];
while (read(p1[0], reading_buf, 1) > 0)
{
write(1, reading_buf, STDOUT_FILENO);
}
close(p1[0]);
int w = -1;
if (-1 == wait(&w))
usage();
}
return 0;
}
Two important changes should be highlighted:
This code echoes the first line of data — the one written by dprintf() — whereas the original code just read it and discarded it.
The wait() call is after the input, not before. If the child had more data to write than a set of fixed messages, it could block waiting for the parent to read some of the data, while the parent is blocked waiting for the child to exit. This would be a deadlock.
The usage() function is not appropriately named — it doesn't report how to run the program. I also exit with a failure status, not success, if the child process fails the execlp().
Under peculiar circumstances, the wait() call might report on the exit status from some child other than the one that was forked. It is generally best to use a loop to reap such children. However, the circumstances required are extremely peculiar — the process which launched the parent with an exec*() function must have previously created some children for which it didn't wait, so that they are inherited by the parent process (because the PID doesn't change across an exec*() call).

pipe() and fork() to transer data from parent to child

I have to create a pipe and then a fork and allow parent and child process (1 child) communication.
In particular Parent reads from a file and writes on pipe the content of file (which is supposed to be huge) then child has to read from pipe and display on stdout the content of file.
gcc compiler is ok but nothing happen when I run the executable file.
Can someone help me with my code? Where did I go wrong and why?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define size 80
int main(int argc,char*argv[]){
if(argc!=2){
write(2,"Missing parameters on the command line\n",38);
return 1;
}
int fd[2];
pid_t pid;
int fd_in;
int i;
char buf[size];
//create pipe for communication between parent and child in this case parent read the file at size bytes at time write into pipe then child write data on stdout received from father
if(pipe(fd)!=0){
printf("Pipe failure\n");
return 1;
}
pid=fork();
if(pid<0){
printf("Fork() failure\n");
return 1;
}
if(pid>0){ // parent process
close(fd[0]);// parent write into pipe ,close reading
if(access(argv[1],F_OK)!=0){
write(2,"Input file does not exists\n",35);
return 1;
}
if(fd_in=open(argv[1],O_RDONLY)<0){
printf("Cannot open for reading file %s\n",argv[1]);
return 1;
}
while(read(fd_in,buf,size)>0){
write(fd[1],buf,size);
}
close(fd[1]); // close write into pipe
wait(0);
}
if(pid==0){ //Child process
close(fd[1]);// child read from pipe, close writing
while(read(fd[0],buf,size)>0){
write(1,buf,size);
}
close(fd[0]);// close reading
return 0;
}
close(fd_in);
return 0;
}

Child shell process bidirectional redirection to parent process

Hello stackoverflow I tried to create a program which execute a son shell process and redirect his I/O to a pipe in order to communicate with his father process.
I can execute command via the write pipe (wpipefd) but I can't get the response from the shell process on the read pipe (rpipefd).
I had 3 errors so far according to Strace : First the read function was blocking the program so I made ​​the read fd of the reading pipe non-blocking (rpipe[0]). Then I had an EAGAIN error with the read function... Finally I got an EPIPE error when I close the read fd from rpipe (close(rpipefd[0])) in the forked process just after the use of dup2() .
I don't understand what I did wrong. Here's what I did so far :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int rpipefd[2], wpipefd[2], pid;
pipe(rpipefd);
pipe(wpipefd);
char buffer[BUF_SIZE] = {0};
int flags = fcntl(rpipefd[0], F_GETFL, 0);
fcntl(rpipefd[0], F_SETFL, flags | O_NONBLOCK);
pid = fork();
if(pid == 0)
{
close(rpipefd[0]);
dup2(rpipefd[1],1);
dup2(rpipefd[1],2);
close(wpipefd[1]);
dup2(wpipefd[0],0);
close(rpipefd[1]);
close(wpipefd[0]);
execl("/bin/sh","/bin/sh",NULL);
}
close(wpipefd[0]);
write(wpipefd[1],"echo helloWorld",strlen("echo helloWorld"));
close(rpipefd[1]);
read(rpipefd[0],buffer,BUF_SIZE);
//perror("read()");
printf("%s",buffer);
exit(0);
}
Please help !
The main issue doesn't come from the code itself: the command passed to the shell is incomplete, you missed the final '\n' and thus the child process (your shell) is waiting for the rest of the command.
The non-blocking part is not a good idea (or at least, you should spin around you pipe in order to retrieve its content.)
Once you're done with your command, you should close the output pipe so the shell get the end-of-file on its input.
Other remarks: you should wait for the child termination (using wait(2)), you should leave after your execl in the child process (use with err(3) for the error message) to handle exec errors. And, seriously, calling strlen on string literal ? I know that gcc is replacing it at compile time, but …
Here is a modified version of your code:
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int rpipefd[2], wpipefd[2], pid;
pipe(rpipefd);
pipe(wpipefd);
char buffer[BUF_SIZE] = {0};
pid = fork();
if(pid == 0)
{
close(rpipefd[0]);
dup2(rpipefd[1],STDOUT_FILENO);
dup2(rpipefd[1],STDERR_FILENO);
close(wpipefd[1]);
dup2(wpipefd[0],STDIN_FILENO);
close(rpipefd[1]);
close(wpipefd[0]);
execl("/bin/sh","/bin/sh",NULL);
err(1, "execl()");
}
close(wpipefd[0]);
close(rpipefd[1]);
write(wpipefd[1], "echo helloWorld\n", 16);
close(wpipefd[1]); // we're done, say it to the shell
int r;
while ( (r = read(rpipefd[0],buffer,BUF_SIZE)) )
{
if (r == -1)
{
if (errno == EAGAIN || errno == EINTR) continue;
err(1, "read()");
}
write(STDOUT_FILENO, buffer, r);
}
wait(NULL);
return 0;
}

Resources