c - 系统调用 execve 不使用 ls 函数返回

标签 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$: 返回。对于为什么会出现这种情况有什么想法吗?

最佳答案

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

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

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

同样,在不为参数分配内存的情况下,您将访问参数[0]

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

关于c - 系统调用 execve 不使用 ls 函数返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28427803/

相关文章:

java - 我试图通过蓝牙发送数据,但 Serial.available() 总是返回 0

c - 在递归函数中使用 libpcre

c - 在内核模块中为根用户提供权限

python - 如何在远程 shell 的上下文中对 pdb 进行 stdin/stdout 重定向?

python - impala shell,带大写字母的 shell 命令

c - 如何在 C 中的 3d 数组中使用 memcpy

linux - UNIX 中的终止命令

windows - 关于为 VS2008 组织跨平台库的最佳方式的任何建议

c - sigsetjmp() 和 siglongjmp() : The mask signals are not the same on call to sigsetjmp() and return of siglongjmp()

linux - 根据文件名上的 grep 获取到最新文件的自动更新符号链接(symbolic link)