What's the purpose of daemonize like this? - c

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

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.

Use C to exit ssh session to linux

I"m running a program that runs over ssh session. Meaning I connect to a linux using putty, the program starts, using the /etc/bash.bashrc file. At some point the program suppose to end and with it the ssh session via putty should disconnect.
What I"ve done untill now with a code below, and it doesn't work: the program exits, and stays in linux shell, meaning the putty is connected. What I expected is the command "exit" to end the putty ssh session.
char file_name[20];
pid_t pid = fork();
if (pid == 0)
{
printf("Starting vi\r\n");
char external_cmd[200] = "vi ";
strcat(external_cmd, file_name);
system(external_cmd);
} else
{
waitpid(pid,0,0);
printf("Exit..\r\n");
system("exit");
}
thanks for the help.
The easiest solution is to start your C program with exec so that it replaces the shell. The SSH session will naturally end when the program exits.
$ exec your_program
This code doesn't accomplish anything:
system("exit");
system() runs a child process under sh:
The system() function shall behave as if a child process were
created using fork(), and the child process invoked the sh utility
using execl() as follows:
execl(<shell path>, "sh", "-c", command, (char *)0);
So, your call to system() starts a sh process, which then executes the exit command you passed to it - and the child process exits, doing nothing to the parent processes.
You can kill the parent shell, though, by obtaining the PID of the parent process with getppid() and then calling kill() to kill it:
#include <unistd.h>
#include <signal.h>
...
pid_t parent = getppid();
kill( parent, SIGKILL );
SIGKILL is probably a bit extreme - it kills a process immediately, with no chance for the process to clean up after itself, but it will work (unless you're running a non-root setuid child process in this case - if you don't know what that is, don't worry about it.). SIGTERM is a less-extreme signal, but since it can be caught or blocked it isn't guaranteed to end a process. SIGINT is the equivalent of CTRL-C and may also work, but again the process can catch or ignore the signal. SIGQUIT can also be used, but it's purpose is to cause the process to quit and dump a core file, which you probably don't want.

In a basic Shell Program in C, how to exit all processes associated with a parent?

I am writing a basic shell program for a university assignment, and i need to test for when the user enters the string "exit". When this happens the program should quit.
I can test for this successfully, but if i have forked new processes that have dealt with an strerror in my program, i have to keep entering exit for however many active processes are running at that current time.
Is there a way of exiting all associated processes with a program under this condition?
Cheers.
As said in comments, you should not spawn interactive processes in the background (at least how your shell and your command will handle the only stdin?).
Also as a shell you should keep track of all spawned processes (in background) so that you are able to catch their return code, as done in sh/bash (at least). For exemple in bash:
> sleep 1 &
[1] 8215
>
(1 sec later)
[1]+ Terminated sleep 1
So if you have the list of existing children you can send SIGINT/SIGKILL to all of them.
Whatever if you really want to be sure to kill everyone you should use process group (PG) killing. Using kill() function with PID=0 sends the kill signal to all processes in the same process group than you.
So you can start your shell by setting a new process group (to be sure to not kill something else), and this PG will be inherited by your children (appart if a child set a new PG of course).
This would looks like:
// at the begining of your main code
// try to get a new process group for me
x = setpgid(0,0);
if (x == -1) {
perror("setpgid");
exit(1);
}
(…)
// here you're about to exit from main, just kill
// all members of your group
kill(0, SIGINT); // send an INT signal
kill(0, SIGKILL); // paranoid: if a child catch INT it will get a KILL
// now you can exit, but you're probably dead 'cause you
// also receive the SIGINT. If you want to survive you have to
// catch SIGINT, but you will not catch KILL whatever
If it is needed for you to survive the kill you may catch the signal using signal() or better sigaction() so that you will not be killed and so able to perform other before-exit actions.

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

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.

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.

Resources