【问题标题】:Within C fork, printf() is not executing after while() loop在 C fork 中, printf() 在 while() 循环之后不执行
【发布时间】:2014-01-30 03:55:40
【问题描述】:

我正在为一个学校项目编写一个自定义 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!

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

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

【问题讨论】:

  • 我看不到你在哪里打印"Done with fork!"
  • 只是快速浏览一下,但在我看来,您似乎并没有处理 second strtok 直接返回 null 的可能性。也许您应该检查并立即中断,而不是尝试对空字符串进行所有这些操作?
  • @woolstar 道歉。我必须在格式化时无意中删除了该行。该行位于“waitpid”调用之后 - 请参阅编辑。谢谢!
  • 我会在子路径末尾的printf 之后尝试fflush(stdout) 和可能的sleep(1)
  • @ChrisStratton 感谢您的输入。您是正确的,第二个 strtok 调用应该位于语句的末尾(由于这个错误,它完全跳过了第一个标记)。这没有解决问题,但很有帮助!

标签: c fork printf


【解决方案1】:

您的代码中有一个错误——您正在使用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;

【讨论】:

  • 感谢您的回答!据我了解,malloc() 命令仅适用于 char 指针。我应该切换到 char 指针,还是我弄错了?一旦我达到我的前 15 个代表,我就会投票。再次感谢!
  • malloc() 返回一个指向已分配内存的指针。这是一个void*,可以转换为任何类型的指针,因此您可以将其分配给char*类型的变量。
  • 我的问题的解决方案是结合您的回答以及 Chris Stratton 对原始问题的评论。谢谢你的解释!
猜你喜欢
  • 2021-07-01
  • 2015-07-16
  • 2020-09-19
  • 1970-01-01
  • 2021-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-08
相关资源
最近更新 更多