所以我试图为我的学校项目创建一个自定义shell。我的方法是创建子进程,并让该进程使用execvp()函数执行命令,我的教授在课堂上简要提到了我们要使用的函数。这是我的代码,一如既往,感谢任何帮助。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define MAX_LINE 80
int main(int argc, char *argv[])
{
char *input = (char*)malloc(MAX_LINE*sizeof(char));
int should_run = 1;
while(should_run){
printf("osh>");
fflush(stdout);
pid_t pid;
pid = fork();
if(pid < 0){
printf("error with creating chiled process");
return 0;
}
if(pid == 0){
fgets(input, MAX_LINE, stdin);
char *token = strtok(input," ");
if(execvp(token[0], token) < 0){
printf("Error in execution.");
return(0);
}
//should_run = 0;
}
waitpid(pid, 1, 0);
}
return 0;
}
答案 0 :(得分:1)
execvp
的原型是
int execvp(const char *file, char *const argv[]);
它期望指向char
的指针作为第一个参数,并且NULL
- 终止
指向char*
数组的指针。你传递的是错误的论点。
您传递的是char
作为第一个参数,char*
作为第二个参数。
改为使用execlp
:
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
所以
char *token = strtok(input," \n");
if(token == NULL)
{
fprintf(stderr, "only delimiters in line\n");
exit(1);
}
if(execlp(token, token, NULL) < 0){
fprintf(stderr, "Error in execution: %s\n", strerror(errno));
exit(1);
}
UNIX中的惯例也是将错误消息打印到stderr
,并且应该有错误的进程
退出状态不是0。
答案 1 :(得分:1)
正如Pablo所说,你将错误的论点传递给execvp()
。
您可以考虑自己编写一个函数(char **strsplit(char *str, char delim)
),它接受一个字符串并将其拆分成更小的部分,返回一个字符串数组。
也不要忽略编译器的警告,他们会告诉你很多事情,我建议你用gcc -Wall -Wextra -Werror
进行编译,以便在你的程序中得到几乎任何可能的错误。
我告诉你这是因为waitpid()
将第二个参数作为指向整数的指针,以获得分叉程序状态的更新。有了这个状态你就可以退出程序(通常是segf,总线错误......),如果出现问题你可以用它来打印错误。
您可以考虑使用execv()
代替(我知道我会离开主题,但您可以学习有用的东西),并自己找到正确的可执行文件。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAX_LINE 255
char **strsplit(char *str, char delim);
char *strjoin(char const *s1, char const *s2);
int isexec(char *path)
{
struct stat buf;
lstat(path, &buf);
if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode))
return (1);
return (0);
}
static char *find_exec_readdir(char *paths, char *cmd)
{
DIR *dir;
struct dirent *dirent;
char *exec;
exec = NULL;
if ((dir = opendir(paths)) != NULL)
{
while ((dirent = readdir(dir)) != NULL)
{
if (!strcmp(dirent->d_name, cmd))
{
exec = strdup(dirent->d_name);
break ;
}
}
if (closedir(dir))
dprintf(2, "Failed closing dir.\n");
}
return (exec);
}
char *find_exec(char *cmd, char **paths)
{
char *exec;
char *path;
char *tmp;
int i;
i = -1;
exec = NULL;
path = NULL;
if ((cmd[0] == '.' || cmd[0] == '/'))
{
if (isexec(cmd))
return (strdup(cmd));
return (NULL);
}
while (paths[++i])
if ((exec = find_exec_readdir(paths[i], cmd)) != NULL)
{
tmp = strjoin(paths[i], "/");
path = strjoin(tmp, exec);
free(tmp);
free(exec);
break ;
}
return (path);
}
int handle_return_status(int status)
{
int sig;
int i;
if (!WIFEXITED(status) && WIFSIGNALED(status))
{
sig = WTERMSIG(status);
i = -1;
while (++i <= 13)
{
if (print_signal_error(sig))
{
return (-1);
}
}
dprintf(2, "Process terminated with unknown signal: %d\n", sig, NULL);
return (-1);
}
return (0);
}
int main(int argc, char *argv[])
{
char *input = NULL;
char **command = NULL;
int should_run = 1;
int status = 0;
(void)argc;
(void)argv;
if ((input = (char*)malloc(MAX_LINE*sizeof(char))) == NULL)
return (dprintf(2, "Failed to malloc, abort.\n"));
while(should_run){
printf("osh> ");
fflush(stdout);
pid_t pid;
pid = fork();
if(pid < 0)
return (dprintf(2, "error with creating chiled process\n"));
if(pid == 0){
fgets(input, MAX_LINE, stdin);
command = strsplit(input, ' ');
command[0] = find_exec(command[0], strsplit(getenv("PATH"), ':'));
if(execv(command[0], &command[1]) < 0)
return (dprintf(2, "Error in execution.\n"));
//should_run = 0;
}
waitpid(pid, &status, 0);
handle_ret_status(status);
}
return 0;
}