系统调用execve不返回ls函数

时间:2015-02-10 09:11:33

标签: c shell unix operating-system minix

我被要求为操作系统类实现我自己的shell。

我的shell运行的每个命令都很好,除了 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(或STDOUT)有关:类似于 ls cat 会使execve挂起执行,我需要回车让我的shell行 [MY_SHELL] current_working_directory $:换回。对于为什么会这样的想法?

2 个答案:

答案 0 :(得分:3)

在您的代码中,在parse_command()函数中,您正在执行

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

但是在那个时间点,arguments未初始化或分配内存。所以基本上你是在尝试写入未初始化的内存。这会调用undefined behaviour

同样地,在没有为arguments分配内存的情况下,您正在访问arguments[0]

注意:正如我在评论中已经提到的,do not cast malloc()和家人的返回值。

答案 1 :(得分:0)

C使用pass by value。这意味着在调用parse_command之后,arguments的值仍将是未定义的,因为对本地副本进行了任何分配。我建议您parse_command返回参数列表,而不是成为三星级程序员:

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

主要是:

arguments = parse_command(command);

还要看看Sourav Ghosh的答案,因为他指出了其他一些错误。

相关问题