Основная проблема точно так, как указано в комментариях - вы не правильно называете execlp()
(или ls
в альтернативе).Вы должны сделать последний аргумент этих вызовов функций явным нулевым указателем, как показано в этом коде, который представляет собой слегка отредактированную версию вопроса:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
static void usage(void)
{
fprintf(stderr, "RIP\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
dprintf(STDOUT_FILENO, "Please work\n");
printf("THIS IS A MESSAGE FROM THE CHILD\n");
fputs("Pretty Please!\n", stdout);
fflush(stdout);
exit(EXIT_SUCCESS);
}
int p1[2];
if (-1 == pipe(p1))
{
fprintf(stderr, "pipe: %s\n", strerror(errno));
usage();
}
int f = fork();
if (f == 0)
{
close(p1[0]);
if (dup2(p1[1], STDOUT_FILENO) < 0)
{
fprintf(stderr, "dup2: %s\n", strerror(errno));
usage();
}
close(p1[1]);
execlp(argv[0], argv[0], "-e", (char *)0);
fprintf(stderr, "failed to exec %s again\n", argv[0]);
exit(EXIT_FAILURE);
}
else if (f == -1)
{
usage();
}
else
{
close(p1[1]);
char b[13];
memset(b, 0, 13);
if (read(p1[0], &b, 12) < 0)
{
fprintf(stderr, "Failed to read from pipe (%s)\n", strerror(errno));
exit(EXIT_FAILURE);
}
int len = strcspn(b, "\n");
printf("M1 [%.*s]\n", len, b);
char reading_buf[1];
while (read(p1[0], reading_buf, 1) > 0)
{
write(1, reading_buf, STDOUT_FILENO);
}
close(p1[0]);
int w = -1;
if (-1 == wait(&w))
usage();
}
return 0;
}
Два важных изменения должны быть выделены:
- Этот код повторяет первую строку данных - ту, которая записана
dprintf()
- тогда как исходный код просто прочитал ее и отбросил. - Вызов
wait()
после ввода, а не до.Если у дочернего элемента было больше данных для записи, чем набора фиксированных сообщений, он мог бы заблокировать ожидание того, чтобы родитель прочитал некоторые данные, в то время как родительский элемент заблокировал ожидание выхода дочернего элемента.Это будет тупик.
Функция usage()
не имеет соответствующего имени - она не сообщает, как запустить программу.Я также завершаю работу с состоянием сбоя, а не с успехом, если дочерний процесс завершается с ошибкой execlp()
.
При особых обстоятельствах вызов wait()
может сообщать о состоянии выхода от какого-либо дочернего объекта, отличного от того, которыйбыл раздвоенКак правило, лучше использовать цикл, чтобы пожинать таких детей.Однако требуемые обстоятельства чрезвычайно необычны - процесс, который запустил родительский элемент с функцией exec*()
, должен был предварительно создать некоторых дочерних элементов, которых он не ожидал, чтобы они наследовались родительским процессом (поскольку PID не 'изменить exec*()
вызов).