Programming in C using pipes to send info backwards - c

I'm trying to figure out how to use pipes. I've managed to set up pipes to send information from C1 (child 1) to C2 (child 2) however, when I try to do the opposite e.g. sending an integer "10" from C2 to C1 it gets stuck after my first system("ps -o pid,ppid,pgid,sess,comm") call. In general I don't seem to have problem sending stuff forward however problem seems to arise when I try to do stuff backwards. Am I missing some logical steps here?
./in reads an integer and prints it and ./out takes an integer and writes it. They seems to be working perfectly okay.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <assert.h>
#define READ 0
#define WRITE 1
int main()
{
int fds[2];
pid_t pid;
int test;
if(pipe(fds)<0)
{
exit(0);
}
pid = fork();
if(pid==0)
{//C1
test = close(READ); assert(test==0);
test = dup(fds[READ]); assert(test==READ);
test = close(fds[READ]); assert(test==0);
test = close(fds[WRITE]); assert(test==0);
sleep(1);
execlp("./in", "./in", NULL);
exit(1);
}
system("ps -o pid,ppid,pgid,sess,comm");
wait(0);
system("ps -o pid,ppid,pgid,sess,comm");
sleep(2);
pid = fork();
if(pid==0)
{//C2
test = close(WRITE); assert(test==0);
test = dup(fds[WRITE]); assert(test==WRITE);
test = close(READ); assert(test==0);
test = close(fds[READ]); assert(test==0);
test = close(fds[WRITE]); assert(test==0);
sleep(2);
execlp("./out", "./out", "10", NULL);
exit(0);
}
sleep(1);
test = close(fds[READ]); assert(test==0);
test = close(fds[WRITE]); assert(test==0);
system("ps -o pid,ppid,pgid,sess,comm");
wait(0);
system("ps -o pid,ppid,pgid,sess,comm");
return 0;
}

The reason your process is getting stuck is the wait() system call after calling system(). system() actually calls wait() itself so your wait() is waiting for child 1 to finish but child 1 is itself probably blocked on IO.
For bidirectional communication, you really need two pipes, one for communication in each direction. With the second pipe you do pretty much exactly what you do at the moment except for child 1 you replace stdout and for child 2 you replace stdin.

the dup() function returns a file descriptor.
The child code is overlaying that file descriptor with the returned value from a call to close() Usually the returned value from close() is 0, which is NOT a file descriptor.
There is no communication possible via a pipe in the posted code as both end of the pipe are closed before calling execlp() for both child 1 and child 2.

Related

execve /bin/bash as child process. interacting with bash via parent process using pipes

I want to execve a bash as a child process in a c program. The bash should essentially be controlled by the parent process: the parent process reads from stdin, stores the read input into a buffer and writes the content of the buffer to the bash through a pipe. The output of the bash is supposed to be passed through another pipe back to the parent process's stdout. For instance: the parent process reads "ls" and gives it to the bash through a pipe and receives the output of the bash through another pipe. I know this program doesn't make sense, because there are better ways to execute ls (or some other program) on behalf of the parent process. I'm actually just trying to understand how piping works and this is the first program that came into my mind. And i can't make this program work. That's what i have so far:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
int main() {
int pc[2];//"parent to child"-pipe
int cp[2];//"child to parent"-pipe
int status;
char buffer[256];
char eof = EOF;
if (pipe(pc) < 0 || pipe(cp) < 0) {
printf("ERROR: Pipes could not be created\n");
return -1;
}
pid_t child_pid = fork();
if (child_pid == 0) { //child has pid 0, child enters here
close(pc[1]);//close write end of pc
close(cp[0]);//close read end of cp
//redirecting file descriptors to stdin/stdout
dup2(cp[1], STDOUT_FILENO);
dup2(pc[0], STDIN_FILENO);
execve("/bin/bash",NULL,NULL);
} else {//parent enters here
close(cp[1]);//close write end of cp
close(pc[0]);//close read end of pc
//redirecting file descriptors to stdin/stdout
dup2(cp[0], STDOUT_FILENO);
while(1) {
read(STDIN_FILENO, buffer, 3);
write(pc[1], buffer, 3);
}
waitpid(child_pid, &status, 0);
}
return 0;
}
On execution: I type in ls, hit enter, nothing happens, hit enter again, output.
$ ./pipe
ls
bash: line 3: s: command not found
Why is only the character 's' delivered to the bash?

Where do I put perror("wait") with fork code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char **argv) {
for(int i = 0; i < 10; i++) {
pid_t pid = fork();
if(pid == 0) {
while(1) {
pid_t pid2 = fork();
wait(NULL);
}
}
}
wait(NULL);
return(0);
}
Basically the program runs several hello world processes and closes with ctrl+C. How would I do the wait error? Like perror(wait). I think I have to use int status instead of NULL but unsure how to go about it when theres orphan processes involved.
The given code is
$ gcc -Wall above.c
$ ./a.out
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
^C (until ctrl C is hit)
$
The function perror is only useful when you know that a function failed and
errno is set, so you want to print an error message. You usually write
perror("something failed") right after the function that could fail and
sets errno (the documentation of the function will tell you whether the
function set errno on failure).
man perror
SYNOPSIS
#include <stdio.h>
void perror(const char *s);
#include <errno.h>
DESCRIPTION
The perror() function produces a message on standard error describing the last error encountered during a call to a system or library
function....
This has nothing to do with wait and it's parameter, it's only useful if
wait fails and you want to print an error message about wait failing.
man wait
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
DESCRIPTION
All of these system calls are used to wait for state changes in a child of the calling process...
...
wait() and waitpid()
The wait() system call suspends execution of the calling process until one of its children terminates. The call wait(&wstatus) is
equivalent to:
waitpid(-1, &wstatus, 0);
...
RETURN VALUE
wait(): on success, returns the process ID of the terminated child; on error, -1 is returned.
...
Each of these calls sets errno to an appropriate value in the case of an error.
If you just want to wait for a child to exit, you can do just wait(NULL).
However if you want to know the status of the child that exited, then you have
to pass a pointer to int.
int wstatus;
pid_t wp = wait(&wstatus);
if(wp == -1)
{
// here I use perror because if wait returns -1 then there
// was an error and errno is set
perror("could not wait for child\n");
exit(1);
}
if(WIFEXITED(wstatus))
printf("Child with pid %d exited normally with status %d\n", wp, WEXITSTATUS(wstatus));
else
printf("Child with pid %d exited abnormally\n", wp);
I personally prefer waitpid over wait, it gives you more control over the
child you are waiting.
See man wait

Using processes to run commands with pipes

I'm still new to processes,pipes and dup2, therefore I'd like someone to help me figure out what's wrong with a program I've created. This program is supposed to run ls | wc. So far the output I get is :
wc : standard input : Bad file descriptor
0 0 0
ls : write error : Bad file descriptor
After I get this output, the terminal still accepts inputs. It's like wc is still running, although if I put commands like ls first(without any other input before) it runs them and shuts down. I tried running ps before/after and while the program was still running and it didn't show any process being open aside from bash and ps. (I'm running this program in Linux terminal)
Here's my code :
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>
#include<errno.h>
int main(int argc, char* argv[]){
pid_t pid;
int fd[2];
char com1[1024] = ("ls");
char com2[1024] = ("wc");
pipe(fd);
pid = fork();
if(pid == 0){
open(fd[1]);
dup2(fd[0],STDOUT_FILENO);
close(fd[0]);
execlp(com1, com1, NULL);
}
else {
pid = fork();
if (pid == 0){
open(fd[0]);
dup2(fd[1],STDIN_FILENO);
close(fd[1]);
execlp(com2, com2, NULL);
}
}
return 0;
}
Bear in mind that I know some if commands for checking are required(like if(pid<0)exit(0);) but I tried to simplify my code as much as possible in order to see if there's any mistake due to carelessness.
Thank you in advance!
According to the pipe manual page:
pipefd[0] refers to the read end of the pipe. pipefd[1] refers to the write end of the pipe.
Now take this line from the first child, the process that calls the ls command:
dup2(fd[0],STDOUT_FILENO);
Here you duplicate the read end of the pipe to STDOUT_FILENO, i.e. where output is written. If you stop and think a little about it, how would you write to a read-only file-descriptor like fd[0]?
Same with the other child process, where you make the write end of the pipe standard input.
The solution is simple: Swap places of the descriptors you duplicate. Use fd[1] for the first child process, and fd[0] for the second child process.
In the first process where you call the ls command:
dup2(fd[1],STDOUT_FILENO);
close(fd[1]);
execlp(com1, com1, NULL);
And in the second child process where you call the wc command:
dup2(fd[0],STDIN_FILENO);
close(fd[0]);
execlp(com2, com2, NULL);

Create child process on OSX and redirect stdin and stdout of child process to parent process?

I'm working on a C program in Xcode on OSX.
The (parent) program has to launch a new (child) process which receives its input via stdin and outputs results to stdout. So the parent writes data to the child process's stdin and the parent reads results from the child process's stdout.
On Windows I use CreateProcess to do the above, but I'm not sure how it's done on OSX in C.
I believe I'm supposed to use exec to start the process, but I don't see how I redirect stdin and stdout of the executable (child process) which exec starts. And from reading the manual it also looks like the child process will become the parent process if I use exec. The child and parent process has to run in parallel so that the parent process can write and read to the child process when it needs to.
Is there a kind OSX C expert out there who could give me a brief example of how the above is done?
Thanks
EDIT
I think I understand. But if the child process is an infinite while-loop which waits for input on stdin, then it won't turn into a "zombie", right?
The child process basically does this:
1. Read data from stdin (i.e. blocked until data is received)
2. Process data
3. Write result to stdout
4. Goto 1
After I read your post, I found this page:
http://www.jukie.net/~bart/snippets/popenRWE/popenRWE.c.html
However, I'm having a problem getting my .exe (child process) to launch
In a terminal, I would start the .exe like this:
./myApp.exe someParam1 someParam2 someParam3
The API looks like this:
popenRWE(int *rwepipe, const char *exe, const char *const argv[])
I'm guessing that the second argument should be:
const char* exe = "./myApp.exe";
and that the third argument should be:
char* p0 = "./myApp.exe";
char* p1 = "someParam1";
char* p2 = "someParam2";
char* p3 = "someParam3";
char** argv[4] = {p0, p1,p2,p3};
Am I right?
I'm including the source of a small library I've written a while ago. That should get you started. Fork / pipe / exec isn't really that easy (especially with all the variants of exec) and it took me a while too. So here goes:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include "limbo.h"
int out_pipe[2], err_pipe[2];
int run_command(char *argv[], int *out_length, int *err_length){
pid_t pid;
int status = 0;
struct stat out_stat, err_stat;
pipe(out_pipe); //create a pipe
pipe(err_pipe);
if(!(pid = fork())) //spawn child
{
// Child. Close the read end of the pipe
close(out_pipe[0]);
close(err_pipe[0]);
// redirect stdout and stderr to the write end of the pipe
dup2(out_pipe[1], STDOUT_FILENO);
dup2(err_pipe[1], STDERR_FILENO);
status = execv(argv[0], argv); //child will terminate here
}
//Only parent gets here. Close write end of the pipe
close(out_pipe[1]);
close(err_pipe[1]);
//or wait for the child process to terminate
waitpid(pid, &status, 0);
fstat(out_pipe[0], &out_stat);
fstat(err_pipe[0], &err_stat);
*out_length = (int) out_stat.st_size;
*err_length = (int) err_stat.st_size;
return status;
}
int read_buffers(char *out_buffer, int out_length, char *err_buffer, int err_length){
out_buffer[read(out_pipe[0], out_buffer, out_length)] = 0;
err_buffer[read(err_pipe[0], err_buffer, err_length)] = 0;
return 0;
}
The comments in the code should help you to understand the code. Feel free to reuse.
Edit
In response to your comment:
The waitpid() call makes the parent process wait for the termination of the child process. If you want both processes to run in parallel, you need to get rid of waitpid() in the place that I use it. But be careful: without a call to one of the wait functions your child process will become a zombie once it finishes. It is your responsibility to keep an eye on your child process and to wait for it so the process can be cleaned up by the kernel.

Using C to send an exec process to the background?

My question sounds the same as this but it isn't:
Start a process in the background in Linux with C
I know how to do fork() but not how to send a process to the background. My program should work like a simple command unix shell that supports pipes and background processes. I could do pipe and fork but I don't know how to send a process to the background with & like the last line of the program:
~>./a.out uname
SunOS
^C
my:~>./a.out uname &
How to achieve the background process?
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define TIMEOUT (20)
int main(int argc, char *argv[])
{
pid_t pid;
if(argc > 1 && strncmp(argv[1], "-help", strlen(argv[1])) == 0)
{
fprintf(stderr, "Usage: Prog [CommandLineArgs]\n\nRunSafe takes as arguments:\nthe program to be run (Prog) and its command line arguments (CommandLineArgs) (if any)\n\nRunSafe will execute Prog with its command line arguments and\nterminate it and any remaining childprocesses after %d seconds\n", TIMEOUT);
exit(0);
}
if((pid = fork()) == 0) /* Fork off child */
{
execvp(argv[1], argv+1);
fprintf(stderr,"Failed to execute: %s\n",argv[1]);
perror("Reason");
kill(getppid(),SIGKILL); /* kill waiting parent */
exit(errno); /* execvp failed, no child - exit immediately */
}
else if(pid != -1)
{
sleep(TIMEOUT);
if(kill(0,0) == 0) /* are there processes left? */
{
fprintf(stderr,"\Attempting to kill remaining (child) processes\n");
kill(0, SIGKILL); /* send SIGKILL to all child processes */
}
}
else
{
fprintf(stderr,"Failed to fork off child process\n");
perror("Reason");
}
}
The solution in plain English appears to be here:
How do I exec() a process in the background in C?
Catch SIGCHLD and in the the handler, call wait().
Am I on the right track?
Q: How do I send a process to the background?
A: In general, exactly what you're already doing: fork()/exec().
Q: What's not working as you expect?
I suspect maybe you also want a "nohup" (to completely disassociate the child from the parent).
The key to doing this is to run "setsid()" in the child process:
How to use fork() to daemonize a child process independant of it's parent?
http://www.enderunix.org/docs/eng/daemon.php

Resources