Fork- przekazywanie danych z procesu dziecka do procesu rodzica

0

Cześć,
Chciałem za pomocą procesu dziecka wykonać polecenia ls -la i przekazać rezultat poprzez potok nienazwany do procesu rodzica. Proces rodzica powinien odebrać dane i je wyświetlić na standardowe wyjście. Napisałem coś takiego. Czy ktoś może mi powiedzieć dlaczego poniższy kod nie działa? Co robię źle?

#include <unistd.h>
#include <sys/types.h>
#include <string.h>

int main()
{
	pid_t pid;
	int fd[2];
	char buffer[3];
	char *argv[3]= {"ls", "-la", NULL};
	buffer[3] = *argv[3];
	
	if(pipe(fd)<0)
		printf("Cannot create pipe\n");
	
	int pipe_result;
	pipe_result =pipe(fd);
	if (pipe_result<0)
		printf("error");
	
	pid= fork();
	
	if(pid<0) {
		printf("Couldn't create child process, err =%d\n", pid);
		return -1;
	} else if (pid ==0) {
		close(fd[0]);
		write(fd[1], buffer, 3);
		close(fd[1]);
		
	} else {
		close(fd[1]);
		read(fd[0], buffer, 1000);
		close(fd[0]);
		}

	
	return 0;
	}
1

Potrzebujesz przed uruchomieniem w procesie potomnym zduplikować deskryptor pipe do STDOUT_FILENO.
Zobacz tutaj: https://github.com/overcq/oux-web-srv/blob/master/srv.cx#L1082 – linie 1082 do 1367, a w szczególności 1104 i 1105 oraz 1356.

3

Ja nie wiem co jeszcze jest źle, ale:

    char buffer[3];
    char *argv[3]= {"ls", "-la", NULL};
    buffer[3] = *argv[3];

ostatnim dozwolonym indeksem tablic buffer oraz argv, jest 2.

Mój kompilator zresztą pokazuje więcej ostrzeżeń:

aaa.c: In function ‘main’:
aaa.c:33:5: warning: ‘read’ writing 1000 bytes into a region of size 3 overflows the destination [-Wstringop-overflow=]
   33 |     read(fd[0], buffer, 1000);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~
aaa.c:9:8: note: destination object ‘buffer’ of size 3
    9 |   char buffer[3];
      |        ^~~~~~
In file included from aaa.c:4:
/usr/include/unistd.h:360:16: note: in a call to function ‘read’ declared with attribute ‘access (write_only, 2, 3)’
  360 | extern ssize_t read (int __fd, void *__buf, size_t __nbytes) __wur
      |                ^~~~
2

A jakiś exec może ? Po wykonaniu fork nie załadowałeś nowej binarki.

2

Pomijając błąd na który zwrócił Ci uwagę @enedil - potrzebujesz mniej więcej taki schemat wywołań funkcji

pipe(...);
fork();
if (child)
{
  dup2(...); // żeby przekierować stdout do pipe (przeczytaj DOKŁADNIE manual)
  execl("/bin/ls", "ls", "-1", NULL); // jeśli nie wiesz dlaczego dwa razy jest "ls" to przeczytaj manual i dokumentację tego co jest w argv
  // zrób sobie przysługę i zakończ tego if-a exit-em...
  exit(..);
}
// parent

Oczywiście do każdego wywołania funkcji systemowej dodaj kod sprawdzający czy nie wystąpił błąd.

Albo po prostu użyj popen().

2

Rozwijając nieco to, co Panowie wyżej powiedzieli -- w POSIXie filozofia jest taka, że (być może nieco intuicyjnie) uruchamianie nowego procesu to nie jest ładowanie nowego programu.

fork robi Ci z jednego działającego procesu dwa -- prawie identyczne, więc nie ładuje magicznie nowego programu, tylko od momentu wywołania tej funkcji działają (o ile nie ma błędu braku zasobów itp.) dwa programy. To w którym jesteśmy sprawdzamy ifem -- i to masz z grubsza w swoim kodzie ogarnięte.

exec... (kropeczki, bo tu są różne końcówki nazwy funkcji w zależności od szczegółów wywołania) nie tworzy nowego procesu, ale zastępuje kod bieżącego całkiem nowym kodem (stary po prostu znika, a nowy dziedziczy po nim aspekty systemowe) wykonywanym od początku (znów, z dokładnością do ewentualnych błędów). Tego nie masz.

To w innych systemach operacyjnych wygląda inaczej, więc może być dla wielu nieintuicyjne -- i wiem, że sprawia kłopoty...

1 użytkowników online, w tym zalogowanych: 0, gości: 1