Każdy działający proces (=uruchomiony program) posiada m.in. następujące parametry:
Można zobaczyć jakie procesy obecnie działają oraz obejrzeć ich parametry przy pomocy polecenia "ps"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.
# 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=1234UWAGA: (działanie klawiszy Ctrl-C, Ctrl-Z, Ctrl-D)
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
pr01 qqq www eee > plik.txtto 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ę sekundJeś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
Łą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 | catNapis "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:
grep awk
|
pr03 | cat | cat | catpokaż i uzasadnij, że programy potoku rzeczywiście działają współbieżnie (pod DOS-em jest inaczej!).
Zadanie 22
cat | cat | cati 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).
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 !)
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 2Moż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-achJeś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=1234Inne 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
Zadanie 24
pr02 | pr02 | pr02to będą one w jednej grupie procesów.
Zadanie 25.
(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" ?
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
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 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
# 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!"
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,ruserRzeczywistym 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 ... dolaczJeśli drugi uzytkownik (inny niż xxx) nalezy do grupy "yyy" to ma prawo uruchamiac "dolacz", jednak efektywnym uzytkownikiem procesu stanie się "xxx".
Zadanie 28 (!)
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" !).
Cwiczenie 29
--> tworzenie "laczy nazwanych":
mkfifo plik_fifo_1 mkfifo plik_fifo_2Prawa rządzące łączami nazwanymi
--> 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
cat < fifo1 > fifo2 &Jeśli wpiszmy cos do lacza fifo1 :
echo "1234" > fifo1 echo "ABCD" > fifo1to 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
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/xtermnatomiast "zrodlo" znajduje sie w pliku :
/usr/lib/terminfo/xterm.tiAby skompilowac opis terminala w pliku "*.ti" nalezy uzyc programu "tic" :
tic xterm.tiProgram "tic" automatycznie tworzy podkatalogi
Aby programy uzywaly "naszego katalogu terminfo"
nalezy ustawic zmienna srodowiska TERMINFO :
export TERMINFO=<nasz katalog terminfo>Zadanie 32 (!)
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.