c - 在 C fork 中, printf() 在 while() 循环之后不执行

标签 c fork printf

我正在为学校项目编写自定义 shell,并且我需要能够通过“execv”函数运行外部命令。我需要我的命令要么成功运行并具有适当的输出,要么声明未找到该命令。这是我此时的代码(带有一些用于调试的 printf() 输出):

/* Create a child process */
pid_t pid = fork();

/* Check if the fork failed */
if (pid >= 0)
{
    if (pid == 0)
    {                           
        /* This is the child process - see if we need to search for the PATH */
        if( strchr( command.args[0], '/' ) == NULL )
        {
            /* Search the PATH for the program to run */
            char fullpath[ sizeof( getenv("PATH") ) ];
            strcpy( fullpath, getenv("PATH") );

            /* Iterate through all the paths to find the appropriate program */
            char* path;

            path = strtok( fullpath, colon );
            while(path != NULL)
            {
                char progpath[COMMAND_SIZE];

                /* Try the next path */
                path = strtok( NULL, colon );
                strcpy(progpath, path);
                strcat(progpath, "/");
                strcat(progpath, command.args[0]);

                /* Determine if the command exists */
                struct stat st;
                if(stat(progpath, &st) == 0)
                {
                    /* File exists. Set the flag and break. */
                    execv( progpath, command.args );
                    exit(0);
                }
                else
                {
                    printf("Not found!\n");
                }
            }
            printf("%s: Command not found!\n", command.args[0]);
        }
        else
        {
            ...
        }

        /* Exit the process */
        exit(EXIT_FAILURE);
    }
    else
    {
        /* This is the parent process - wait for the child command to exit */
        waitpid( pid, NULL, 0 );
        printf("Done with fork!\n");
    }
}
else
{
    /* Could not fork! */
    printf("%s: %s > Failed to fork command!\n", command.args[0], strerror(errno) );
}

这是输出:

john@myshell:/home/john/project>dir
/usr/local/sbin/dir: Not found!
/usr/local/bin/dir: Not found!
/usr/sbin/dir: Not found!
/usr/bin/dir: Not found!
/sbin/dir: Not found!
/bin/dir: Found!
makefile  makefile~  myshell.c  myshell.c~  myshell.x
Done with fork!
john@myshell:/home/john/project>foo
/usr/local/sbin/foo: Not found!
/usr/local/bin/foo: Not found!
/usr/sbin/foo: Not found!
/usr/bin/foo: Not found!
/sbin/foo: Not found!
/bin/foo: Not found!
/usr/games/foo: Not found!
Done with fork!
john@myshell:/home/john/project>

已知命令“dir”已被发现并正确执行。输出很棒。但是,当我使用假“foo”命令时,我希望它找不到该命令(显然没有),完成“while”循环,并执行以下“printf”命令。话虽如此,我预计在输出末尾会看到以下内容:

foo: Command not found!

我尝试使用 bool 值和整数值作为“标志”来确定是否找到该命令。然而,似乎没有任何代码在 while 循环之外运行。如果我删除“exit(0)”,“printf”命令仍然不会运行。我对为什么 while 循环之外的代码似乎根本没有运行感到困惑和困惑。我也不知道这是否是我 fork 方式的问题,或者这是否与输出缓冲区有关。

我这样做的方式是否错误,或者如果未找到命令,如何确保“未找到命令”消息始终运行一次?

最佳答案

您的代码中存在错误 - 您正在使用 strcpy() 并导致缓冲区溢出:

// Note the declaration of getenv():
char *getenv(const char *name);

因此 sizeof(getenv("PATH")) == sizeof(char*),可能是 4 或 8。

/* Search the PATH for the program to run */
char fullpath[ sizeof( getenv("PATH") ) ];   // allocate fullpath[4] or [8]
strcpy(fullpath, getenv("PATH"));   // overrun... copy to 4-8 char stack buffer
// UNDEFINED behavior after this - Bad Things ahead.

您可以使用malloc()来动态分配堆上的完整路径:

char* fullpath = malloc(strlen(getenv("PATH")) + 1); // +1 for terminating NUL
strcpy(fullpath, getenv("PATH"));   // OK, buffer is allocated large enough

// ... use fullpath ...

// Then when you are done, free the allocated memory.
free(fullpath);
// And as a general habit you want to clear the pointer after freeing
// the memory to prevent hard-to-debug use-after-free bugs.
fullpath = 0;

关于c - 在 C fork 中, printf() 在 while() 循环之后不执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21447517/

相关文章:

c - C语言中的fork()函数

c - printf 的 h 和 hh 修饰符的用途是什么?

c - 模拟 printf 堆栈弹出

c - 是否可以将代码注入(inject) x86-64 上的堆栈

c - Fork - 即使是 if else,父进程和子进程如何运行

c - alarm() 函数没有在正确的时间关闭

security - Printf 安全 golang

c - 访问内存并更改某些变量的值

c - 如何遍历数组中字符串的字符?

php - 如何向 PHP 发送简短的 Ajax 请求、获得确认并且无需等待完整处理完成