fork - Can I exit from parent? - c

I have written a code which will call exec as shown below. But if I call isValid from main, both child and parent process are returning and I am getting the output twice.
I want to get the out of the exec and want to check the return value in main only once. which process I need to exit inorder to make this work properly?
int isValid(void)
{
int number, statval;
int child_pid;
child_pid = fork();
if(child_pid == -1) { printf("Could not fork! \n"); exit( 1 ); }
else if(child_pid == 0)
{
execl(...); // Child
}
else
{
// Parent
waitpid( child_pid, &statval, WUNTRACED );
if(WIFEXITED(statval))
{
if (WEXITSTATUS(statval) == 0)
return 1;
else
return 0;
}
else
printf("Child did not terminate with exit\n");
}
return 0;
}
int main(void)
{
if (isValid())
{
printf("Valid\n");
}
else
{
printf("Invalid\n");
}
}

The doubled output may occur when the execl fails. The code above does not check the execl return value. Actually the execl returns only in case of failure so there is no need to check the returned value but it is necessary to handle error anyway.
EDIT:
If the exec fails then:
Child's isValid() returns 0 at the end of the function and the main prints "Invalid"
Parent waits for the child exit and then WIFEXITED is true because child exits and WEXITSTATUS is 0 because the child exits normally. Parent's isValid returns 1 and "Valid" is printed.

#include <sys/shm.h>
int *tabPID;
int isValid(void)
{
int number, statval;
if(fork() == 0){
tabPID[1] = getpid();
execl(...); // Child
return -1;
}
// Parent
tabPID[0]=getpid();
usleep(10);//as Basile Starynkevitch suggests
waitpid(tabPID[1], &statval, WUNTRACED );
if(WIFEXITED(statval))
{
if (WEXITSTATUS(statval) == 0)
return 1;
else
return 0;
}
else
printf("Child did not terminate with exit\n");
return 0;
}
int main(void)
{
shmId = shmget(1234, 2*sizeof(int), IPC_CREAT|0666);
tabPID = shmat(shmId, NULL, 0);
if (isValid())
{
printf("Valid\n");
}
else
{
printf("Invalid\n");
}
}

You probably should do some tiny things (perhaps some usleep(3) for a few milliseconds) after the fork but before the waitpid to have some real chance to get the waitpid(2) call succeed. Otherwise, it could happen that the other process won't be scheduled to run.
BTW, you should test the return value from waitpid, .e.g. code
statval = 0;
pid_t wpid = waitpid(child_pid, &statval, WUNTRACED );
if (wpid>0) {
assert (wpid == child_pid);
if (WIFEXITED(statval)) {
if (WEXITSTATUS(statval) == 0)
return 1;
At last, regarding the title of your question, read job control wikipage, read several chapters of Advanced Linux Programming, and consider using daemon(3)
Also, just after the execl be sure to put
perror("execl");
exit(EXIT_FAILURE);
to handle the rare case of execl failure.

Related

Multiprocess parent return value

Im wondering about the nature of the variable status and when its returned in a function.
Ive set my function to get an error, but if I dont do return status >> 8(127) and instead do return status, I get a return value of 0.
Ive used return WEXITSTATUS (status) in the past and itd return the correct status number.
My questions are if WEXITSTATUS actually does the operation status >> 8?
And when doing Multiprocessing and the parent process exists properly is it better to verify with WIFEXITED(status) then return WEXITSTATUS (status) rather than doing what I do?
int main {
int status;
int filedes[2];
pid_t pid_enfant;
pipe(filedes);
if (pid_child == 0) {
...
char *tab[] = {"/bin/bash", "-c", arg[1], NULL};
execv("/bin/bash", arg[1]);
return 1;
} else {
...
pid_t pid_child = wait(&status);
return status >> 8; -- // return this vs this below
//if (WIFEXITED(status) && pid_valide == pid_child)
//return WEXITSTATUS (status);
}
}
To answer your your question regarding WEXITSTATUS, the answer is yes; it is meant to shift the status down by 8 bits.
WEXITSTATUS(wstatus)
returns the exit status of the child. This consists of
the least significant 8 bits of the status argument that
the child specified in a call to exit(3) or _exit(2) or as
the argument for a return statement in main(). This macro
should be employed only if WIFEXITED returned true.
Further, it explicitly states that the value of WEXITSTATUS(wstatus) is only valid if WIFEXITED(wstatus) is non-zero. So for your code to be correct with this specification, you should have
pid_t pid_child = wait(&status);
if (WIFEXITED(status))
{
return WEXITSTATUS(status);
}
else
{
// child did not terminate normally
}
As to why you should check this, here's a toy example:
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int signal = /* choose your favourite signal, or 0 */;
switch (fork())
{
case -1:
perror("fork");
return -1;
case 0:
if (signal) { raise(signal); }
return 0;
default:
{
int status;
pid_t child = wait(&status);
printf("child=%d, status=%04x\n", child, status);
if (WIFEXITED(status))
{
puts("good exit");
return WEXITSTATUS(status);
}
else
{
puts("bad exit");
return -1;
}
}
break;
}
}
If we do not raise anything in the child and get a clean exit, we'll see child=..., status=0000 in the parent, and would take the 'good exit' branch returning 0, as expected. However, if we raise something like SIGSEGV in the child, then the parent will get child=..., status=008b. Now, if you blindly did status >> 8, then your parent would return 0 just like the 'good exit' path, but clearly the child did not exit cleanly.

waitpid hangs even though child process is dead

i have the following function:
int run_func(command history[MAX_INPUT_SIZE], char** args, int capacity) {
int need_to_wait = 1;
int i = 0;
char* arg = args[0];
int status;
while (arg != NULL) {
if (strcmp(arg, "&") == 0) {
need_to_wait = 0;
break;
}
arg = args[i++];
}
pid_t wait_pid;
pid_t pid = fork();
int res;
if (pid == 0) {
res = execvp(args[0], args);
if (res == -1) {
printf("exec failed\n");
fflush(stdout);
return 0;
}
} else if (pid < 0) {
printf("fork failed\n");
fflush(stdout);
return 0;
} else {
if (need_to_wait){
do {
wait_pid = waitpid(pid, &status, 0);
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
}
history[capacity - 1].pid = pid;
}
return 1;
}
the issue I have is that the bottom while loop, hangs and doesn't stop whenever I get an invalid command such as 'hello' from the user from the terminal until I press enter again.
this function is being called from another function that receives input from the user.
Copying comment into an answer.
Side issues:
Error messages should be printed to stderr, not stdout.
There's no need to save or test the return value from execvp() — if it returns, it failed; if it succeeds, it does not return.
Main observation:
You should almost certainly have an exit() or _exit() instead of return 0; in the error handling code after execvp(). When the command fails (hello?), then you end up with two processes running — one from the failed execvp() and one is the parent process. This is apt to confuse everything as you have two processes trying to read the terminal at the same time.

Child process hanging after call to system()

The problem is that either the parent or child process is not exiting. The child process prints its message and then the program hangs. Could be stuck at system() because this doesn't happen when the system() call is removed. The unhide_string() filters out non-letters and args is defined elsewhere. The command "cmd" that's passed to get_page() is valid.
int get_page(char* cmd) {
system(cmd);
return 0;
}
int main() {
char* args_s = unhide_string(args);
if (args_s == NULL) {
printf("Please run me again :)\n");
}
if (fork() == 0) {
get_page(args_s);
printf("Guess what I did :)\n");
}
free(args_s);
return 0;
}
Fixed by having the parent wait for the child process to finish. This allowed the program to properly terminate.
Revised fork code:
if (fork() == 0) {
get_page(args_s);
printf("Guess what I did :)\n");
} else {
waitpid(-1, NULL, 0);
}

How to wait for a child process and get its return value

I am trying to fork my C application, running on an embedded linux environment, and get its return value for failure/success analysis.
I looked at similar questions (e.g. this, this, this, this and some other Q/A..) but still can't get it to work.
code:
static int fork_test(const char *src, const char *dst)
{
int childExitStatus;
pid_t pid;
int status;
DEBUG_PRINT("forking");
pid = fork();
if (pid == 0) { // child
sleep(2);
DEBUG_PRINT("child - exiting");
exit(1);
}
else if (pid < 0) {
return -1;
}
else { // parent
int i;
for (i = 0 ; i < 10 ; i++)
{
pid_t ws = waitpid(pid, &childExitStatus, WNOHANG);
if (-1 == ws)
{
DEBUG_PRINT("parent - failed wait. errno = %d", errno);
return -1;
}
if (0 == ws)
{
DEBUG_PRINT("parent - child is still running");
sleep(1);
continue;
}
}
if (10 == i)
return -1;
DEBUG_PRINT("parent - done waiting");
if (WIFEXITED(childExitStatus)) /* exit code in childExitStatus */
{
DEBUG_PRINT("parent - got status %d", childExitStatus);
status = WEXITSTATUS(childExitStatus); /* zero is normal exit */
if (0 != status)
{
DEBUG_PRINT("parent - picked up bad exit status");
return status;
}
return 0;
}
else
{
DEBUG_PRINT("parent - bad exit route");
return -1;
}
}
}
This provided this output:
forking
parent - child is still running
parent - child is still running
parent - child is still running
child - exiting
parent - failed wait. errno = 10
note that errno=10 means ECHILD.
so i tried to add:
...
DEBUG_PRINT("forking");
signal(SIGCHLD,SIG_DFL);
pid = fork();
...
(or with SIG_IGN) with no difference.
I can successfully add a signal handler for SIGCHLD, and might be able to wait for signal, instead of the child process, with sigwait() or the likes, but it seems like a bad solution..
Any idea what I'm missing here?
$ uname -mrso
Linux 3.18.20 armv7l GNU/Linux
Your code nicely tests for "errors". Good.
But the code unfortunately misses to catch the case you are after, the one where waitpid() actually returns the child's PID.
You could achieve this like so:
for (i = 0 ; i < 10 ; i++)
{
pid_t ws = waitpid(pid, &childExitStatus, WNOHANG);
if (-1 == ws)
{
DEBUG_PRINT("parent - failed wait. errno = %d", errno);
return -1;
}
else if (0 == ws)
{
DEBUG_PRINT("parent - child is still running");
sleep(1);
continue;
}
DEBUG_PRINT("parent - successfully waited for child with PID %d", (int) ws);
break;
}

Forking in Linux and the use of setsid()

I have a sample code and I'm at loss in understanding how to figure out what's happening.
I'm only showing relevant parts. The problem is make_daemon().
From what I understand about forking is that code from close(0) onwards is executed by the child which should have a pid == 0.
What happens when the code hits return -1? Does the code return to the parent or does it exit? Does the child p process code execute if(share) in Monitor()?
This code is an extract from Monitor.c in mdadm.
Thanks in advance for any help.
int Monitor( struct mddev_dev *devlist,
char *mailaddr, char *alert_cmd,
struct context *c,
int daemonise, int oneshot,
int dosyslog, char *pidfile, int increments,
int share )
{
if (daemonise) {
int rv = make_daemon(pidfile);
if (rv >= 0)
return rv;
}
if (share)
if (check_one_sharer(c->scan))
return 1;
/* etc .... */
}
static int make_daemon(char *pidfile)
{
int pid = fork();
if (pid > 0) {
if (!pidfile)
printf("%d\n", pid);
else {
FILE *pid_file;
pid_file=fopen(pidfile, "w");
if (!pid_file)
perror("cannot create pid file");
else {
fprintf(pid_file,"%d\n", pid);
fclose(pid_file);
}
}
return 0;
}
if (pid < 0) {
perror("daemonise");
return 1;
}
close(0);
open("/dev/null", O_RDWR);
dup2(0,1);
dup2(0,2);
setsid();
return -1;
}
fork can return three types of return values:
a positive number: this only happens in the parent: it is the pid of a successfully created child.
zero: this is only returned in the child and indicates that this code now executes in the child. This is not the pid of the child, use getpid to obtain the pid of the child.
a negative value (commonly -1). This is also only ever returned in the parent and indicates that fork failed for whatever reason and no child was created.
As to what your code does: yes the child will continue at close(0); provided that a child was indeed created.
When your cild hits return -1 it will return to whatever function called make_daemon back in the parent and will continue execution at that point. Normally forked children would do whatever they are supposed to do and then call exit in order not to mess up what the parent was doing.

Resources