简体   繁体   English

使用 `clone()` 创建子进程。 为什么 `wait()` 不等待它终止?

[英]Created child process with `clone()`. Why does `wait()` not wait for it to terminate?

I'm trying to run some code inside a separate UTS namespace, and I've been trying to do it in C.我正在尝试在单独的 UTS 名称空间内运行一些代码,并且我一直在尝试在 C 中执行此操作。

I have a parent function with the following code:我有一个父 function,代码如下:

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;
}

which creates a new process and SHOULD wait for it to finish its execution.它创建了一个新进程并且应该等待它完成它的执行。

The 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'd like to run any command before the parent shutting up.我想在父母闭嘴之前运行任何命令。
The problem is that some commands (eg /bin/ls ) manage to execute, other (slower) commands (eg /bin/sh ) are shut down by the end of parent.问题是一些命令(例如/bin/ls )设法执行,其他(较慢的)命令(例如/bin/sh )在父级结束时关闭。

Since I used a wait function, I can't understand why the execution is stopping.由于我使用了 wait function,我不明白为什么执行停止了。

I tried using a sleep in the parent after the clone, and it delays the end of the program.我尝试在克隆之后在父级中使用睡眠,它延迟了程序的结束。 This should mean that the problem is that the parent doesn't wait for its child.这应该意味着问题是父母没有等待它的孩子。

I tried both wait and waitpid, but the process still ended. wait 和 waitpid 都试过了,进程还是结束了。

Can the problem be the spawn of a new process ( /bin/sh )?问题可能是新进程 ( /bin/sh ) 的产物吗? How can I fix?我该如何解决?

Edit :编辑

This should be a reproducible example这应该是一个可重现的例子

#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;
}

Extract from man page of clone从克隆的手册页中提取

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 ()).终止信号在标志的低字节 ( clone ()) 或 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).如果此信号指定为SIGCHLD以外的任何信号,则父进程在使用wait (2) 等待子进程时必须指定 __WALL 或 __WCLONE 选项。 If no signal (ie, zero) is specified, then the parent process is not signaled when the child terminates.如果没有指定信号(即零),则当子进程终止时,父进程不会收到信号。

So, answer is clear.所以,答案很明确。 You did not specify a signal, so you are not notified when your child terminates, so wait has nothing to wait.您没有指定信号,因此当您的孩子终止时您不会收到通知,因此 wait 无需等待。

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

should solve the problem (at least, without it, you have no chance to have wait working)应该解决问题(至少,没有它,你没有机会等待工作)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM