Я спросил о своем коде, и ответ был, что он неверен. использование perror в этом случае Теперь мне интересно, как я могу настроить и улучшить, чтобы я не больше не будет этих ошибок?
execvp не возвращает значение, за исключением случаев возникновения ошибки, поэтому, если все работает, объемлющая функция никогда не вернется.
значение «i» уже находится за концом массива в «cmd» из-за предыдущего цикла, поэтому «cmd[i].argv[0] неверно.
cmd не является массивом команды struct, поэтому не должен индексироваться
первая запись в cmd.argv является указателем на массив, где последняя запись имеет значение NULL. execvp будет работать с этим (и только с этим) массивом, поэтому все остальные указатели на массивы будут игнорироваться.
В коде большое количество ошибок. например, первый раз в цикле fork_pipe() 'in' содержит мусор. второй параметр, передаваемый в 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);
}
execvp()
(если он возвращается, он не пройден), но вам нужен отчет об ошибке и вызов выхода после него. - person Jonathan Leffler   schedule 12.04.2015cmd
не является массивом» кажется фиктивным; внутриfork_pipes()
это массив. Он не используется как массив внутриspawn_proc()
. - person Jonathan Leffler   schedule 12.04.2015struct command
. - person Jonathan Leffler   schedule 12.04.2015i
уже находится за концом массива вcmd
из-за предыдущего цикла, поэтомуcmd[i].argv[0]
неверно» неверен, потому что циклfor (i = 0; i < n - 1; i++)
, поэтомуi
равенn-1
после цикла, а массивcmd
имеет элементы0..n-1
по адресу. - person Jonathan Leffler   schedule 12.04.2015in
в первом вызовеspawn_proc()
действительно мусор. Вероятно, вы можете просто установить его на 0 (STDIN_FILENO) и все будет в порядке, но вам нужно это проверить. А вот комментарий по поводу второго аргумента кexecvp()
своеобразен — приведение должно отсутствовать, а в остальном код мне кажется нормальным. Я должен добавить, что я еще не запускал компилятор над чем-либо из этого, поэтому все, что я сказал до сих пор, должно быть исправлено компилятором. Но и анализ я делаю не случайно… Вы компилируете компилятором, установленным как минимум:gcc -Wall -Wextra -Werror
(я использую больше опций!)? - person Jonathan Leffler   schedule 12.04.2015fork_pipes()
проверкаif
наexecvp()
и предложениеelse
выглядят странно. Вам просто нужны вызовыexecvp()
,perror()
иexit()
— никаких условий. - person Jonathan Leffler   schedule 12.04.2015