C程序如何使用execve重新启动?

问题描述 投票:0回答:1

我正在尝试编写一个可自行重启一次的C程序。我的方法是转到fork,并在子进程调用中execve。我以为我会看到两次打印Hello。这在这里打印两次main,但是即使我注释掉了execve,我也认为我在这里没有正确使用execve。该二进制文件称为“ restartOnce”。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>

int main(int argc, char *argv[]) {
    pid_t pid = fork();
    printf("Main.\n");
    if (pid == 0) { 
        char *argv = "hello"; // To silence gcc compiler warning.
        char *env  = "world"; // To silence gcc compiler warning.  
        execve("restartOnce", &argv, &env);
    } else {
        wait(NULL);
        printf("Done.\n");
    }
    return 0;
}
c
1个回答
0
投票

我不确定您要完成什么,但是我看到有两点要注意。我们必须正确执行execve()调用,此外,我们还必须避免产生叉式炸弹,并且此代码应该可以实现。

有很多避免叉形炸弹的方法,但是我选择在环境中设置一些东西,当孩子看到此环境变量时,它将知道不会继续。

所以execve()需要它自己的argv,它是指向各个字符串的指针的数组(末尾带有NULL指针,并且完全可以传递从main获得的相同参数。)>

第三个参数类似于argv,但它是环境变量列表,而不是命令行参数。它具有TERM=vt100PATH=/bin/...等许多其他内容。尽管您可以使用getenv("PATH")单独获取环境变量,但Unix / Linux系统提供了类似argv的变量environ

此变量在<unistd.h>中声明,但需要定义_GNU_SOURCE宏才能公开。

完成后,您可以通过这种方式安全地呼叫execve

#define _GNU_SOURCE
#include <unistd.h>

    ...
    execve("restartOnce", argv, environ);

为了避免产生叉式炸弹,该程序要做的第一件事就是寻找环境变量FORKBOMB-如果设置了该变量,则说明我们处于子进程中,应该停止分叉其他子进程,或者做其他事情(该程序的实际工作?)

但是如果我们在父级中-没有看到变量-我们通过将其放在子进程可以看到的自己的环境中来主动set

变量:putenv("FORKBOMB=no");

一个小小的补充:程序要做的第一件事就是报告它已经启动,并且它提供了自己的进程ID,以便您知道它在做什么。

也许我误解了这个问题,但这就是我要解决的我想像中的问题:

#define _GNU_SOURCE // for "environ"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>

int main(int argc, char *argv[])
{
    printf("Main in pid %d.\n", getpid() );

    if (getenv("FORKBOMB") != 0)
    {
        printf("**We're in the second child, no more forking\n");
        exit(0);
    }

    putenv("FORKBOMB=no");

    pid_t pid = fork();

    if (pid == 0) {
        execve("restartOnce", argv, environ);
    } else {
        wait(NULL);
        printf("Done.\n");
    }
    return 0;
}

[还有很多其他方法可以避免产生叉式炸弹,但这与任何使想法得以传播的方法一样好,其他方法可能会引起他们的喜爱。

EDIT

但是,考虑到这一点,我很确定无论您想要完成什么,这都是没有必要的,除非这只是一种学习练习。

我可以想象的两件事是:

1)您需要与父进程分离,以便可以在后台运行,就像守护进程一样。在这种情况下,您不必执行,只需在子进程中执行守护程序即可。

2)如果程序更改了[[itself

-也许下载了其自身的更新版本,则它确实必须调用exec来获取新的可执行文件,但是不需要fork()所以我不确定我们(或至少我)知道您要完成的工作。
© www.soinside.com 2019 - 2024. All rights reserved.