我正在为学校项目编写自定义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循环之外的代码似乎根本不运行而感到困惑。我也不知道这是我的分叉问题,还是与输出缓冲区有关。
我是以错误的方式执行此操作,或者如果找不到命令,如何确保“命令未找到”消息始终只运行一次?
答案 0 :(得分:2)
您的代码中存在错误 - 您正在使用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;