2010-04-15 56 views
1

我在c中实现了一个简单版本的linux shell。简单的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; 
} 

谢谢。

+1

您可以用gdb运行您的程序,当它SEG-故障,您可以用'bt'得到一个背跟踪堆栈。这应该可以帮助你确切地确定你在哪里崩溃。 – 2010-04-15 17:41:15

+1

str [strlen(str)-1] ='\ 0';是不安全的,如果str =“”; – Ernelli 2010-04-15 17:43:29

+1

事实上,这对于gdb来说是一项完美的任务...更重要的是,它是熟悉gdb的完美任务。能够使用gdb来跟踪段错误位置将是最重要的调试技巧之一,对于新的C开发人员尤其如此。 – Rakis 2010-04-15 17:48:40

回答

4

问题出在cmd_info->arg,声明为char **arg,并且您从不为其分配内存。

因此,当您尝试访问它以保存像这样的参数cmd_info->arg[iarg++] = args[i]时,您正在取消引用未初始化的指针,导致分段错误。

一个解决办法是改变Command_Info结构申报arg这样的:

char *arg[MAX_ARG_LENGTH];