【问题标题】:execlp() is not properly working after fork()fork() 后 execlp() 无法正常工作
【发布时间】:2020-02-08 17:17:16
【问题描述】:

我正在编写函数,它接收链表中的值,然后使用传递到命令行的参数分叉进程并执行一个新进程。这是我为 prog2b.cc 提供的代码:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cplist.h"
#include <sys/time.h>
#include <iostream>
#include <sys/wait.h>
#include <errno.h>

struct timeval start, end;
char *key;

int launch_children(cplist *head){
    pid_t cpid;
    double execution_times = 0; 
    if(cpid = fork()  < 0 ){   // Important to trap errors
            std::cerr << "ARGH I'm likely in trouble, get me out of here!" << std::endl;
            exit(1);  // Important to exit on errors
        }else if (cpid == 0 ){
            std::cout << "Child process "<< getpid() << ". Running grep on " << key << head->path << std::endl;
            execlp("prog2b", "prog2b", "grep", "-R", key, head->path, NULL); 
            std::cerr << "Exec failed.. Why?" << std::endl;
            exit(1); // VERY IMPORTANT - DON'T LET CHILD KEEP RUNNING
    } else { // parent
            head->cpid = cpid;
            wait(NULL); 
            std::cout << "Child "<< cpid << "has terminated in " << execution_times;
    }
}



int main(int argc, char *argv[]){
    int i;
    int j = 0;
    cplist *head = (cplist*) malloc(sizeof(cplist));
    head->path = NULL;
    head->next = NULL;

    if(strcmp(argv[1], "-v") == 0){
        key = argv[2];
        for(i = 3; i < argc; i++){
            cpl_add(head, argv[i]);
            j++;
        }
    } else {
        key = argv[1];
        for(i = 2; i < argc; i++){
            cpl_add(head, argv[i]);
            j++;
        }
    }

    printf("key: %s\n", key);
    launch_children(head);


return(0);
}

我的程序应该从命令行获取键和路径值,然后子进程应该使用 'grep' '-r' 执行 execlp,并传入值。我正在努力让 exec 执行好好工作。我在手册页上花了很多时间让高管们试图更好地理解他们并测试其他高管,但我陷入了困境。 exec 进程不会运行。下面是一个例子来展示它现在是如何工作的:

当我从命令行运行:./prog2b 5678 /hw1/02/ 时,我的输出是:

key: 5678
Child process 70788. Running grep on 5678 /hw1/02
Exec failed.. Why?
key: 5678
Child process 70789. Running grep on 5678 /hw1/02
Exec failed.. Why?

正确的输出应该是:

key: 5678
Child process nnnnn. Running grep -R 5678 hw1/02

../../hw1/02/nYyLimCI:5678
../../hw1/02/ANFGmj97:5678
../../hw1/02/oFrtX8Sy:5678
../../hw1/02/UrYt9aBz:5678
../../hw1/02/wE1AMVeh:5678
../../hw1/02/F6TGJEiJ:5678
../../hw1/02/v1HG6zmh:5678
../../hw1/02/YyOSKcJG:5678


Child process nnnnn has terminated in a.bbbbbb seconds

我知道 exec 失败了,我尝试使用 errno 并输出“没有这样的文件或目录”。我发现它指的是第一个 prog2b,但是当更改为 ./prog2b 时,我相信它会导致分叉炸弹。我还没有完全掌握如何在 exec 中使用 grep,我觉得这可能是问题所在。希望这将有助于解决我在 fork 和 exec 方面的麻烦。我有一个 _add 和 _dump 的头文件和链表函数类,但我不相信这些是导致错误的原因

【问题讨论】:

  • "head-&gt;path" 是一个字符串。使用值"head-&gt;path" 另外:您的代码看起来不像 C。也许它是 C++?
  • if(cpid = fork() &lt; 0 ){...} 这是经典。

标签: c++ grep fork exec


【解决方案1】:

errno 设置为ENOENT(没有这样的文件或目录)这一事实告诉您execlp() 无法找到可执行文件。

来自the manual page

如果指定的文件名不包含斜杠 (/) 字符,execlp()execvp()execvpe() 函数会重复 shell 在搜索可执行文件时的操作。在PATH 环境变量中指定的以冒号分隔的目录路径名列表中查找该文件。如果未定义此变量,则路径列表默认为当前目录,后跟confstr(_CS_PATH) 返回的目录列表。 (这个confstr(3) 调用通常返回值"/bin:/usr/bin"。)

您当前的工作目录很可能在您的PATH 中,因此找不到可执行文件。一个简单的解决方案是在其名称前添加一个./

execlp("./prog2b", "prog2b", "grep", "-R", "key","head->path", NULL); 
// here ^^

未来提示:您可以使用 strace 准确查看 exec*() 尝试查看的位置:

$ strace -f -e execve ./prog2b 5678 /hw1/02/
execve("./prog2b ", ["./prog2b", "5678", "/hw1/02/"], [/* 40 vars */]) = 0
key: 5678
Child process 70788. Running grep on 5678 /hw1/02
execve("/usr/local/bin/prog2b", ["prog2b", "grep", "-R", "key","head->path"], [/* 40 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/bin/prog2b", ["prog2b", "grep", "-R", "key","head->path"], [/* 40 vars */]) = -1 ENOENT (No such file or directory)
execve("/bin/prog2b", ["prog2b", "grep", "-R", "key","head->path"], [/* 40 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/local/games/prog2b", ["prog2b", "grep", "-R", "key","head->path"], [/* 40 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/games/prog2b", ["prog2b", "grep", "-R", "key","head->path"], [/* 40 vars */]) = -1 ENOENT (No such file or directory)
Exec failed.. Why?
+++ exited with 1 +++

【讨论】:

  • 当我简单地在第一个 prog2b 前面添加“./”并运行它时,它给我的输出更差。在两个孩子之后,它使用 grep 作为密钥并继续分叉和执行
  • @JoshPokorny 这是一个完全不同的逻辑问题,我只是在回答你的问题。
猜你喜欢
  • 1970-01-01
  • 2022-01-13
  • 2016-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-07
  • 2019-08-10
相关资源
最近更新 更多