系统调用 execve 没有 return with ls 函数

System call execve does not return with ls function

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

我的 shell 可以正常运行每个命令,除了 ls 不会 return on execve,这很奇怪,因为 cd、cp、mv 和所有其他主要命令都正常 return。

ls 仍在显示正确的输出(文件夹中的文件列表),但只是在(execve 挂起并需要回车 return 完成)。

-l、-a 等所有选项也都正常工作,但存在同样的问题。

编辑: 我修改了我的代码以完全避免任何内存泄漏(我使用 valgrind 来跟踪它们),添加了一些注释以便您可以看到发生了什么,但是ls 仍然没有 returning。这是更新后的版本:

#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 = '[=11=]';
    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)有关:与 lscat 使 execve 在执行后挂起,我需要回车 return 让我的 shell 行 [MY_SHELL]current_working_directory$ : 回线。想知道为什么会这样吗?

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

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

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

同理,没有为 arguments 分配内存,您正在访问 arguments[0]

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

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

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

主要是:

arguments = parse_command(command);

另请参阅 Sourav Ghosh 的回答,他指出了其他一些错误。