【问题标题】:perror usage in this case在这种情况下使用 perror
【发布时间】:2015-06-16 16:13:14
【问题描述】:

我们可以检查我的 perror 用法是否正确吗?背景就是这些问题 How to handle errors in execvp? How to use perror with dup2? 现在我有了这段代码,但代码正确吗?

/* Helper function that forks pipes */
int fork_pipes (int n, struct command *cmd) {
    int i;
    int in, fd [2];
    for (i = 0; i < n - 1; ++i) {
        pipe (fd);
        spawn_proc (in, fd [1], cmd + i);
        close (fd [1]);
        in = fd [0];
    }
    dup2 (in, 0);
    /*return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);*/
    if (execvp (cmd [i].argv [0], (char * const *)cmd [i].argv) < 0) {
        perror("execvp failed");
        exit(1);
    } else {
        return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
    }
}

完整的程序是

#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
struct command
{
    const char **argv;
};
/* Helper function that spawns processes */
int spawn_proc (int in, int out, struct command *cmd) {
    pid_t pid;
    if ((pid = fork ()) == 0) {
        if (in != 0) {
            /*if (dup2(in, 0) == -1) {
                perror("dup2 failed");
                exit(1);
            }*/
            dup2 (in, 0);
            close (in);
        }
        if (out != 1) {
            dup2 (out, 1);
            close (out);
        }
        if (execvp(cmd->argv [0], (char * const *)cmd->argv) < 0) {
            perror("execvp failed");
            exit(1);
        }
    } else if (pid < 0) {
        perror("fork failed");
        exit(1);
    }
    return pid;
}
/* Helper function that forks pipes */
int fork_pipes (int n, struct command *cmd) {
    int i;
    int in, fd [2];
    for (i = 0; i < n - 1; ++i) {
        pipe (fd);
        spawn_proc (in, fd [1], cmd + i);
        close (fd [1]);
        in = fd [0];
    }
    dup2 (in, 0);
    /*return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);*/
    if (execvp (cmd [i].argv [0], (char * const *)cmd [i].argv) < 0) {
        perror("execvp failed");
        exit(1);
    } else {
        return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
    }
}

int main (int argc, char ** argv) {
    int i;
    if (argc == 1) { /* There were no arguments */
        const char *printenv[] = { "printenv", 0};
        const char *sort[] = { "sort", 0 };
        const char *less[] = { "less", 0 };
        struct command cmd [] = { {printenv}, {sort}, {less} };
        return fork_pipes (3, cmd);
    }
    if (argc > 1) { /* I'd like an argument */

        if (strncmp(argv[1], "cd", 2) && strncmp(argv[1], "exit", 2)) {
            char *tmp;
            int len = 1;
            for( i=1; i<argc; i++)
            {
                len += strlen(argv[i]) + 2;
            }
            tmp = (char*) malloc(len);
            tmp[0] = '\0';
            int pos = 0;
            for( i=1; i<argc; i++)
            {
                pos += sprintf(tmp+pos, "%s%s", (i==1?"":"|"), argv[i]);
            }
            const char *printenv[] = { "printenv", 0};
            const char *grep[] = { "grep", "-E", tmp, NULL};
            const char *sort[] = { "sort", 0 };
            const char *less[] = { "less", 0 };
            struct command cmd [] = { {printenv}, {grep}, {sort}, {less} };
            return fork_pipes (4, cmd);
            free(tmp);
        } else if (! strncmp(argv[1], "cd", 2)) { /* change directory */
            printf("change directory to %s\n" , argv[2]);
            chdir(argv[2]);
        } else if (! strncmp(argv[1], "exit", 2)) { /* change directory */
            printf("exit\n");
            exit(0);
        }
    }
    exit(0);
}

【问题讨论】:

  • forkexecdup2pipe,就像 unix 中的大多数系统调用一样,在失败时返回 errno 使用的全局变量由perror 打印消息。所以你的用法没有错。顺便说一句,man 是一个很好的资源,它可以提供有关函数在失败时的作用的信息。
  • 代码中有大量错误。例如,第一次通过 fork_pipe() 'in' 中的循环包含垃圾。传递给 execvp() 的第二个参数需要是一个指向字符串的指针,最后一个 NULL 指针。最终的 NULL 指针不见了,还有很多问题
  • @user3629249:关于in的评论是正确的——应该初始化为0。其他cmets大多是错误的; execvp() 的第二个参数是指向 char * 的空终止数组的指针,尽管 const 有点歪斜(因此是强制转换),并且初始化程序中的 0 是空指针常量。另见How to fix these errors in my code?

标签: c linux error-handling


【解决方案1】:

这段代码:

 if (execvp (cmd [i].argv [0], (char * const *)cmd [i].argv) < 0) {
    perror("execvp failed");
    exit(1);
 } else {
    return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
 }

有几个问题。

  1. execvp 不会返回,除非发生错误,因此如果一切正常,封闭函数将永远不会返回。

  2. 由于前面的循环,值 'i' 已经超过了 'cmd' 中数组的末尾,因此 'cmd[i].argv[0] 不正确。

    李>
  3. cmd不是一个数组,属于struct命令,所以不应该被索引

  4. cmd.argv 中的第一个条目是指向最后一个条目为 NULL 的数组的指针。 execvp 将在那个(并且只有那个)数组上工作 所以所有其他指向数组的指针都将被忽略

【讨论】:

  • (1) 不需要测试但是报错退出是;第二个execvp() 永远不会执行。 (2) 这种分析是错误的;循环转到for (i = 0; i &lt; n-1; i++) 而不是for (i = 0; i &lt; n; i++) — 后者将使您的分析正确。 (3) cmdfork_pipes() 中的一个数组,因此对它进行索引是完全合法的。 (4) 这种分析完全是假的; struct command cmd[] 数组已正确初始化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 2015-11-30
  • 2017-05-16
  • 2012-10-06
  • 2011-05-18
  • 2021-02-04
  • 2019-11-29
相关资源
最近更新 更多