2

我被要求为操作系统类实现我自己的 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$:回行。关于为什么会这样的任何想法?

4

2 回答 2

3

在您的代码中,在parse_command()功能中,您正在做

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

但在那个时间点,arguments没有初始化或分配内存。所以本质上你是在尝试写入未初始化的内存。这会调用未定义的行为

与此相同,无需为 分配内存arguments,您正在访问arguments[0].

注意:正如我在评论中已经提到的,不要强制转换malloc()and family的返回值。

于 2015-02-10T09:20:02.527 回答
0

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

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

主要是:

arguments = parse_command(command);

当他指出其他一些错误时,还请查看 Sourav Ghosh 的回答。

于 2015-02-10T09:30:41.043 回答