【发布时间】:2010-04-15 17:39:40
【问题描述】:
我正在用 c 实现一个简单版本的 linux shell。
我已经成功编写了解析器,但是我在分叉子进程时遇到了一些麻烦。但是,我认为问题出在数组、指针等方面,因为刚开始使用这个项目的 C 语言,对它们还不是很了解。
我遇到了分段错误,不知道从哪里来。非常感谢任何帮助。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#define MAX_COMMAND_LENGTH 250
#define MAX_ARG_LENGTH 250
typedef enum {false, true} bool;
typedef struct {
char **arg;
char *infile;
char *outfile;
int background;
} Command_Info;
int parse_cmd(char *cmd_line, Command_Info *cmd_info)
{
char *arg;
char *args[MAX_ARG_LENGTH];
int i = 0;
arg = strtok(cmd_line, " ");
while (arg != NULL) {
args[i] = arg;
arg = strtok(NULL, " ");
i++;
}
int num_elems = i;
if (num_elems == 0)
return -1;
cmd_info->infile = NULL;
cmd_info->outfile = NULL;
cmd_info->background = 0;
int iarg = 0;
for (i = 0; i < num_elems-1; i++)
{
if (!strcmp(args[i], "<"))
{
if (args[i+1] != NULL)
cmd_info->infile = args[++i];
else
return -1;
}
else if (!strcmp(args[i], ">"))
{
if (args[i+1] != NULL)
cmd_info->outfile = args[++i];
else
return -1;
}
else
cmd_info->arg[iarg++] = args[i];
}
if (!strcmp(args[i], "&"))
cmd_info->background = true;
else
cmd_info->arg[iarg++] = args[i];
cmd_info->arg[iarg] = NULL;
return 0;
}
void print_cmd(Command_Info *cmd_info)
{
int i;
for (i = 0; cmd_info->arg[i] != NULL; i++)
printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]);
printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]);
printf("infile=\"%s\"\n", cmd_info->infile);
printf("outfile=\"%s\"\n", cmd_info->outfile);
printf("background=\"%d\"\n", cmd_info->background);
}
void get_cmd(char* str)
{
fgets(str, MAX_COMMAND_LENGTH, stdin);
str[strlen(str)-1] = '\0'; //apaga o '\n' do fim
}
pid_t exec_simple(Command_Info *cmd_info)
{
pid_t pid = fork();
if (pid < 0)
{
perror("Fork Error");
return -1;
}
if (pid == 0)
{
execvp(cmd_info->arg[0], cmd_info->arg);
perror(cmd_info->arg[0]);
exit(1);
}
return pid;
}
int main(int argc, char* argv[])
{
while (true)
{
char cmd_line[MAX_COMMAND_LENGTH];
Command_Info cmd_info;
printf(">>> ");
get_cmd(cmd_line);
if ( (parse_cmd(cmd_line, &cmd_info) == -1) )
return -1;
parse_cmd(cmd_line, &cmd_info);
if (!strcmp(cmd_info.arg[0], "exit"))
exit(0);
pid_t pid = exec_simple(&cmd_info);
waitpid(pid, NULL, 0);
}
return 0;
}
谢谢。
【问题讨论】:
-
您可以使用 gdb 运行您的程序,当它出现段错误时,您可以键入
bt以获取堆栈的回溯。这应该可以帮助您准确确定崩溃的位置。 -
str[strlen(str)-1] = '\0';不安全,如果 str = "";
-
确实,这对 gdb 来说是一项完美的任务……而且,更重要的是,这是一项让您熟悉 gdb 的完美任务。能够使用 gdb 跟踪段错误位置将是最重要的调试技能之一,尤其是对于新的 C 开发人员。
-
请考虑默认使用 strtok_r(),如果/当您在线程中处理命令时,它将为您省去很多麻烦。 strtok() 只需要一个额外的指针即可将其正在进行的工作保存在线程本地存储中。