我询问了我的代码,答案是不正确的。 perror usage in this case 现在我想知道如何调整和改进,以便我不再有这些错误?
execvp不会返回,除非发生错误,所以如果一切正常, 封闭功能永远不会返回。
价值'我'已经超过数组的结尾了?cmd'因为 先前循环,所以' cmd [i] .argv [0]不正确。
cmd不是struct命令的数组,因此不应编入索引
cmd.argv中的第一个条目是指向最后一个数组的指针 条目为NULL。 execvp将在那个(并且只有那个)数组上工作 所有其他指向数组的指针都将被忽略
代码中存在大量错误。例如, 第一次通过fork_pipe()'中的循环包含垃圾。该 传递给execvp()的第二个参数需要是指向字符的指针 字符串,带有最终的NULL指针。最后的NULL指针是 缺少,还有很多问题
#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);
}
答案 0 :(得分:2)
将评论转移到(部分)答案中。
您不需要execvp()
上的测试(如果它返回,则失败),但您确实需要错误报告并在此之后退出呼叫。
'cmd
不是数组'评论似乎是假的;在fork_pipes()
内,它是一个数组。它不用作spawn_proc()
内的数组。
我认为评论'cmd.argv
中的第一个条目是指向最后一个条目为NULL的数组的指针。 execvp
将在那个(并且只有那个)数组上工作,因此所有其他指向数组的指针都将被忽略'也是假的。我认为他们忽略了你正在创建一个struct命令数组。
我认为评论'值i
已经超过了cmd
中数组的末尾,因为先前的循环,所以cmd[i].argv[0]
不正确'是不正确的因为循环是for (i = 0; i < n - 1; i++)
所以i
在循环之后是n-1
,而数组cmd
具有要处理的元素0..n-1
。
但是,第一次调用in
时spawn_proc()
的值确实是垃圾。可能您只需将其设置为0
(STDIN_FILENO
)即可,但您需要验证。但关于execvp()
的第二个参数的评论是特殊的 - 演员应该没有,但是否则代码对我来说是好的。我应该补充一点,我还没有运行任何编译器,所以我到目前为止所说的任何东西都要由编译器来纠正。但我不是随便做分析......你是否正在编译你的编译器设置繁琐:gcc -Wall -Wextra -Werror
作为最低限度(我使用更多选项!)?
在fork_pipes()
中,if
上的execvp()
测试和else
子句很奇怪。您只需要拨打execvp()
,perror()
和exit()
。
以上这些评论基本上是准确的。这是一些修改过的代码,但修改主要是装饰性的。 err_syserr()
函数基于我用于报告错误的内容。它是一个varargs函数,也报告系统错误。它优于perror()
因为(a)它可以更全面地格式化并且(b)它退出。
我收到的编辑警告如下:
ft13.c: In function ‘spawn_proc’:
ft13.c:45:9: error: passing argument 2 of ‘execvp’ from incompatible pointer type [-Werror]
execvp(cmd->argv[0], cmd->argv);
^
In file included from ft13.c:6:0:
/usr/include/unistd.h:440:6: note: expected ‘char * const*’ but argument is of type ‘const char **’
int execvp(const char *, char * const *);
解决这些问题的最简单方法是将const
放在struct command
中的正确位置,并从各种命令的参数列表中删除const
。
其他更改更具外观性而非实质性(未初始化的in
是唯一需要修复的严重错误)。我使用了我的错误报告代码,并检查了一些额外的系统调用(例如dup2()
),并清理了execvp()
和错误报告。我将exit
和cd
的测试移到通用代码之前,以避免重复测试。此外,您使用的是strncmp()
,exit
的测试仅查看ex
,但ex
是系统命令...请使用strcmp()
。我在条件中使用strcmp(x, y) == 0
;正在使用的关系运算符模仿我正在测试的关系运算(strcmp(x, y) >= 0
x
测试大于或等于y
等。)
现代POSIX不需要#include <sys/types.h>
作为包含。其他标题包括必要的内容。
ft13.c
已编译为ft13
。
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct command
{
char * const *argv;
};
static _Noreturn void err_syserr(char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, "(%d: %s)\n", errnum, strerror(errnum));
exit(EXIT_FAILURE);
}
/* Helper function that spawns processes */
static int spawn_proc(int in, int out, struct command *cmd)
{
pid_t pid;
if ((pid = fork()) == 0)
{
if (in != 0)
{
if (dup2(in, 0) < 0)
err_syserr("dup2() failed on stdin for %s: ", cmd->argv[0]);
close(in);
}
if (out != 1)
{
if (dup2(out, 1) < 0)
err_syserr("dup2() failed on stdout for %s: ", cmd->argv[0]);
close(out);
}
fprintf(stderr, "%d: executing %s\n", (int)getpid(), cmd->argv[0]);
execvp(cmd->argv[0], cmd->argv);
err_syserr("failed to execute %s: ", cmd->argv[0]);
}
else if (pid < 0)
err_syserr("fork failed: ");
return pid;
}
/* Helper function that forks pipes */
static void fork_pipes(int n, struct command *cmd)
{
int i;
int in = 0;
int fd[2];
for (i = 0; i < n - 1; ++i)
{
pipe(fd);
spawn_proc(in, fd[1], cmd + i);
close(fd[1]);
in = fd[0];
}
if (dup2(in, 0) < 0)
err_syserr("dup2() failed on stdin for %s: ", cmd[i].argv[0]);
fprintf(stderr, "%d: executing %s\n", (int)getpid(), cmd[i].argv[0]);
execvp(cmd[i].argv[0], cmd[i].argv);
err_syserr("failed to execute %s: ", cmd[i].argv[0]);
}
int main(int argc, char **argv)
{
int i;
if (argc == 1) /* There were no arguments */
{
char *printenv[] = { "printenv", 0};
char *sort[] = { "sort", 0 };
char *less[] = { "less", 0 };
struct command cmd[] = { {printenv}, {sort}, {less} };
fork_pipes(3, cmd);
}
else
{
if (strcmp(argv[1], "cd") == 0) /* change directory */
{
printf("change directory to %s\n", argv[2]);
chdir(argv[2]);
}
else if (strcmp(argv[1], "exit") == 0)
{
printf("exit\n");
exit(0);
}
else
{
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]);
}
char *printenv[] = { "printenv", 0};
char *grep[] = { "grep", "-E", tmp, NULL};
char *sort[] = { "sort", 0 };
char *less[] = { "less", 0 };
struct command cmd[] = { {printenv}, {grep}, {sort}, {less} };
fork_pipes(4, cmd);
free(tmp);
}
}
return(0);
}
样本1:
$ ./ft13 | cat
1733: executing less
1735: executing printenv
1736: executing sort
Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.sl7NmyZPgI/Render
BASH_ENV=/Users/jleffler/.bashrc
CDPATH=:/Users/jleffler:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work:/Users/jleffler/ids
CLICOLOR=1
…lots of environment omitted…
VISUAL=vim
XPC_FLAGS=0x0
XPC_SERVICE_NAME=0
_=./ft13
__CF_USER_TEXT_ENCODING=0x1F7:0x0:0x0
$
样本2:
$ ./ft13 PATH | cat
1739: executing printenv
1737: executing less
1740: executing grep
1741: executing sort
CDPATH=:/Users/jleffler:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work:/Users/jleffler/ids
DYLD_LIBRARY_PATH=/usr/lib:/usr/informix/11.70.FC6/lib:/usr/informix/11.70.FC6/lib/esql:/usr/informix/11.70.FC6/lib/cli
GOPATH=/Users/jleffler/Software/go-1.2
LD_LIBRARY_PATH=/usr/lib:/usr/gnu/lib:/usr/gcc/v4.9.1/lib
MANPATH=/Users/jleffler/man:/Users/jleffler/share/man:/usr/local/mysql/man:/usr/gcc/v4.9.1/share/man:/Users/jleffler/perl/v5.20.1/man:/usr/local/man:/usr/local/share/man:/opt/local/man:/opt/local/share/man:/usr/share/man:/usr/gnu/man:/usr/gnu/share/man
PATH=/Users/jleffler/bin:/usr/informix/11.70.FC6/bin:.:/usr/local/mysql/bin:/usr/gcc/v4.9.1/bin:/Users/jleffler/perl/v5.20.1/bin:/usr/local/go/bin:/Users/jleffler/Software/go-1.2/bin:/usr/local/bin:/opt/local/bin:/usr/bin:/bin:/usr/gnu/bin:/usr/sbin:/sbin
$