我被要求为操作系统类实现我自己的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 $:换回。对于为什么会这样的想法?
答案 0 :(得分:3)
在您的代码中,在parse_command()
函数中,您正在执行
bzero(arguments, sizeof(char) * MAXARGS);
但是在那个时间点,arguments
未初始化或分配内存。所以基本上你是在尝试写入未初始化的内存。这会调用undefined behaviour。
同样地,在没有为arguments
分配内存的情况下,您正在访问arguments[0]
。
注意:正如我在评论中已经提到的,do not cast malloc()
和家人的返回值。
答案 1 :(得分:0)
C使用pass by value。这意味着在调用parse_command
之后,arguments
的值仍将是未定义的,因为对本地副本进行了任何分配。我建议您parse_command
返回参数列表,而不是成为三星级程序员:
char **parse_command(char *command){
char **arguments = malloc(...);
...
return arguments;
}
主要是:
arguments = parse_command(command);
还要看看Sourav Ghosh的答案,因为他指出了其他一些错误。