stdin control is not given to the child after the parent death - c

Considering the following code, when the parent is terminated, the stdin control is taken back by the shell and there is no way to see that the child process is running except through the "ps -e" command.
Is there is any way to give the stdin control to the child process before the parent dies?
I read some similar topics here, but non of them gives a solution to this issue. One has suggested to use "#cat | ./a.out" as a work around but I want a code level solution if there is any.
pid = fork();
if( pid == 0)
{
while(1);
}
else
{
//wait(&childstatus);
printf("Hello From Parent\n");
}

Yes, this is the way shell works. If you don't want the shell take active process group, keep the parent alive.

Related

How to keep child's stdout open after parent's termination in linux?

I am trying to run a child process from the parent app in Ubuntu. Both are C programs. The parent uses fork() with subsequent execl(), then waits for ~1 sec and terminates. The idea is to let parent terminate in a regular way, and keep child alive and running in the same console. So, the child begins to print some output with intervals of 300 ms, and I can see it for about the time while parent is alive. Then parent terminates, and further child output can not be seen in the console.
From what I have read to this moment, it seems that since the child shares all the handles, upon parent's exit stdout gets closed for both parent and child. So, I guess the child has to somehow preserve binding to the same console it was bound to upon its start. Please, advice how to achieve this.
You don't have to do anything special if you want the child process to keep running and writing to the terminal, even after the parent has stopped. Try the program below. This BTW is super annoying as the child process will trash you current terminal session.
This works because:
The child process gets a copy of the parents open file descriptors, including stdout. This is AFAIK the same as what dup() does.
To actually close the file, you have to close all associated file descriptors.
See the man pages for fork() and dup() for more information.
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
int wstatus;
switch (pid)
{
case -1:
fprintf(stderr, "fork() failed\n");
exit(EXIT_FAILURE);
case 0:
while (1)
{
printf("child working...\n");
sleep(1);
}
break;
default:
printf("Press ENTER to exit parent...\n");
getchar();
}
return EXIT_SUCCESS;
}
Sorry for bothering you guys and thank you all for your comments! As a windows-backgrounded person I just was not sure what should be normal behaviour in such a scenario.
While building and trying out the example, I think I understood the reason of this behaviour. The problem was that I ran it in mc with panels shown. Now, I have tried to run it under different conditions, and have the following picture: if I run it from bare console, it works fine; if I run it from mc with panels hidden, it runs OK either. The only case when it stops to show output after parent had closed is when I run it with panels shown. Now it's obvious to me that in this case the mc prints "Press any key to continue..." message right upon the parent's termination and stops showing any further output from the child.

Execlp execute in another terminal

I am creating an application in C which I have to execute the firefox with the command execlp but every time I execute it I "lost" my current terminal, but after the execlp i still need to use the terminal which I was before, so my question is: Is there a way where I can be in one terminal call execlp and it executes in another one without block the one I am on?
here is a snippet of my code:
pid_t child = fork();
if (child == -1) {
perror("fork error");
} else if (child == 0) {
exec_pid = getpid();
execlp("firefox", "firefox", URL, NULL);
perror("exec error");
}
// keep with program logic
If I'm understanding you correctly, you're saying that your program launches Firefox and then keeps control of your shell until Firefox terminates. If this is the case, there are a couple of ways around this.
The easiest solution is to run your program in the background. Execute it like ./my_program & and it be launched in a separate process and control of your terminal will be returned to you immediately.
If you want to solve this from your C code, the first step would be to print out the process ID of the child process after the fork. In a separate shell, use ps to monitor both your program and the forked PID. Ensure that your program is actually terminating and that it's not just stuck waiting on something.

Replace Parent Process with Child Process After Death

It is my objective to make a program with a parent and child process, and when either one them is killed, they are replaced. The part I am struggling with is the case of the parent's death. In this case, the child must step up to become the new parent, and then fork() a child of its own. When I send a SIGKILL to the parent process, my entire program seems to end abruptly, and since I cannot handle a SIGKILL, I am unsure of how to do this properly.
Is there a way to keep the child running in order to become the new parent process?
Thanks
Normally the child you fork shouldn't be killed when it's parent is killed, unless you do something like: How to make child process die after parent exits?
If the parent is killed, the children become a children of the init process. You probably saw on terminal that the process returns immediately after you send KILL to parent. That's because the sub-bash is waiting only on the parent's PID. But the child is actually running elsewhere.
Here is a example to show it:
#!/usr/bin/env python
# test_parent_child_kill.py
import os
import time
def child():
print "Child process with PID= %d"%os.getpid()
time.sleep(20)
def parent():
print "Parent process with PID= %d"%os.getpid()
newRef=os.fork()
if newRef==0:
child()
else:
print "Parent process and our child process has PID= %d"%newRef
time.sleep(20)
parent()
Then within sleep period:
user#mac:/tmp|⇒ python test_parent_child_kill.py
Parent process with PID= 17430
Parent process and our child process has PID= 17431
Child process with PID= 17431
user#mac:/tmp|⇒ kill 17430
user#mac:/tmp|⇒ ps -ef | grep 17431
503 17431 1 0 9:30PM ttys000 0:00.00 /usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python test_parent_child_kill.py
So the child is actually still alive.
--Edit--
Why when the parent is killed my program exits back to the shell?
Bash invokes the command also via folk/exec via something like this:
childPid = fork();
if (childPid == 0){
executeCommand(cmd); //calls execvp
} else {
if (isBackgroundJob(cmd)){
record in list of background jobs
} else {
waitpid (childPid);
}
}
Since from bash's point of view, the parent of your program is the child, it would return to prompt input when it returns from waitpid(childPid).
Is there a way to stay within the program and continue functioning as it was but with a new parent?
It might be a bit difficult if you want to "re-attach", but it's not impossible:
Attach to a processes output for viewing
https://unix.stackexchange.com/questions/58550/how-to-view-the-output-of-a-running-process-in-another-bash-session
Reference:
http://www.cs.cornell.edu/Courses/cs414/2004su/homework/shell/shell.html

execvp/fork -- how to catch unsuccessful executions?

Right now I'm writing a C program that must execute a child process. I'm not doing multiple child processes simultaneously or anything, so this is fairly straightforward. I am definitely executing the built-in shell programs (i.e. things like cat and echo) successfully, but I also need to be able to tell when one of these programs fails to execute successfully. I'm trying this with the following simplified code:
int returnStatus; // The return status of the child process.
pid_t pid = fork();
if (pid == -1) // error with forking.
{
// Not really important for this question.
}
else if (pid == 0) // We're in the child process.
{
execvp(programName, programNameAndCommandsArray); // vars declared above fork().
// If this code executes the execution has failed.
exit(127); // This exit code was taken from a exec tutorial -- why 127?
}
else // We're in the parent process.
{
wait(&returnStatus); // Wait for the child process to exit.
if (returnStatus == -1) // The child process execution failed.
{
// Log an error of execution.
}
}
So for example, if I try to execute rm fileThatDoesntExist.txt, I would like to consider that a failure since the file didn't exist. How can I accomplish this? Also, while that execvp() call successfully executes built-in shell programs, it doesn't execute programs in the current directory of the executable (i.e. the program that this code is running inside of); Is there something else that I have to do in order to get it to run programs in the current directory?
Thanks!
This is a classic problem with a very elegant solution. Before forking, create a pipe in the parent. After fork, the parent should close the writing end of the pipe, and block attempting to read from the reading end. The child should close the reading end and set the close-on-exec flag, using fcntl, for the writing end.
Now, if the child calls execvp successfully, the writing end of the pipe will be closed with no data, and read in the parent will return 0. If execvp fails in the child, write the error code to the pipe, and read in the parent will return nonzero, having read the error code for the parent to handle.
wait(2) gives you more than just the exit status of the child process. In order to get the real exit status, you need to use the WIFEXITED() macro to test if the child exited normally (as opposed to abnormally via a signal etc.), and then use the WEXITSTATUS() macro to get the real exit status:
wait(&status);
if(WIFEXITED(status))
{
if(WEXITSTATUS(status) == 0)
{
// Program succeeded
}
else
{
// Program failed but exited normally
}
}
else
{
// Program exited abnormally
}
In order for execvp(3) to run a program in the current directory, you either need to add the current directory to your $PATH environment (generally not a good idea), or pass it the full path, e.g. use ./myprogram instead of just myprogram.
In terms of failure detection, if an exec() function replaces the current process with a new one, then the current process is gone; it doesn't matter if the executed program decides that what it has been asked to do is a success or failure. However, the parent process from before the fork can discover the child's exit code which would likely have the command success/failure information.
In terms of finding executables, execvp() duplicates the action of the shell, searching the current path. If it is not finding executables in the working directory, it is likely that directory is not in the search path (or the files are not actually executable). You can try specifying them by a full path name.
If you simply want to run a command and wait for the result, you might want to use the system() function which handles this for you, instead of building it yourself with fork/exec.

What's the purpose of daemonize like this?

ngx_int_t ngx_daemon(ngx_log_t *log)
{
int fd;
switch (fork()) {
case -1:
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");
return NGX_ERROR;
case 0:
break;
default:
exit(0);
}
It seems pointless to me,as it only changes the pid,nothing else.
What's the benifit ?
The process becomes detached from the terminal so that when the user that started it quits his session, the process remains running.
Daemonizing is not only about the fork, it involves calling setsid(2) in the child process that detaches the process from the controlling terminal. If you run ps you can see such processes marked with a ? in the tty column.
Also, when you start a daemon it returns the control to the shell right after the fork, rather than the shell having to wait for the process to terminate.
What this does is break the parent-child link. The parent who is waiting on the child will stop waiting because the child will spawn the daemon and then exit.
The process also becomes the 'process group leader'. See this SO answer which contains much more detail:
Create a daemon with double-fork in Ruby

Resources