如何使用execvp()执行命令

时间:2018-03-06 02:51:19

标签: c shell

所以我试图为我的学校项目创建一个自定义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;
}

2 个答案:

答案 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;
}