execlp() 在 fork() 之后无法正常工作

execlp() is not properly working after fork()

本文关键字:常工作 工作 之后 fork execlp      更新时间:2023-10-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: %sn", key);
launch_children(head);

return(0);
}

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

当我从命令行运行:./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

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

errno

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

从手册页:

如果指定的文件名不包含斜杠(/(字符,则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 +++