我正在编写一个C程序来模拟一个简单的shell。这个shell基本上会像任何其他shell(ls,cat等)一样评估命令,以及处理流水线和重定向。
目前,我试图通过获取用户输入,对其进行标记并执行所提供的命令(例如仅执行“ls”而不是“ls -l”)来开始。但是,我在分叉时遇到了很多困难。似乎每次我分叉,出现问题并创建数百个相同的进程,导致我的计算机冻结,我不得不重新启动。代码似乎是正确的,但我不知道是什么导致了这种行为。下面是我的代码的相关部分(主方法和输入标记化方法)。
int main() {
char inputLine[512]; //user input
char *args[10]; //arguments
char* pathVar = "/bin/";//path for argument
char programPath[512]; //pathVar + args[0]
int n; //count variable
//loop
while (1) {
//print prompt, get input
printf("input> ");
fgets(inputLine, 512, stdin);
n = tokenizer(inputLine, args);
//fork process
pid_t pid = fork();
if (pid != 0) { //if parent
wait(NULL);
} else { //if child
//format input for execution
strcpy(programPath, pathVar);
strcat(programPath, args[0]);
//execute user command
int returnVal = execv(programPath, args);
}
}
return 0;
}
int tokenizer(char *input, char *args[]) {
char *line; //current line
int i = 0; //count variable
line = input;
args[i] = strtok(line, " ");
do {
i++;
line = NULL;
args[i] = strtok(line, " ");
} while (args[i] != NULL);
return i;
}
答案 0 :(得分:1)
全部放在一起:
您需要检查fork
和execv
是否有失败。
在exit
失败后(可能在execv
失败后),您应该fork
。
您需要将\n
添加到strtok
分隔符(或以其他方式从输入行中删除换行符)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAXARGS 10
#define PATH "/bin/"
int main() {
char inputLine[BUFSIZ];
char *args[MAXARGS];
char programPath[BUFSIZ + sizeof(PATH) + 10];
while (1) {
printf(":-> ");
if (fgets(inputLine, BUFSIZ, stdin) == NULL) /* ctrl-D entered */
break;
tokenize(inputLine, args);
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid != 0) { /* parent */
wait(NULL);
} else { /* child */
strcpy(programPath, PATH);
strcat(programPath, args[0]);
execv(programPath, args); /* will not return unless it fails */
perror("execv");
exit(EXIT_FAILURE);
}
}
return 0;
}
int tokenize(char *input, char *args[]) {
int i = 0;
args[0] = strtok(input, " \n");
for (i = 0; args[i] && i < MAXARGS-1; ++i)
args[++i] = strtok(NULL, " \n");
return i;
}
答案 1 :(得分:0)
您应检查 execv 是否失败,并确保在子块结尾处退出()。
//execute user command
int returnVal = execv(programPath, args);
// check return from execv
if (returnVal < 0) {
perror("execv");
exit(1);
}
此外,请注意在此上下文中使用 strcpy 等函数,因为它们可能会导致缓冲区溢出。如果不受信任的攻击者类型正在与您的shell通信,则此类安全问题可能会让他们突破“沙箱”。