【问题标题】:System call execve does not return with ls function系统调用 execve 不使用 ls 函数返回
【发布时间】:2015-04-10 06:10:03
【问题描述】:

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

我的 shell 可以正常运行所有命令,除了不会在 execve 上返回的 ls,这很奇怪,因为 cd、cp、mv 和所有其他主要命令恢复正常。

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

-l、-a 等所有选项也都可以正常工作,但问题相同。

编辑:我修改了我的代码以完全避免任何内存泄漏(我使用 valgrind 来跟踪它们),添加了一些 cmets 以便您可以看到发生了什么,但 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$: 行返回。关于为什么会这样的任何想法?

【问题讨论】:

  • 标准警告:请do not castmalloc()和family的返回值。
  • 我怀疑cdexecve 一起使用...
  • 抱歉 cd,是的,它应该是一个内置命令。我修复了代码,内存泄漏,但 ls 仍然没有返回。

标签: c shell unix operating-system minix


【解决方案1】:

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

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

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

同样的,不给arguments分配内存,你访问的是arguments[0]

注意:正如我在我的 cmets 中已经提到的,do not castmalloc() 和家庭的返回值。

【讨论】:

  • 我编辑了代码,消除了对 bzero 的需求,并修复了您指出的内存泄漏。我也避免强制转换 malloc 的返回值(我现在使用 calloc 是因为我需要一些初始化)。
【解决方案2】:

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

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

主要是:

arguments = parse_command(command);

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

【讨论】:

    猜你喜欢
    • 2012-09-23
    • 1970-01-01
    • 2015-03-23
    • 2014-12-10
    • 2021-07-30
    • 2021-07-24
    • 2012-02-11
    • 2013-03-25
    • 1970-01-01
    相关资源
    最近更新 更多