Use ‘clone()’ to create the child process. Why doesn’t ‘wait()’ wait for it to terminate?

Use ‘clone()’ to create the child process. Why doesn’t ‘wait()’ wait for it to terminate? … here is a solution to the problem.

Use ‘clone()’ to create the child process. Why doesn’t ‘wait()’ wait for it to terminate?

I’m trying to run some code in a separate UTS namespace, and I’ve been trying to do it in C.

I have a parent function that contains the following code:

void run (char **args, int arglen) {
    printf("[*] Starting PID: %d\n", getpid());

int i=1;
    cmd = concat_args(args, arglen);

pid_t child_pid = clone(child_container, child_stack+STACK_SIZE, CLONE_NEWUTS | CLONE_NEWPID, NULL);

int status;
    wait(&status);
    printf("[*] Exit code: %d", status);
    return;
}

It creates a new process and should wait for it to finish executing.

Child has the following code:

void child_container () {
    printf("This is the container!\n");
    printf("[*] Child PID: %d\n", getpid());
    system(cmd);
    printf("test\n");
}

And I want to run any command before the parent shuts down.
The problem is that some commands (e.g. /bin/ls) manage to execute, and other (slower) commands (e.g. /bin/sh) close parent at the end.

Because I used the wait function, I don’t understand why the execution stops.

I tried using sleep in the parent after cloning and it delayed the end of the program. This should mean that the problem is that the parent is not waiting for its child.

Wait and waitpid tried, but the process ended.

Could the problem be the product of a new process (/bin/sh)? How do I fix it?

Edit:

This should be a reproducible example

<pre class=”lang-c prettyprint-override”>#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUF_SIZE 0x3ff
#define STACK_SIZE 8192

static char child_stack[STACK_SIZE];
char *cmd;

char *concat_args(char **args, int arglen);
void child_container ();
void parse_command(char *cmd, char **args, int argc);
void run (char **args, int arglen);

char *concat_args(char **args, int arglen) {
char *cmd = (char *)malloc((BUF_SIZE+1)*sizeof(char));
memset(cmd, 0, BUF_SIZE+1);
strncat(cmd, args[0], BUF_SIZE);
for (int i=1; i<arglen; i++) {
strncat(cmd, " ", BUF_SIZE);
strncat(cmd, args[i], BUF_SIZE);
}
return cmd;
}

void run (char **args, int arglen) {
printf("[*] Starting PID: %d\n", getpid());

int i=1;
cmd = concat_args(args, arglen);

pid_t child_pid = clone(child_container, child_stack+STACK_SIZE, CLONE_NEWUTS | CLONE_NEWPID, NULL);
sleep(1);
int status, e_code;
e_code = wait(&status);
if (e_code == -1) {
perror("wait");
}
printf("[*] Exit code: %d\n[*] Status: %d\n", e_code, status);
return;
}

void child_container () {
printf("This is the container!\n");
printf("[*] Child PID: %d\n", getpid());
system(cmd);
printf("test\n");
}

void parse_command(char *cmd, char **args, int argc) {
if (!strcmp(cmd, "run")) {
run(args, argc-2);
} else {
error("No such command!");
}
}

int main(int argc, char **argv) {

const char *format = "./container run [cmd] [args]";
if (argc < 3) {
error("Wrong format!\nThe commands must be formatted in the following way:\t./container run [cmd] [args]");
return 0;
}

char *cmd = argv[1];
char **args = &argv[2];

parse_command(cmd, args, argc);
return 0;
}

Solution

Clone an excerpt from a man page

The child termination signal
When the child process terminates, a signal may be sent to the parent. The termination signal is specified in the low
byte of flags (clone()) or in cl_args.exit_signal (clone3()). If this signal is specified as anything other than
SIGCHLD, then the parent process must specify the __WALL or __WCLONE options when waiting for the child with wait (2).
If no signal (i.e., zero) is specified, then the parent process is not signaled when the child terminates.

So, the answer is clear. You don’t specify a signal, so you won’t be notified when your child terminates, so there’s nothing to wait for.

    pid_t child_pid = clone(child_container, child_stack+STACK_SIZE, CLONE_NEWUTS | CLONE_NEWPID | SIGCHLD, NULL);

It should solve the problem (at least, you don’t have a chance to make wait work without it).

Related Problems and Solutions