SIGINT处理后出现奇怪的printf行为

时间:2017-08-17 17:48:36

标签: c shell printf signals

我正在使用C创建一个非常原始的shell。输入命令后,提示正确打印并正确打印命令输出。在执行“run”命令之后出现问题,该命令基本上在用户输入的可执行文件上调用execve。我做到了这样,如果用户按下Ctrl-C(SIGINT),父级将不会死,并且子级(运行execve'd程序的那个)被中断。这是有效的,并且控制权将返回给父级,但是提示的打印在它之后会中断。运行“ls”或任何其他execve系统调用时可以看到它。

预期输出

DOGsh:-$ run /bin/cat
This is cat just repeating what I say.
This is cat just repeating what I say.
Okay, I will do Ctrl-C to send SIGINT to parent and child. Parent will doNothing and child will act normally.
Okay, I will do Ctrl-C to send SIGINT to parent and child. Parent will doNothing and child will act normally.
^C
DOGsh:-$ echo "Now watch what happens when I execve('/bin/ls')..."
Now watch what happens when I execve('/bin/ls')...
DOGsh:-$ run /bin/ls
commands.c  commands.h commands.o  help.txt  main.c  main.o  makefile  readinput.c  readinput.h  readinput.o  task2  utils.c  utils.h  utils.o
DOGsh:-$

实际输出

DOGsh:-$ run /bin/cat
This is cat just repeating what I say.
This is cat just repeating what I say.
Okay, I will do Ctrl-C to send SIGINT to parent and child. Parent will doNothing and child will act normally.
Okay, I will do Ctrl-C to send SIGINT to parent and child. Parent will doNothing and child will act normally.
^C
DOGsh:-$ echo "Now watch what happens when I execve('/bin/ls')..."
Now watch what happens when I execve('/bin/ls')...
DOGsh:-$ run /bin/ls
/* Note the gap here and the printing of the output after the shell prompt. */
DOGsh:-$ commands.c  commands.h commands.o  help.txt  main.c  main.o  makefile  readinput.c  readinput.h  readinput.o  task2  utils.c  utils.h  utils.o
// Here it's waiting for my next command but the prompt is missing...
[-] Unknown command.  // Entering an empty command comes up with this error message.
DOGsh:-$  // Oh great, it's back...

跑步功能

pid_t run_pid;  // Global var of the child pid.

int run(CommandStruct *cmd_struct) {
    char *arg_str = cmd_struct->arg_str;  // The path of the executable
    char *args[2] = {arg_str, NULL};  // *argv[] for the executable

    signal(SIGINT, doNothing);  // The parent should ignore the SIGINT.
    run_pid = fork();

    if (run_pid > 0) {
        wait(NULL);
    }
    else {
        execve(arg_str, args, NULL);
        exit(1);
    }

    printf("\n");
    signal(SIGINT, SIG_DFL);  // Reset the handler for parent.

    return 0;
}

void doNothing(int sig) {
    return;
}

主要功能

/* Only relevant parts included */
int main() {
    char raw_cmd[BUF_SIZE];
    char install_dir[BUF_SIZE];
    CommandStruct *cmd_struct;  // A struct with the command name and its args.
    Commands cmd;  // Enum with command names. Used for easier decision making.

    // ...

    while (1) {
        printf("\033[1;31mDOG\033[1;30msh:-$\033[0;37m ");  // Coloured prompt.
        fgets(raw_cmd, BUF_SIZE, stdin);
        cmd_struct = getCommandStruct(raw_cmd);
        cmd = getCommandFromCommandStruct(cmd_struct);

        switch (cmd) {
            case CLEAR:
                clear();
                break;
            // ...
            case RUN:
                run(cmd_struct);  // Run function
                break;
        }

        free((void*) cmd_struct);
    }

    return 0;
}

编辑:MCVE 我创建了类似的东西来重新创建我遇到的问题,当你遇到我放在循环中作为断点的getchar时,只需继续按Enter键。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#define BUF_SIZE 1024

typedef struct CommandStruct {
    char cmd[BUF_SIZE];
    char arg_str[BUF_SIZE];
} CommandStruct;

pid_t run_pid;

void doNothing(int sig) {
    return;
}

int run(CommandStruct *cmd_struct) {
    char *arg_str = cmd_struct->arg_str;
    char *args[2] = {arg_str, NULL};

    signal(SIGINT, doNothing);
    run_pid = fork();

    if (run_pid > 0) {
        wait(NULL);
    }
    else {
        execve(arg_str, args, NULL);
        exit(1);
    }

    signal(SIGINT, SIG_DFL);

    return 0;
}

int main() {
    CommandStruct cmd_struct;
    strcpy(cmd_struct.cmd, "run");
    strcpy(cmd_struct.arg_str, "/bin/cat");

    while (1) {
        printf("\033[1;31mDOG\033[1;30msh:-$\033[0;37m ");
        getchar();  // Waiting to continue.

        run(&cmd_struct);

        printf("\033[1;31mDOG\033[1;30msh:-$\033[0;37m ");
        getchar();  // Waiting to continue.

        strcpy(cmd_struct.arg_str, "/bin/ls");

        run(&cmd_struct);
    }

    return 0;
}

0 个答案:

没有答案