2015-02-10 84 views
2

我被要求爲操作系統類實現我自己的shell。系統調用execve不會使用ls函數返回

我的殼運行的每個命令很好,除了LS不會在execve的,因爲CD,CP,MV,和所有其它主要的命令返回還好這是奇怪的回報。

ls仍然顯示正確的輸出(文件夾中的文件列表),但只是繼續運行(execve掛起並需要回車完成)。

像-l,-a之類的所有選項也可以正常工作,並具有相同的問題。

編輯:我修改了代碼,以徹底避免任何內存泄漏(我用的valgrind跟蹤它們),增加了一些評論,所以你可以看到發生了什麼事情,但LS依然沒有回來。以下是更新版本:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <signal.h> 
#include <strings.h> 
#include <sys/types.h> 
#include <sys/wait.h> 

#define MAXPATHLEN 40 
#define MAXSIZE 100 
#define MAXARGS 10 

static char cwd[MAXPATHLEN]; 

typedef void (*sighandler_t)(int); 

void handle_signal(int signo); 
void parse_command(char *command, char **arguments); 

int main(int argc, char *argv[], char *envp[]) 
{ 
    int status; 
    char *command; 
    char **arguments; 

    signal(SIGINT, SIG_IGN); 
    signal(SIGINT, handle_signal); 
    while(1) { 
     //Allocating memory 
     command = calloc(MAXSIZE, sizeof(char)); 
     arguments = calloc(MAXARGS, sizeof(char *)); 

     //Print shell name and cwd 
     getcwd(cwd,MAXPATHLEN); 
     printf("[MY_SHELL]:%s$ ", cwd); 
     parse_command(command, arguments); 

     //Displays command and arguments 
     printf("Command is %s\n", command); 
     int i; 
     for(i=0; arguments[i] != NULL; ++i){ 
      printf("Argument %d is %s\n", i, arguments[i]); 
     } 

     //Fork exec code 
     if (fork() != 0){ 
      waitpid(1, &status, 0); 
     } else{ 
      execve(command, arguments, 0); 
     } 
     free(command); 
     for (i=0; arguments[i] != NULL; ++i) { 
      free(arguments[i]); 
     } 
     free(arguments); 
    } 
    return 0; 
} 

void handle_signal(int signo) 
{ 
    getcwd(cwd,MAXPATHLEN); 
    printf("\n[MY_SHELL]:%s$ ", cwd); 
    fflush(stdout); 
} 

void parse_command(char *command, char **arguments){ 
    char buf[MAXSIZE]; 
    char env[MAXPATHLEN]; 
    char *tmp; 

    //Initiate array values to avoid buffer overflows 
    memset(buf, 0, sizeof(buf)); 
    memset(env, 0, sizeof(env)); 

    //Read command and put it in a buffer 
    char c = '\0'; 
    int N = 0; //Number of chars in input - shouldn't be more than MAXSIZE 
    while(1) { 
     c = getchar(); 
     if (c == '\n') 
      break; 
     else{ 
      if (N == MAXSIZE) 
       break; 
      buf[N] = c; 
     } 
     ++N; 
    } 

    //Extract command name (e.g "ls"), fetch path to command, append it to command name 
    tmp = strtok(buf, " "); 
    strcpy(env, "/bin/"); 
    size_t len1 = strlen(env); 
    size_t len2 = strlen(tmp); 
    memcpy(command, env, len1); 
    memcpy(command + len1, tmp, len2); 

    //Extracts arguments array: arguments[0] is path+command name 
    arguments[0] = calloc(strlen(command) + 1, sizeof(char)); 
    strcpy(arguments[0], command); 
    int i = 1; 
    while(1){ 
     tmp = strtok(NULL, " "); 
     if (tmp == NULL) 
      break; 
     else{ 
      arguments[i] = calloc(strlen(tmp) + 1, sizeof(char)); 
      strcpy(arguments[i],tmp); 
      ++i; 
     } 
    } 
} 

編輯2:這似乎有事情做與STDIN(或標準輸出):相若方式比LS使得執行後execve的掛了,我需要回車讓我的shell行[MY_SHELL] current_working_directory $:回來。有關爲什麼會出現這種情況的任何想法?

+1

標準警告:請[不要轉換](http://stackoverflow.com/q/605845/2173917)'malloc()'和系列的返回值。 – 2015-02-10 09:13:02

+0

我懷疑'cd'與'execve'一起工作... – mafso 2015-02-10 10:55:06

+0

對不起,關於cd,是的,它應該是一個內置的命令。我修復了代碼,內存泄漏,但ls仍然沒有返回。 – 2015-02-10 21:48:22

回答

3

在你的代碼,在parse_command()功能,你在做

bzero(arguments, sizeof(char) * MAXARGS); 

,但在那個時間點,arguments未初始化或分配的內存。所以基本上你試圖寫入未初始化的內存。這調用undefined behaviour

同樣的,沒有分配內存到arguments,您正在訪問arguments[0]

注意:正如我在我的評論中已經提到的,do not cast的返回值爲malloc()和family。

+0

我編輯了代碼,刪除了對bzero的需求,並修復了您指出的內存泄漏。我也避免了施放malloc的返回值(我現在使用calloc是因爲我需要一些初始化)。 – 2015-02-10 21:54:45

0

C使用按價值傳遞。這意味着在撥打parse_command之後,arguments的值仍將是未定義的,因爲任何分配都是針對本地副本進行的。而不是成爲一個三星級的程序員,我會建議你有parse_command返回參數列表,而不是:

char **parse_command(char *command){ 
    char **arguments = malloc(...); 
    ... 
    return arguments; 
} 

而且在主:

arguments = parse_command(command); 

也期待在Sourav戈什的回答正如他指出的一些其他錯誤。