Nowe posty

Autor Wątek: łacza nienazwane  (Przeczytany 4459 razy)

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 5
    • Zobacz profil
łacza nienazwane
« dnia: 2012-04-14, 13:47:24 »
Witam, mam problem z takim czymś:

Chciałbym zrobić potok działający w ten sposób:

pipe cmd1 cmd2 plik

cmd1/2 to komendy wpisywane argv[]
plik to nazwa pliku do jakiego będzie zapisany wynik

Wiem, że już były podobne tematy. Wzorowałem się na nich, ale tam polecenia były typu ls -l plik a ja chcę napisać:

przykład:
who | less plik.txt



#include 
#include
#include
#include
#include
#include
#include

int main(int argc, char **argv) {
   pid_t pid;
   pid_t pid2;
   int fd[2];
   int file;
   mode_t fd_mode=S_IRWXU;//flaga odczyt zapis wykonywanie dla uzytkownikow
   
   
   
   if ((pipe(fd) == -1) || ((pid = fork()) == -1)) {
       perror("err...");
       return 1;
   }
   
   if(pid>0) {
      printf("Macierzysty\\n");
     
      dup2(fd[1], STDOUT_FILENO);

      close(fd[0]);
      close(fd[1]);
     
      execlp(argv[1], argv[1], (char *) 0);
   }
   if (pid == 0){
  if ((pid2 =fork()) == 0)
  {
  printf("I am child 2\\n");
  dup2(fd[0], STDIN_FILENO);
  close(fd[0]);
  close(fd[1]);

  file=open(argv[3], O_WRONLY | O_CREAT,fd_mode);
  char *buffer=(char *)malloc(500);
 
  read(STDIN_FILENO, buffer, 100);
  if (write(file, buffer, 100) < 0) {
  perror("Failed to write to the pipe\\n");
  return 1;
  }
  }
 
  printf("I am child 1\\n");
  dup2(fd[0], STDIN_FILENO);
  close(fd[0]);
  close(fd[1]);
 
  execlp(argv[2], argv[2], (char *) 0);
  close(fd[0]);
  close(fd[1]);
  return 1;

   }
return 0;
}

Offline

  • Users
  • Prawie jak Guru
  • ****
  • Wiadomości: 263
    • Zobacz profil
łacza nienazwane
« Odpowiedź #1 dnia: 2012-04-14, 15:59:05 »
Napisz dokładnie co chcesz osiągnąć i po co to robisz.

Bo odnoszę wrażenie, że próbujesz wyważyć otwarte drzwi wymyślając na nowo program tee, ale mam duże wątpliwości, czy dobrze rozumiem Twój problem.
Natura dała nam dwoje oczu, dwoje uszu, ale tylko jeden język po to, abyśmy więcej patrzyli i słuchali, niż mówili. -- konwencjonalnie Sokrates

Offline Tomasz Frydrych

  • Users
  • Guru
  • *****
  • Wiadomości: 529
    • Zobacz profil
łacza nienazwane
« Odpowiedź #2 dnia: 2012-04-14, 21:43:01 »
chodzi ci o to aby program powołał 2 procesy potomne(ewentualnie wykonał jakiś execv wewnątrz), takie, że wyjście jednego będzie wejściem drugiego?
Gdyby głupota była lżejsza od powietrza to unosilibyśmy się pod sufitem.

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 5
    • Zobacz profil
łacza nienazwane
« Odpowiedź #3 dnia: 2012-04-15, 11:56:42 »
@Minio nie do końca to ma być tee.
Chodzi mi o coś takiego jak @Ksanderon napisał. Dwa procesy, gdzie wyjście jest wejściem drugiego.

EDIT: Dokładniej może tak to opiszę: Przekierowanie standardowego wyjścia pierwszego procesu na standardowe wejście drugiego, oraz standardowe wyjście
drugiego procesu do pliku.


Działanie programu ma symulować tak jak pisałem
np: $ who | less >plik.txt
gdzie who to cmd1
less to cmd2
plik.txt to nazwa pliku wynikowego do którego jest przekazane to co normalnie pojawiło by się na konsoli

Offline Tomasz Frydrych

  • Users
  • Guru
  • *****
  • Wiadomości: 529
    • Zobacz profil
łacza nienazwane
« Odpowiedź #4 dnia: 2012-04-15, 16:37:42 »
czyli jak zwykle- Google nie działają(z czego wróżę rychły ich upadek...:D).

Podpowiem tylko: man dup2(w Googlach było by ciekawiej, nawet gotowiec by się znalazł ale skoro nie działają...)
Gdyby głupota była lżejsza od powietrza to unosilibyśmy się pod sufitem.

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 5
    • Zobacz profil
łacza nienazwane
« Odpowiedź #5 dnia: 2012-04-15, 21:47:43 »
Po co mi google skoro program napisałem i podałem w pierwszym poście.
Chodziło mi by ktoś na niego spojrzał i podpowiedział co należało by poprawić by był w pełni poprawny.

Na razie wypisuje informacje do pliku, ale wiem że jest to na siłę robione i są błędy, a nie zależy mi na podniecaniu się gotowcem.

Offline vanhelzing

  • Users
  • Prawie jak Guru
  • ****
  • Wiadomości: 314
    • Zobacz profil
łacza nienazwane
« Odpowiedź #6 dnia: 2012-04-16, 14:06:48 »
Cytuj
Po co mi google skoro program napisałem i podałem w pierwszym poście
Ten program pokazuje akurat, że absolutnie nie masz pojęcia o podstawach:

1) zła struktura programu,
2) źle obsługujesz forka (vide pid2). To, co tutaj napisałeś, jest tak dziwne, że nawet ja miałbym problem ze stwierdzeniem, skąd Ci to się wzięło. Mam wrażenie, że masz nikłe pojęcie, jak działa fork (chociaż stawiałbym na to, że bezmyślnie zastąpiłeś tam execa i stąd te makabryczne meandry przepływu sterowania),
3) nie wiem, czy zdajesz sobie sprawę, ale cmd2 uruchamiane jest dwukrotnie i to ani razu tak jak powinno,
4) utworzyłeś jeden potok zamiast dwóch i to jeszcze w sposób, który absolutnie wyklucza prawidłowe działanie,
5) źle zapisujesz dane do pliku,
6) deskryptory, które powinieneś zamknąć zostawiasz otwarte, zamykasz je jak Ci się widzi,
7) nie wiem skąd wziął Ci się pomysł, że ten program jest chociażby w połowie prawidłowy, skoro wystarczy uruchomić ten program, żeby przekonać się, że nie ma prawa działać prawidłowo.
8) żeby ten program poprawić powinieneś napisać go od nowa, bo nie da się go poprawić.

Dopóki nie zrozumiesz podstaw, to nawet nie ma jak Ci to wytłumaczyć. To są raptem trzy pojęcia na krzyż i dwa mechanizmy, które wystarczy ze sobą złożyć. Poczytaj sobie najpierw o tym jak działa fork, pipe, albo jak się zapisuje dane do pliku. W internecie masz mnóstwo szczegółowych informacji na ten temat.

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 5
    • Zobacz profil
łacza nienazwane
« Odpowiedź #7 dnia: 2012-04-16, 21:30:55 »
Ok, wielkie dzięki za odpowiedź.
Starałem się poprawić kod:

#include 
#include
#include
#include
#include
#include
#include
#include
#include


int main(int ac, char **av)
{
int fd[2], pid;

if ( pipe( fd ) == -1 )
perror("ERR pipe");

if ( (pid = fork()) == -1 )
perror("ERR pipe");

if ( pid > 0 ){ //rodzic
close(fd[1]);
dup2(fd[0], 0);//stdin
close(fd[0]);

execlp( av[2], av[2], NULL);
           perror("ERR exec av[2]");
}

if(pid == 0){
close(fd[0]);
dup2(fd[1], 1);
close(fd[1]);
execlp( av[1], av[1], NULL);
perror("ERR exec av[1]");
}

return 0;
}
Jednak wypisanie do pliku nie idzie :/
Czy jest jakiś prosty sposób by zrobić to w procesie macierzystym?

Żeby nie tworzyć kolejnego procesu tylko po zrobieniu av[2] od razu zapisać?

Offline vanhelzing

  • Users
  • Prawie jak Guru
  • ****
  • Wiadomości: 314
    • Zobacz profil
łacza nienazwane
« Odpowiedź #8 dnia: 2012-04-16, 22:52:19 »
Cytuj
Żeby nie tworzyć kolejnego procesu tylko po zrobieniu av[2] od razu zapisać?
exec nadpisuje Ci aktualny proces, więc po stworzeniu av[2] jest już tylko av[2].

Cytuj
Czy jest jakiś prosty sposób by zrobić to w procesie macierzystym?
Tak. Utworzyć jeszcze jeden proces potomny.

Struktura programu:
main() ----> fork() ---------------> zapis                         dziadek
                |                                  ^
                |                                  | pipe1
                |                                  |
                +------> fork() ---> exec(av[2])                    rodzic
                            |                      ^
                            |                      | pipe2
                            |                      |
                            +------> exec(av[1])                   dziecko

Offline

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 5
    • Zobacz profil
łacza nienazwane
« Odpowiedź #9 dnia: 2012-04-17, 23:56:25 »
Stosując się do rady powstało cos takiego:
#include 
#include
#include
#include
#include
 
 
int main(int ac, char **av)
{

  int fd[2], fd1[2];
 
  int pid;
 
  if (pipe(fd) == -1) {
    printf("Error: Pipe1 failed.\\n");
    return 1;
  }
  if (pipe(fd1) == -1) {
    printf("Error: Pipe2 failed.\\n");
    return 1;
  }
 
  if ((pid = fork()) < 0) {
    printf("Error: Fork failed.\\n");
    return 1;
  }
   
  if (pid == 0) {

if(fork() == 0){//dziecko
close(fd[0]);
close(fd1[1]);
dup2(fd[1],1);
close(fd[1]);    

execlp(av[1], av[1], NULL);
 printf("Error: execlp av1.\\n");
return 1;
}
else{ //rodzic
close(fd1[1]);
close(fd[1]);
dup2(fd1[0], 0);
close(fd1[0]);
execlp(av[2], av[2], NULL);
printf("Error: execlp av2.\\n");
return 1;
}return 0;
  }
 
  else{ //dziadek
close(fd[1]);
close(fd1[0]);
dup2(fd[0], 0);
close(fd[0]);
int file=open(av[3], O_WRONLY | O_CREAT, 0777);
dup2(file, 1);
close(fd1[1]);
close(fd1[1]);
  }
 return 0;
}
Jeszcze tylko male bledy z zamykaniem tego. Wie ktoś co jeszcze nie tak moze z tym byc?

EDIT:
Już chyba sam odpowiedziałem sobie na to pytanie.

Problem tkwi w tym, że dla komend less, more nie zamyka się, ale dla sort czy wc działa poprawnie

Offline vanhelzing

  • Users
  • Prawie jak Guru
  • ****
  • Wiadomości: 314
    • Zobacz profil
łacza nienazwane
« Odpowiedź #10 dnia: 2012-04-18, 12:09:52 »
Cytuj
Problem tkwi w tym, że dla komend less, more nie zamyka się, ale dla sort czy wc działa poprawnie
Wtedy:
ls | less | cat > x.txt
również by nie działało, a działa.

Problem jest w tym, że w:
           read(STDIN_FILENO, buffer, 100);
           if (write(file, buffer, 100) < 0) {
               perror("Failed to write to the pipe\\n");
               return 1;
           }
czytasz tylko 100 bajtów, i dokładnie tyle zapisujesz.

Powinieneś czytać wszystkie dane z potoku i je zapisywać w pętli (kopiować plik bajt-po-bajcie), a po osiągnięciu końca pliku (końca strumienia) zamykać deskryptory i kończyć proces.

[dodane]
less nie zamyka się, ponieważ czeka, aż przeczytasz wszystkie dane, a po zakończeniu działania rodzica nie kończy się, ale jest po prosty wywalany jako sierota.