execve失败 - 忽略退出语句[重复]

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

这个问题在这里已有答案:

fgetsexecve混合在一起时,我有一个奇怪的问题。

我有一个函数从文件中读取行,并通过解析它们自己的函数或使用execve来执行它们。为简单起见,我的测试文件只有外部函数:

echo whoowhee
lx
ls
dir

第二个命令,lx不存在,所以在那一点上execve应该失败。

这是我从文件中读取的代码:

  while(fgets(line, 1024, testfile) != NULL){
    if(strlen(line) < 3){continue;}
    if(line[0] == '#'){continue;}

    printf("%s%s", value("PROMPT"), line); // Emulates the prompt

    //Terminates line at right place to simulate input
    line[strlen(line)-2] = '\0';

    execute(line);

    Var *prompt = retrieveVar("PROMPT");
    sprintf(prompt->value, "< Executing script... - [%s] > $ ", value("EXITCODE"));

    lineNo++; 
  }

这是我的fork-exec块:

  if(pid == 0){ // Child

    // For loop for using all paths
    for(int i = 0; i < pathn; i++){
      args[0] = paths[i];

      // Executes command path[i] with arguments args with environment envp
      execve(paths[i], args, envp);
    }

    perror("execve");
    exit(0);
  }
  else if(pid > 0){ //Parent
    current_pid = pid;

    if(setpgid(pid, pid) != 0) perror("setpid");

    // Waits if background flag not activated.
    if(BG == 0){
      // WUNTRACED used to stop waiting when suspended
      waitpid(current_pid, &status, WUNTRACED);

        if(WIFEXITED(status)){
          setExitcode(WEXITSTATUS(status));
        }
        else if(WIFSIGNALED(status)){
          printf("Process received SIGNAL %d\n", WTERMSIG(status));
        }
    }
  }
  else{
    perror("fork()");
  }

由于execve需要程序的绝对路径,paths是程序应该存在的可能路径的数组.BG说明进程是否应该在后台执行,value("EXITCODE")是进程的exitcode,并且execute是函数,你猜对了它,执行线。

现在,这是我运行testfile时的输出,代码原样如下:

<Welcome to Eggshell> $ echo whoowhee
whoowhee
< Executing script... - [0] > $ lx
execve: No such file or directory
< Executing script... - [0] > $ ls
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt
< Executing script... - [0] > $ dir
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt
< Executing script... - [0] > $ dir
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt

如你所见,dir运行两次。

如果我在文本文件中添加另一个无意义的命令,问题就不会停在这里:

echo whoowhee
lx
onetimesoneistwo
ls
dir

如果我尝试运行该函数,它最终会陷入无限循环。不仅如此,这次它一直在不停地运行整个文件!

但是,如果我从exit位中删除fork-exec,并重新运行该函数,则会出现以下情况:

<Welcome to Eggshell> $ echo whoowhee
whoowhee
< Executing script... - [0] > $ lx
execve: No such file or directory
< Executing script... - [0] > $ onetimesoneistwo
execve: No such file or directory
< Executing script... - [0] > $ ls
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt
< Executing script... - [0] > $ dir
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt
< Executing script... - [0] > $ ls
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt
< Executing script... - [0] > $ dir
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt
< Executing script... - [0] > $ onetimesoneistwo
execve: No such file or directory
< Executing script... - [0] > $ ls
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt
< Executing script... - [0] > $ dir
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt
< Executing script... - [0] > $ ls
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt
< Executing script... - [0] > $ dir
add-on  codecov.yml documentation  eggshell.c  LICENSE  Makefile        README.md  switch.sh      val.log
ci  createfile.txt  eggshell       eggshell.h  main.c   Makefile-Clang  src        testinput.txt

令人惊讶的是,它不是一个无限循环!确定onetimesoneistwo运行4次之后的每个命令,onetimesoneistwo本身运行两次,但至少它是什么。

我猜想execve失败导致分叉的孩子永远不会终止,但那么为什么exit会导致无限循环而没有exit之后复制所有指令?

有趣的故事是,如果我正常运行程序,自己提供输入而不是从文件中获取输入,同样的事情不会发生,所以我的猜测是我的源函数或我的fork-exec严重错误码。

c fork fgets execve
1个回答
0
投票

对我来说,解决方案似乎是使用_exit而不是exit。如果execve失败,使用前者会立即杀死孩子,而不是有一个奇怪的无限循环效果。

虽然我仍然不知道为什么exit造成无限循环,为什么_exit工作在exit不...

更新:这不是很好。解决问题的方法是在存在之前的循环中使用fgets,并将所有行存储在字符串数组缓冲区中。然后,在下一个循环中,我只是逐个读取数组中的行。由于exit正在重置文件指针,因此解决方案是不再使用循环内的文件指针。

© www.soinside.com 2019 - 2024. All rights reserved.