Two way communication from the file that run with exec in child - c

I am creating a child process with a fork in program y. In that child, I run another program with exec, in which I want the function in that program (let's call it program x) to return something to me. Is there a way to pass this returned value to the parent?
I provided some sort of a pseudo-code that demonstrates what I want to do below.
program.x:
int main(int argc, char** argv)
{
if(argc != 2)
{
printf("argument count does not match\n");
return -1;
}
printf("task1!\n");
...
char *value = "want this"; // how to pass this to the parent in the program y?
...
}
program y:
int main(int argc, char *argv[])
{
int fd[2];
pipe(fd);
pid_t p;
p = fork();
if(p==-1)
{
printf("There is an error while calling fork()");
}
if(p==0)
{
printf("We are in the child process\n");
printf("Calling hello.c from child process\n");
char *args[] = {"Hello", "C", "Programming", NULL};
execv("./hello", args);
close(fd[0]);
write(fd[1], ???, ??);
close(fd[0]);
}
else
{
printf("We are in the parent process");
wait(NULL);
close(fd[1]);
read(fd[0], ???,???);
close(fd[0]);
}
return 0;
}

The only thing you can pass directly is the exit code of the child (via wait()).
To pass a string between two processes, you need an IPC data structure like pipes. See the pipe() function in unistd.h.

For the simple case where there is one-way communication from a child to a parent), you can use popen. It's high level, simple to use, and has little overhead (if any) over fork/exec
int main(...)
{
...
FILE *fp = popen("./hello 'Hello', 'C', 'Programming'", "r") ;
char resp[200] ;
if ( fgets(resp, sizeof(resp, fp) ) {
// Do something
}
int result = pclose(fp) ;
}
Note that the way to pass command line arguments follows shell rules - arguments may need to be quoted (usually, single quote) to pass any special characters.
The 'pclose' result is the exit code of the executed program.

Related

xv6 Start new process and exec user program

I'm trying to fork() a new process and exec() the the user program in newly created process.
This code works in user space. I'm not sure how to do the similar thing in kernel space. As per my debugging, seems like fork() never returns 0 in kernel space.
Additional question: How can I execute the user program from kernel space. Is it possible to do that with exec()?
int
main(int argc, char *argv[])
{
int pid = fork();
if(pid == 0){
// child
char *argv[2];
argv[0] = "echo";
argv[1] = "CHILD";
exec("/bin/echo", argv);
exit();
}
if(pid > 0) {
wait();
printf("parent");
}
else {
printf("ERROR");
}
exit();
}

Does anyone see any mistakes here? I am trying to get a message via a pipe, from my parent to child

The problem here is that the child process does not wait for the message to arrive from the function startWorking(), and because of that I am getting a random char as output or sometimes nothing.
I am sending a char array from startWorking() to the pipe and I am making sure only the parent does this job.
One solution would be, sending a signal from startWorking() to the child processor, after writing into the pipe.
But the read() function behavior is waiting for the pipe to receive the message and only then read the message, but somehow it's not doing that, or maybe there is a problem in writing the message.
int main(int argc, char const *argv[])
{
pid_t pid;
pid = fork();
int mypipefd[2];
if (pid > 0)
{
if (pipe(mypipefd) == -1)
{
perror("Pipe failed\n");
exit(EXIT_FAILURE);
}
storeEngine(mypipefd);
}
else if(pid < 0)
{
perror("fork call failed \n");
exit(EXIT_FAILURE);
}
else
{
printf("I am the child \n");
printf("child: %d \n", getpid());
char message[6];
close(mypipefd[1]);
read(mypipefd[0], &message, 6);
close(mypipefd[0]);
printf("child read value:\n ");
printf("%s \n", message);
}
return 0;
}
void startWorking(int *mypipefd)
{
printf("%d \n" ,getpid());
//close(*mypipefd);
write(*(mypipefd+1), "hello", 6);
close(*(mypipefd+1));
}
Notice that if I remove the two slash behind close(*mypipefd) the program will never finish, and it will get stuck there.
Without examining the rest of your code, you need to call pipe() before you call fork() so the pipe can be used by both the parent and the child process. If you call pipe() after you call fork(), the pipe is only usable by that one process.
More like this:
int main(int argc, char const *argv[])
{
int mypipefd[2];
if ( pipe( mypipefd ) == -1 )
{
perror("Pipe failed\n");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid > 0)
{
storeEngine(mypipefd);
}
.
.
.
No, pipes used to communicate between processes should be created before the fork() (otherwise, you have no easy way to send thru them, since the reading and the writing ends should be used by different processes).

C - program is terminated (fork() and exec())

I have the following code:
int main(int argc, char **argv)
{
char *program;
char stringa[1000] = "";
int num = 123;
char snum[5];
program = argv[1];
sprintf(stringa, "./%s", program);
pid_t pid = fork();
if (pid < 0 ) {
perror("fork failed.");
exit(1); }
else if (pid == 0) {
char* args[] = {stringa, NULL};
execv(args[0], args);
}
else {
char procmon_str[] = "./procmon ";
num = pid;
sprintf(snum, "%d",num);
printf("PID of child is %s", snum);
char* args2[] = {procmon_str, snum, NULL};
execv(args2[0], args2);
sleep(20);
kill(num, SIGTERM);
sleep(2);
int parent_pid = getpid();
printf("PID of parent is %d", parent_pid);
kill(parent_pid, SIGTERM);
}
wait(NULL);
return 0;
}
The idea is to call with program with 1 command line argument which is a name of another compiled C program in the same folder.
I want to execute that program from within the C code (hence the use of fork()), and at the same time i want to launch another program from within the parent part of the fork().
The part that is in the child part of fork() works perfectly, but when i run it through the shell it says Terminated right after and does not execute the code in the parent part of the fork().
Why is that?
Your program call fork(). Now the execution of the parent process and the child process proceeds in parallel.
The child:
Builds the argument array args[].
Calls execv() and is replaced by the program supplied as argument.
The parent, in parallel with the child:
Builds the argument array args2[].
Calls execv() and is replaced by ./procmon.
The code from sleep(20) onwards in not reached unless the execv() fails (which you did not check for).
Read the manual page for fork() again, and redo the logic of the program.

How to pipe stdin from child to parent?

I'm trying to exec()a child process from a parent process. In this child process, I ask the user to enter a message so it can be printed out by the parent process but I can't find a way to do it...
So far, my code is :
parent.c
int main(int argc, char **argv) {
int fd[2];
char line[80];
pipe(fd);
pid_t pid = (pid_t)fork();
if(pid > 0) {
waitpid(pid, NULL, 0);
close(fd[0]);
int size = read(fd[1], line, 79);
close(fd[1]);
line[size] = '\0';
printf("[parent] Received \"%s\", size = %d\n", line, size);
}
else {
close(fd[1]);
close(stdin);
dup2(fd[0], stdin);
close(fd[0]);
exec("./child", 0, NULL);
}
return 0;
}
child.c
int main(int argc, char **argv) {
char line[80];
printf("[child] Enter message: ");
gets(line, 80);
printf("[child] line = %s\n", line);
return 0;
}
When I launch the parent process, it displays [child] Enter message: but when I try to type something, nothing appears, even if I hit the return key.
Do you know how can I make it work ?
Thank you for your help.
Besides the problems mentioned in my comments, the problem you are experiencing is a deadlock. You get that because the parent process waits for the child process to exit. But the child process is waiting for input that never arrives.
That's because in the child process you say that the input should come from the pipe.
Furthermore in the parent process you attempt to read from the write-end of the pipe.
Finally, your program will never work as long as the child process is wanting to read user-input, because all user-input will go to the parent process.
To make it all work, you need to rethink your design, and to make the parent process the one that reads input from the user, and writes to the pipe. And the child process should read from the pipe and print to (the non-piped) standard output. Or you close the (normal, non-piped) standard input in the parent, and in the child you write to the pipe (as standard output).
Your code has several problems:
you mix integer (low level) file descriptors, and (high level) FILE * constants.
you invert stdin and stdout as well as the order of the descriptors obtained through pipe
you write a message on stdout when you intend to redirect it (should use stderr)
Here is a fixed version (I changed your gets by fgets, as well as your exec with execl to have everything to compile):
parent.c:
int main(int argc, char **argv) {
int fd[2];
char line[80];
pipe(fd);
pid_t pid = (pid_t)fork();
if(pid > 0) {
waitpid(pid, NULL, 0);
close(fd[1]);
int size = read(fd[0], line, 79);
close(fd[0]);
line[size] = '\0';
printf("[parent] Received \"%s\", size = %d\n", line, size);
}
else {
close(fd[0]);
close(1);
dup2(fd[1], 1);
close(fd[1]);
execl("./child", NULL);
}
return 0;
}
child.c
int main(int argc, char **argv) {
char line[80];
fprintf(stderr, "[child] Enter message: ");
fgets(line, 80, stdin);
printf("[child] line = %s\n", line);
return 0;
}
I've found a workaround. My actual goal was to pass information between parent and child. My error was to dup2 on stdin. By doing this, I couldn't enter anything when the program asked. So I passed the value of the file descriptors in the argv and my problem was solved.
Thanks again for your help !

Why is the following statements printing thrice?

Here is my program:
int main(int argc, char * argv[])
{
pid_t child;
int i=0;
if( argc < 4 ){
printf("Usage: %s <num_threads> <test_interval> <no_of_prints>\n", argv[0]);
exit(1);
}
// Some program logic goes here
printf("context - switch \n\nPid\ttid\tNPid\tNtid\tJiffies\n\n");
syscall(320);
child = fork();
if(child == 0 ) { //in child
fork();
fork();
process();
}
else {
wait(child);
//Do some printing here
}
My output has 3 (and sometimes 2) prints of "context - switch" printf line.
It's probably because of stdio buffering. In a nutshell, multiple processes (the parent, it children, grandchildren etc) end up with the same buffer and they all write it to the screen when they die. Try:
printf("context - switch \n\nPid\ttid\tNPid\tNtid\tJiffies\n\n");
fflush(stdout);
Or maybe just use write(2) instead of printf.

Resources