SOP121/ćw - temat B.

3. Unix: procesy.

Podstawowe pojęcia związane z procesami:

Każdy działający proces (=uruchomiony program) posiada m.in. następujące parametry:

  • PID ="Process IDentifier"; identyfikator procesu.
  • PPID = "Parent Process ID"; identyfikator "rodzica" procesu; w Unix-ie proces może się "rozdwoić", nowy proces nazywamy procesem potomnym, a stary proces nazywamy procesem macierzystym; proces potomny jest początkowo dokładną kopią procesu macierzystego; proces potomny może zacząć wykonywać inny program niż ten wykonywany przez proces macierzysty; jeśli z pewnej powłoki uruchamiamy program to program ten wykonuje się w procesie potomnym a powłoka jest jego procesem macierzystym; w Unix-ie istnieje drzewko procesów ...
  • UID = "User ID"; identyfikator właściciela procesu; proces ma takie prawa do plików, jakie ma jego właściciel.
  • PGID = "Process Group ID"; identyfikator grupy procesów, do której ten proces należy; na początku proces potomny należy do tej samej grupy co proces macierzysty (może jednak założyć własną grupę procesów i stać się jej przywódcą, czyli może mieć PID=PGID). Jakie są zastosowania grup procesów ? np można wysyłać sygnały do całych grup procesów a nie tylko do pojedynczych procesów.
  • USER; nazwa użytkownika, której używany przy logowaniu (UID to liczba całkowita; w pliku /etc/passwd znajdują się identyfikatory i nazwy użytkowników).
  • TNAME, LONGTNAME; krótka i długa nazwa pliku specjalnego terminala sterującego procesu.
  • PCPU, PMEM; procentowe zużycie czasu procesora i pamięci.
  • Można zobaczyć jakie procesy obecnie działają oraz obejrzeć ich parametry przy pomocy polecenia "ps"
    (dokładniejsze omówienie polecenia "ps" znajduje się tutaj).
    Listę wszystkich parametrów procesów można zobaczyć na stronie manuala dotyczącej polecenia "ps" !.
      # przykład użycia polecenia "ps"
    
      ps -A -O ppid
         # pokazuje wszystkie procesy (opcja -A)
         # wyświetlane informacje będą zawierały parametr PPID (opcja -O ppid)
         # nazwa parametru (np "ppid") musi być pisana małymi literami !
    Sygnały są wysyłane do procesu przez system operacyjny z powodu wystąpienie jakiegoś zdarzenia, lub przez inne procesy. Można wysyłać sygnały poleceniem "kill" (dokładniejsze omówienie polecenia "kill" znajduje się tutaj).
      # przykład użycia polecenia "kill"
    
      kill -kill 1234
         # lub
      kill -9 1234
         # wysłanie sygnału SIGKILL (o numerze 9) oznaczającego
         # żądanie bezwarunkowego zakończenia procesu
         # do procesu z pid=1234
    UWAGA: (działanie klawiszy Ctrl-C, Ctrl-Z, Ctrl-D)
  • Gdy naciskamy klawisz Ctrl-C to jest wysyłany sygnał SIGINT do bieżącego (pierwszoplanowego) procesu. Standardowa reakcja procesu na SIGINT to zakończenie działania procesu.
  • Gdy naciskamy klawisz Ctrl-Z to jest wysyłany sygnał SIGTSTP do bieżącego (pierwszoplanowego) procesu.  Sygnał ten powoduje zatrzymanie (NIE zakończenie) procesu; jest możliwe wznowienie zatrzymanego procesu - patrz rozdział o sterowaniu pracami.
  • Gdy naciskamy klawisz Ctrl-D to żaden sygnał nie jest wysyłany, lecz dla programów czytających dane z terminala ma to taki efekt jakby się "terminal skończył" (tak jak może "się skończyć" plik z którego czytamy po jednym znaku).  Programy czytające z terminala interpretują ten fakt jako koniec pracy; na tej zasadzie tworzyliśmy plik przy pomocy polecenia "cat >plik.txt" (na końcu należało nacisnąć Ctrl-D, co program "cat" interpretował jako koniec wprowadzania danych).
  •  
    Deskryptor to liczba całkowita, którą otrzymujemy po otwarciu pliku. Otwarcie pliku to przygotowanie go do przetwarzania (pisania i/lub czytania). Proces odwołuje się do (otwartego) pliku poprzez (otwarty lub inaczej aktywny) deskryptor. Oznacza to, że jeśli proces zamierza np odczytać 1 bajt z pliku to musi wywołać pewną funkcję systemową i jako jeden z jej parametrów podać deskryptor tego pliku.

    Każdy proces (zaraz po uruchomieniu) posiada pewną ilość otwartych deskryptorów. Są to m.in. deskryptory 0,1,2 oznaczające odpowiednio

    Zazwyczaj są one związane z terminalem tj dotyczą pliku specjalnego terminala.  Jeśli uruchomimy program "pr01" następująco:
           pr01 qqq www eee > plik.txt
    to deskryptor 1 dotyczy nie terminala tylko pliku plik.txt (jest to tzw przekierowywanie lub przeadresowanie dokonywane przez powłokę z której uruchamiamy program).

    Proces nazywamy pierwszoplanowym jeśli powłoka z której został uruchomiony czeka na jego zakończenie (i dopiero po zakończeniu wyświetla następny "prompt"). Uruchamianie procesu pierwszoplanowego:

           sleep 30 
           # program "sleep" czeka podaną liczbę sekund
    Jeśli powłoka nie czeka na zakończenie procesu, to taki proces nazywamy drugoplanowym (proces drugoplanowy wykonuje się współbieżnie z powłoką). Uruchamianie procesu drugoplanowego:
           sleep 30 &
           # inny przykład :
           ls -l > plik.txt &
    Zadanie 20

    1) Aby eksperymentować z procesami skompiluj program w języku C "pr02.c", który wyświetla swój PID, PPID, UID, PGID (używając fun. sys. getpid(), getppid(), getuid(), getpgrp()) oraz "śpi" przez 60 sekund (fun. sleep()), a następnie się kończy. Skompiluj także program "pr03.c", który wyświetla bez końca kolejne liczby, co 1 sekundę.
    2) URUCHOM dwa procesy "pr02" jako drugoplanowe a następnie odczytaj ich parametry poleceniem "ps" (porównaj z tym co one same wypisują). Opis polecenia "ps" znajduje się tutaj.
    3) URUCHOM proces "pr02" jako pierwszoplanowy przekonaj się, ze można go zakończyć "przed czasem" naciskając klawisz Ctrl-C (jest wysyłany sygnał SIGINT). Nie musisz niczego wstawiać do sprawozdania w tym punkcie.
    4) URUCHOM program "pr03" drugoplanowo, z przekierowaniem stdout do pliku plik.txt. Zaobserwuj zwiększanie się rozmiaru pliku. Następnie zabij proces sygnalem SIGKILL. Opis polecenie "kill" znajduje się tutaj.
     


    Łącze to jednokierunkowy kanał komunikacyjny między dwoma procesami, jeden proces wysyła przez łącze bajty, a drugi może je odczytywać. Łącza zazwyczaj mają ograniczoną pojemność, jeśli jeden proces wysyła coś poprzez łącze a żaden inny proces tego nie odbiera, to łącze może zostać "przepełnione". Każde łacze ma dwie "końcówki": końcówkę WEjściową i WYjściową; końcówkę WE ma nadawca a końcówkę WY odbiorca; daną końcówkę może posiadać większa liczba procesów. Dostęp do końcówki łącza odbywa się tak samo jak dostęp do pliku tj istnieje otwarty deskryptor końcówki.

    Prawa rządzące łączami:
    Jeśli końcówka WE pewnego łącza nie jest otwarta w żadnym procesie, to końcówka WY tego łącza zachowuje się jak plik który się skończył (tj próba odczytu z tej końcówki da informacje "koniec pliku").

    Potokiem nazywamy ciąg działających wspólbieżnie i komunikujących się poprzez łącza programów (w taki sposób że stdout poprzedniego programu "jest połączony" z stdin następnego programu).

         # przykłady uruchamiania potoków :
         ls -al | cat | cat | sort | cat
         pr03 | cat | cat | cat
    Napis "p1  |  p2" oznacza że utworzono łącze miedzy procesami "p1" i "p2", czyli połączono stdout procesu "p1" z stdin procesu "p2" (operację tę wykonuje powłoka, w której wydaliśmy to polecenie !!!).
     
    Do czego służą potoki ?
    można stworzyć "polecenie złożone" z "poleceń elementarnych";
    teraz przykład - z poleceń elementarnych:
      ls
      grep
      awk
    stworzymy (używając potoku) polecenie złożone wyświetlające info o plikach pewnego rodzaju:
      ls -l | grep '^abc.*\.txt$' | awk '{print $1 $9}'
    (powyższe polecenie wyświetla informacje o plikach mających nazwy postaci "abc*.txt", a ponadto wyświetla tylko prawa do pliku i jego nazwę).

    Zadanie 21

    (zasadnicza różnica między potokami DOS/Windows(?) i UNIX-a)
    Na podstawie przykładu:
        pr03 | cat | cat | cat
    pokaż i uzasadnij, że programy potoku rzeczywiście działają współbieżnie (pod DOS-em jest inaczej!).
    Zanim uruchomisz powyzszy potok odczytaj plik spec terminala poleceniem "tty"; otrzymasz odpowiedz np "tty01". Nastepnie uruchom powyzszy potok. Potem z innego okienka xterm wydaj polecenie "ps -t tty01" i wklej wydruk do sprawozdania.
     

    Zadanie 22


    (Automatyczne "kończenie się" procesow w potokach).
    Uruchom następujący potok:
        cat | cat | cat
    i zaobserwuj co się dzieje po wprowadzeniu linii tekstu. Przekonaj się, że wszystkie 3 procesy działają współbieżnie przy pomocy polecenia "ps" z opcją "-t" z innego okienka xterm (tak jak w powyzszym zadaniu).
    Przekonaj się, że gdy naciśniesz "^D", co dla piewszego programu "cat" ma taki efekt jakby się jego stdin skończył, to wszystkie 3 procesy znikną !. ODPOWIEDZ na pytanie dlaczego tak się dzieje; wymaga to dokładnego przestudiowania definicji łącza oraz informacji że po zakończeniu działania programu wszystkie jego deskryptory są zamykane, a także że program "cat" kończy działnie jeśli się skończy jego stdin.
     

    Opis polecenia "ps".

    Polecenie "ps" pozwala wyciągnąć wszystkie informacje o istniejących procesach (podobnie jak "ls" pozwalało wyciągnąć wszystkie informacje o plikach).
  • ps : wyświetla Twoje procesy, które "mają" terminal sterujący
  • ps -f, ps -l : wyświetlają "nieco więcej" informacji
  • Polecenie "ps" ma 2 grupy opcji:

      --> opcje mówiące KTÓRE procesy pokazywać, np:
             ps -A # wszystkie procesy
    
             ps -t lista_terminali # procesy związane z tymi terminalami
             ps -t ttyp5,ttyp6,ttyp7
    
             ps -u lista_uzytkownikow # wszystkie procesy tych użytkowników
             ps -u mhanckow,root      # w tym także te BEZ terminala !
    
      --> opcje mówiące JAKIE informacje o procesach pokazywać, np:
             ps -o pid,ppid,state,uid,ruid,tty,cmd
             ps -O ppid # "ppid" + standardowe informacje
    
      (Oczywiście, można łączyć obie grupy opcji !)

    Opis polecenia "kill".

    Pozwala ono wysyłać sygnaly do procesów (można używać nazw sygnałów lub ich numerów)
        kill -l # wyświetla dopuszczalne nazwy sygnałów
        kill -kill 1234 # wysłanie sygnału SIGKILL do procesu z pid=1234
        kill -9 1234    # to samo wyżej, bo SIGKILL ma nr 9    
        kill -int 1234  # wysłanie sygnału SIGINT do procesu z pid=1234
        kill -2 1234    # to samo wyżej, bo SIGINT ma nr 2
    Można wysyłać sygnał do większej liczby procesów np :
        kill -kill 0 # wysyła sygnał do wszystkich procesów
                     # w grupie procesów procesu wysyłającego
        kill -kill 1234 1235
                     # do dwóch procesów o podanych pid-ach
    Jeśli się poda ujemną wartość to sygnał jest wysyłany do grupy procesów z PGID równym wartości absolutnej parametru :
        kill -kill -1234 # do wszystkich procesów w grupie pgid=1234
    Inne możliwości - patrz "man 2 kill".

    Numery sygnalow i ich oznaczenia symboliczne mozna znalezc w manualu:

    man 7 signal
      # na Linuxie dane te sa w 7 rozdziale
     

    Zadanie 23


    URUCHOM program "pr03" w jednym xterm-ie, a następnie "zabij" go z drugiego xterm-u sygnałem SIGKILL uzywajac oczywiscie polecenia "kill". Aby wyświetlać procesy z pierwszego xterm-u użyj "tty" i "ps -t".

    Zadanie 24


    WYPRÓBUJ polecenie "kill" w wersji wysyłającej sygnał do grupy procesów.  Jeśli uruchomimy procesy następująco:
       pr02 | pr02 | pr02
    to będą one w jednej grupie procesów.
    UWAGA: w niektórych unixo-podobnych s.o. gdy zabija się lidera grupy procesow (PID=PGID), to do pozostalych procesow grupy jest wysylany sygnal SIGHUP (standardowa reakcja na ten sygnal to zakonczenie). Dlatego aby zobaczyć różnicę miedzy wysyłaniem sygnału do pojedynczego procesu i do całej grupy procesów należy jako "pojedynczy proces" wziąć proces który nie jest liderem grupy !.

    Zadanie 25.


    (Proces "bez rodzica")
    Co się dzieje z parametrem PPID procesu "bez rodzica" ? Należy doprowadzić do następującej sytuacji :
        (ksh) --> (ksh) --> (pr03)
    Symbol "-->" oznacza pokrewieństwo procesów; proces uruchomiony z powłoki jest jej procesem potomnym; powłokę "ksh" uruchamia się poleceniem "ksh". Następnie należy "zabić" środkowe "ksh". Co się stanie z PPID "pr03" ?
    UWAGA: obserwacje procesow oraz wysylanie sygnalow nalezy prowadzic z osobnego okienka !.
     

    Definicja: Proces potomny staje się mumią jeśli się zakończył, jeśli istnieje jego proces macierzysty, oraz jeśli proces macierzysty nie czeka na zakończenie tego procesu potomnego (nie próbuje odczytać jego kodu zakończenia).
    Inne nazwy mumii: zombi. Sens istnienia mumii jest następujący: dopóki ktoś nie odczyta kodu zakończenia procesu dopóty nie może on całkowicie zniknąć z systemu bo gdzieś ten kod zakończenia musi być przechowywany ...

    Zadanie 26


    (Obserwowanie mumii).
    Aby zobaczyc jak polecenie "ps" sygnalizuje mumie stworzymy ja sztucznie przy pomocy programu "mumia.cc" (+"unix.h"). Program ten nalezy skompilowac i uruchomic, wtedy powinna powstac mumia ktora "ps" oznacza przez "<defunct>".
     
     

    Sterowanie pracami.

    (Używamy przykladu "pr03.c" ktory wypisuje kolejne liczby co 1 sekundę)

    Sterowanie pracamy polega na tym, że można "czynić" procesy (i całe ich grupy) procesami drugo-lub-pierwszo-planowymi (gdy one już działają !).
    Robi się to przy pomocy poleceń:

        jobs, bg, fg.
    Przy pomocy klawisza Ctrl-Z można "zatrzymać proces" pierwszoplanowy  (można go potem uczynić pierwszo lub drugo planowym poleceniami "bg" i "fg"). Klawisz Ctrl-Z powoduje wysłanie sygnału SIGTSTP (nie mylić z Ctrl-C).

    Opis poleceń:

    UWAGA 1:  sterowanie pracami jest dostępne tylko w niektórych powłokach; np w "ksh", "bash"

    UWAGA 2:  "praca" nie musi być pojedyńczym procesem; może być całym potokiem jeśli uruchomimy pierwszoplanowy potok i naciśniemy Ctrl-Z to odpowiedni sygnał zostanie wysyłany do wszystkich procesów potoku (wszystkie procesy potoku znajdują się w tej samej grupie procesów - jest to jedno z głownych zastosowań grup procesów !)
     
    Zadanie 27


    1) WYPRÓBUJ powyższe możliwości (czyli polecenia jobs, bg, fg) z programem "pr03" który wyświetla kolejne liczby. Powiedzmy, że włączyliśmy pierwszoplanowo program pr03 z przeadresowaniem stdout; następnie stwierdziliśmy że chcemy włączyć na tym samym terminalu edytor wobec czego pr03 powinien działać drugoplanowo ... jak to zrobić przy pomocy "sterowania pracami" ?
    2) Jeśli proces drugoplanowy "czyta" z terminala to zostanie zatrzymany automatycznie (jest do niego wysyłany sygnał SIGTSTP). Wypróbuj to np z programem "cat" lub "vi".
    3) SPRAWDZ jaki jest stan procesów "zatrzymanych" raportowany przez polecenie "ps" (ps -O state).
    4) PRZEĆWICZ następujący praktyczny przyklad wykorzystania "sterowania pracami":
       # uruchamiamy edytor vi
       vi  
       # nagle przypomnielismy sobie, ze chcemy sprawdzic poczte
       # naciskamy "Ctrl-Z"
       # program "vi" zostaje zatrzymany (ciagle jest w pamieci !)
       # ... mozemy sprawdzic poczte
       # teraz chcemy wznowic dzialanie "vi", 
       # wydajemy polecenie:
       jobs
           # ktore wyswietli cos w rodzaju
           #   [1]+ Stoppend vi
       # mozemy teraz wznowic "vi" jako proces pierwszoplanowy
       # wydajemy polecenie:
       fg %1  
           # "%1" odpowiada napisowi "[1]"
           # UWAGA: kończenie pracy edytora vi: "ZZ" lub ":q!"
     

     

    Efektywny i rzeczywisty uzytkownik procesu (prawo "s").

    Dla kazdego procesu istnieja :
  • rzeczywisty użytkownik procesu (RUID, RUSER)
  • efektywny (lub obowiązujący) użytkownik procesu (UID, USER); standardowo jest to ta sama osoba; proces ma takie prawa do plikow jakie ma do nich efektywny uzytkownik procesu.
  • UWAGA: Pojęć "użytkownik procesu" i "właściciel procesu" używam zamiennie.

    Mozna dowiedziec się kim jest użytkownik rzeczywisty/obowiązujący procesu przy pomocy :

       ps -O uid,ruid
       # lub
       ps -O user,ruser
    Rzeczywistym uzytkownikiem procesu jest zawsze ten kto ten proces uruchomil. Istnieje mozliwosc aby efektywnym uzytkownikiem procesu byl wlasciciel pliku z programem tego procesu. Daje to procesowi prawa do plikow takie jakie ma wlasciciel pliku z programem !.
    Na tej zasadzie dziala program "passwd" do zmieniania hasla ktore znajduje sie w pliku ktorego nie mamy prawa modyfikowac. Oczywiscie wlascicielem programu "passwd" jest root ktory ma prawo modyfikowac plik z haslami !.
    Aby uzyskac ten efekt nalezy nadac prawo "s" wlascicielowi programu poleceniem "chmod u+s dolacz" (wcześniej właściciel musi mieć prawo "x" !):
        ls -l dolacz
        -rwx--x--x ... xxx yyy ... dolacz
        chmod u+s dolacz
        ls -l dolacz
        -rws--x--x ... xxx yyy ... dolacz
    Jeśli drugi uzytkownik (inny niż xxx) nalezy do grupy "yyy" to ma prawo uruchamiac "dolacz", jednak efektywnym uzytkownikiem procesu stanie się "xxx".

    Zadanie 28 (!)


    (To zadanie wymaga 2 uzytkownikow Linuxa !).
    CEL: Chcemy dac innym uzytkownikom mozliwosc kontrolowanego dostepu do pliku "moj_plik.txt". Chcemy aby mogli dopisywac linie na koniec pliku "moj_plik.txt" (i nic wiecej !) przy pomocy programu "dolacz.cc"

    Musisz skompilować program "dolacz", a nastepnie ustawić prawo "s" dla właściciela tego pliku. Musisz także udostępnić ten program drugiej osobie. Musisz zapewnić aby druga osoba nie miała dostępu do "moj_plik.txt" BEZ programu "dolacz" !.

    UWAGA:  to zadanie może się nie udać jeśli system plików na którym działamy został zamontowany w globalnym drzewie katalogów z opcją "nosuid", która powoduje wyłączenie działania prawa "s". Można to sprawdzić wydając polecenie "mount", bez parametrów, lub oglądając plik /etc/fstab (w takim wypadku można jeszcze spróbować z katalogiem "/tmp", do którego mamy prawo "w" !).
     
     
     

    Polecenie "screen".

    Polecenie screen tworzy kilka "wirtualnych ekranów" na pojedynczym tekstowym terminalu (xterm).
    Oznacza to m.in. że z pojedynczego terminala tekstowego możemy uruchomić równocześnie kilka polecen "pelnoekranowych", takich jak pine czy pico.
     
  •   Na poczatku nalezy wydac polecenie "screen".
  •   Nowy "wirtualny ekran" tworzymy kombinacja klawiszy: Ctrl-a c
  •   Przelaczanie miedzy ekranami: Ctrl-a n, Ctrl-a p, Ctrl-a <nr ekranu liczac od 0>
  •   Usuwanie bieżącego ekranu: Ctrl-a K (Musi byc duze K !)
  •   Istnieje mozliwosc wylogowania sie i ponownego zalogowania polaczonego z uaktywnieniem pozostawionych ekranow, wraz z ich programami. Aby sie wylogowac nacisnij: Ctrl-a DD. Potem, po ponownym zalogowaniu, nalezy wydac polecenie "screen -r", i wszystkie programy ktore pozostawilismy powinny zaczac normalnie dzialac.
  • Cwiczenie 29


    Wypróbuj polecenie "screen" (wymienione powyżej możliwości).
     
     
     
     

    Łącza nazwane (pliki FIFO).

  • Lącze nazwane to kanał komunikacyjny między dwoma procesami.
  • Łącza nazwane są widoczne jako pliki w drzewie katalogów, w przeciwieństwie do łączy nienazwanych z jakimi mamy do czynienia podczas uruchamiania potoków.
  • Polecenie "ls" pokazuje literkę "p" jako typ pliku, a jako długość pliku pokazuje ilość znaków zalegających w łączu (które mogą być przeczytane przez jakiś proces).
  • --> tworzenie "laczy nazwanych":

    	mkfifo plik_fifo_1
    	mkfifo plik_fifo_2
    Prawa rządzące łączami nazwanymi
    (w ponizszym opisie łączy nazwanych odwołuję się do pojęcia "funkcji systemowej UNIX-a", ktore to pojecie bedzie wyjasnione dopiero pozniej ...)

    --> uzywanie "laczy nazwanych":
          nalezy je otworzyc tak jak zwykle pliki, przy pomocy fun. sys. open(), otrzymując przy tym deskryptor;
          musimy otwierać łącze nazwane w trybie "tylko do odczytu" lub "tylko do zapisu";
          podczas otwierania, fun. sys. open() moze blokowac na następujących zasadach:
          1) jesli otwieramy z flaga O_RDONLY to open() blokuje az jakis proces nie otworzy lacza do zapisu
          2) jesli otwieramy z flaga O_WRONLY to open() blokuje az jakis proces nie otworzy lacza do odczytu

    --> funkcje read() i write(), służące do czytania i pisania z/do otwartego pliku
          wspolpracuja z laczami na następujących zasadach:

        1) jesli czytamy fun. "read()" z lacza, ktorego NIKT
          nie ma otwartego do zapisu  to "read()" zwraca 0
          (czyli zachowuje się tak jakby plik sie skonczyl)

        1A) jesli ktos ma to lacze otwarte do zapisu, lecz jest ono PUSTE
          to fun. "read()" blokuje, az nie pojawia sie jakies znaki.
          (Jesli w pewnym momencie okaze sie, ze nie ma procesow
          ktore maja to lacze otwarte do zapisu to fun. "read()"
          zakonczy sie i zwroci 0).

        2) jesli piszemy fun. "write()" do lacza, ktorego NIKT
          nie ma otwartego do czytania, to jest wysylany sygnal SIGPIPE
          a funkcja "write()" konczy dzialanie z bledem.

        2A) jesli ktos ma to lacze otwarte do czytania,
          lecz w pewnym momencie uleglo ono PRZEPELNIENIU
          to fun. "write()" bedzie blokowac.
          (Jesli w pewnym momencie okaze sie, ze nie ma procesow
          ktore maja to lacze otwarte do czytania to fun. "write()"
          zakonczy sie bledem i bedzie wyslany SIGPIPE).
     

    Zadanie 30


    Utwórz dwa łącza nazwane "fifo1" i "fifo2", a następnie uruchom drugoplanowo program "cat" tak aby czytał z pliku "fifo1" i pisał do pliku "fifo2" (oznacza to przepisywanie fifo1 do fifo2).  Następnie sprawdź czy to wszystko działa zgodnie z naszymi przewidywaniami.
    Wskazówki: program "cat" (ktory przepisuje stdin na stdout)  uruchamiamy nastepujaco :
          cat < fifo1 > fifo2 &
    Jeśli wpiszmy cos do lacza fifo1 :
         echo "1234" > fifo1
         echo "ABCD" > fifo1
    to mozemy sie przekonac, ze "cat" rzeczywiscie przepisuje fifo1 do fifo2 nastepujaco:
          read x < fifo2; echo $x
          # polecenie "read" odczytuje jedną linię tekstu 
          # i umieszcza ją w zmiennej "x";
          # "echo $x" wypisuje zawartość zmiennej "x"
          # a oto inny sposób ...
          
          cat < fifo2
          # wypisywana jest cala zawartosc fifo2
          # w tym wypadku trzeba bedzie zakonczyc program cat 
          # przez Ctrl-C (dlaczego ???)
    Ile bajtow znajduje sie w laczach mozemy sie przekonac wydajac polecenie:
          ls -l  fifo*
    UWAGA: okazje się że łącze "fifo1" musi byc caly czas otwarte do zapisu (przez niezalezny proces dzialajacy w tle, którego kod znajduje się w pliku "fifoprg.cc").  W przeciwnym wypadku powyższy eksperyment nie zadziała, gdyż polecenie "echo 1234 > fifo1" jest realizowane przez powłokę w ten sposób że plik "fifo1" jest otwierany, jest do niego zapisywany tekst, a następnie plik "fifo1" jest zamykany - w tym momencie program cat "pomysli sobie", ze jego stdin sie skonczyl i sam sie zakonczy (wynika to z własności łączy - punkt "1" !).
     

    Zadanie 31


    Utwórz cykl procesów "cat" połączonych łączami, po którym krąży napis "ABC". Użyj potoków i łączy nazwanych. Potok można uruchomić następująco: "cat <fifo | cat | cat | cat >fifo". Jak sprawdzić czy to rzeczywiście dziala ? (zobacz w manualu: polecenie "tee").
     

    Terminale tekstowe (baza TermInfo).

     Istnieje wiele typow terminali, nazwa typu terminala jest
     przechowywany w zmiennej srodowiska TERM.

     Istnieja "bazy danych" przechowujace informacje o terminalach roznego typu.
     Sa tam np informacje o tym jakie "kody" do czego sluza w danym terminalu
     (np jaki jest kod sluzacy do "czyszczenia" terminala).

     Sa dwie takie "bazy danych" :
         TERMCAP - jeden plik tekstowy (jest to baza starego typu)

         TERMINFO - wiele plikow binarnych, w specjalnych podkatalogach
              (chodzi tu o szybkosc dostepu do definicji terminala;
              jesli wszystko jest w jednym pliku - to jest on b. dlugi)

     Przykladowo opis terminala typu "xterm" wyglada nastepujaco:

           xterm|vs100|xterm terminal emulator,
                ind=^J, cols#80, lines#25,
                clear=E[HE[2J, cub1=^H, am, cup=E[%i%p1%d;%p2%dH,
                cuf1=E[C, cuu1=E[A, el=E[K, ed=E[J,
                cud=E[%p1%dB, cuu=E[%p1%dA, cub=E[%p1%dD,
                cuf=E[%p1%dC, km,
                smso=E[7m, rmso=E[m, smul@, rmul@,
                bold=E[1m, rev=E[7m, blink=@, sgr0=E[m,
                rs1=E>E[1;3;4;5;6lE[?7hE[mE[rE[2JE[H, rs2=@
                kf1=EOP, kf2=EOQ, kf3=EOR, kf4=EOS, ht=^I, ri=EM,
                vt@, xon@, csr=E[%i%p1%d;%p2%dr,
                il=E[%p1%dL, dl=E[%p1%dM, il1=E[L, dl1=E[M,
                ich=E[%p1%d@, dch=E[%p1%dP, ich1=E[@, dch1=E[P,
                use=vt100-am,
     znajduje sie on (w formie skompilowanej=binarnej) w pliku :
            /usr/lib/terminfo/x/xterm
     natomiast "zrodlo" znajduje sie w pliku :
            /usr/lib/terminfo/xterm.ti
     Aby skompilowac opis terminala w pliku "*.ti" nalezy uzyc programu "tic" :
            tic xterm.ti
     Program "tic" automatycznie tworzy podkatalogi
     jednoliterowe "x" i "v", w ktorch umieszcza pliki binarne

     Aby programy uzywaly "naszego katalogu terminfo"
     nalezy ustawic zmienna srodowiska TERMINFO :

            export TERMINFO=<nasz katalog terminfo>
    Zadanie 32 (!)

    Zmien (odrobinę) definicje Twojego terminala tekstowego. Skopiuj plik "xterm.ti" do wlasnego "katalogu terminfo" (musisz ustawic zmienna TERMINFO na ten katalog). Mozesz dopisac cos na koncu kodu wykonujacego "clear", np:
        clear=E[HE[2JA ku ku !!!
    w pliku "xterm.ti".  Skompiluj plik "xterm.ti" programem "tic".  Potem uruchom jakis program uzywajacy TERMINFO (np vi) aby zobaczyc efekt zmiany.