Część II
Użytkownicy i grupy¶
Linux od początku był systemem dla wielu osób pracujących jednocześnie na tym samym komputerze.
Każda osoba ma własne konto użytkownika (ang. user).
System rozpoznaje użytkownika po liczbie: UID (ang. user ID); login to tylko czytelna dla człowieka etykieta.
Użytkowników można łączyć w grupy (ang. group), które również mają swoje numery: GID.
Specjalny użytkownik root ma UID równy 0 i jest administratorem: system pozwala mu na wszystko.
Polecenie id pokazuje, kim jesteśmy,
a groups wypisuje same nazwy naszych grup:
z1234567@student:~$ id
uid=20936(z1234567) gid=20936(z1234567) groups=20936(z1234567),100(users)
z1234567@student:~$ groups
z1234567 users
Na serwerze studenckim każdy ma własną grupę o nazwie loginu, a wszyscy studenci należą też do grupy users.
Informacje o kontach i grupach system przechowuje w plikach tekstowych:
/etc/passwd-- konta użytkowników (może czytać każdy),/etc/group-- grupy i ich członkowie (może czytać każdy),/etc/shadow-- skróty (hashe) haseł (może czytać tylko administrator).
Polecenie getent przeszukuje te bazy, także wtedy, gdy konta są zapisane gdzie indziej (np. w LDAP):
z1234567@student:~$ getent passwd z1234567
z1234567:x:20936:20936:Jan Kowalski,,,:/home/z1234567:/bin/bash
z1234567@student:~$ getent group users
users:x:100:banakh,bosek,brianski,duraj,...
Każda linijka /etc/passwd ma format
login:x:UID:GID:opis:katalog domowy:powłoka
x w drugim polu oznacza, że hasła tu nie ma: jest w /etc/shadow.
GID to główna grupa użytkownika; pozostałe grupy wynikają z /etc/group.
Każdy plik i każdy proces w systemie ma właściciela (użytkownika), a plik ma także grupę.
Zarządzanie kontami¶
Konta i grupy zakłada administrator.
Żeby wykonać pojedyncze polecenie jako root, używa się polecenia sudo.
Wolno to tylko użytkownikom wskazanym w konfiguracji sudo (zwykle członkom grupy sudo).
Na serwerze studenckim nie mamy takich uprawnień, więc poniższe polecenia skończą się odmową; warto jednak wiedzieć, jak wyglądają:
sudo adduser anna # nowe konto z katalogiem domowym; pyta o hasło
sudo addgroup projekt # nowa grupa
sudo usermod -aG projekt anna # dopisz użytkownika anna do grupy projekt
sudo gpasswd -d anna projekt # wypisz annę z grupy projekt
sudo deluser --remove-home anna # usuń konto razem z katalogiem domowym
sudo delgroup projekt # usuń grupę
sudo passwd anna # ustaw annie nowe hasło
- W
usermod -aGliteraa(ang. append) oznacza „dopisz”. Samo-G projektzastąpiłoby listę dodatkowych grup użytkownika. - Przynależność do nowej grupy zaczyna działać od następnego logowania.
- Własne hasło każdy zmienia sam poleceniem
passwd, bezsudo. adduser,deluser,addgroupidelgroupto wygodne nakładki dostępne w Debianie i Ubuntu. W każdym Linuksie działają niskopoziomoweuseradd(useradd -m anna),userdel(userdel -r anna),groupaddigroupdel.
Prawa dostępu¶
Odczytywanie praw¶
Kolumny wypisywane przez ls -l omówiliśmy w części I.
Teraz przyjrzyjmy się pierwszej z nich:
z1234567@student:~$ ls -l /etc/passwd /etc/shadow
-rw-r--r-- 1 root root 23187 Oct 12 12:34 /etc/passwd
-rw-r----- 1 root shadow 10807 Oct 5 11:10 /etc/shadow
z1234567@student:~$ cat /etc/shadow
cat: /etc/shadow: Permission denied
-rw-r----- root shadow /etc/shadow
│└┬┘└┬┘└┬┘ │ └ grupa pliku
│ u g o └ właściciel pliku
└ typ: - zwykły plik, d katalog, l dowiązanie symboliczne
Po typie następują trzy trójki praw:
u (ang. user) dla właściciela, g (ang. group) dla członków grupy pliku i o (ang. others) dla wszystkich pozostałych.
Każda trójka to r (odczyt), w (zapis) i x (wykonanie); - oznacza brak prawa.
System wybiera jedną trójkę: jeśli jesteś właścicielem, liczy się u;
jeśli nie, ale należysz do grupy pliku, liczy się g; w przeciwnym razie o.
Prawa z różnych trójek się nie sumują: plik z prawami ----r--r-- mogą czytać wszyscy poza jego właścicielem.
Dla /etc/shadow jesteśmy „pozostałymi” (o), a ta trójka to ---, stąd odmowa.
Opcja -d pokazuje prawa samego katalogu zamiast jego zawartości:
z1234567@student:~$ ls -ld ~
drwx--x--- 8 z1234567 www-data 4096 Mar 24 2023 /home/z1234567
Do naszego katalogu domowego wchodzimy tylko my oraz serwer WWW (grupa www-data), który może przejść do katalogu public_html.
Znaczenie praw dla plików i katalogów¶
| Prawo | Zwykły plik | Katalog |
|---|---|---|
r |
odczyt zawartości | odczyt listy nazw (ls) |
w |
zmiana zawartości | tworzenie, usuwanie i zmiana nazw wpisów (razem z x) |
x |
uruchomienie jako program | wejście (cd) i dostęp do pliku o znanej nazwie |
Katalog można wyobrazić sobie jako szafkę z kartkami:
r pozwala przeczytać spis kartek, x pozwala sięgnąć po kartkę, której nazwę znamy, a w pozwala dokładać i wyjmować kartki.
Przykład:
z1234567@student:~$ mkdir szafka; echo tajne > szafka/kartka
z1234567@student:~$ chmod u-x szafka
z1234567@student:~$ ls szafka
kartka
z1234567@student:~$ cat szafka/kartka
cat: szafka/kartka: Permission denied
z1234567@student:~$ chmod u+x,u-r szafka
z1234567@student:~$ ls szafka
ls: cannot open directory 'szafka': Permission denied
z1234567@student:~$ cat szafka/kartka
tajne
Wnioski:
- Bez
xwidzimy nazwy, ale nie dostaniemy się do plików. - Bez
rnie wylistujemy katalogu, ale plik o znanej nazwie przeczytamy. - Dostęp do pliku wymaga prawa
xwe wszystkich katalogach na ścieżce. - Usunięcie pliku zmienia spis w katalogu, więc decyduje o nim prawo
wkatalogu, a nie samego pliku. - Kropka na początku nazwy tylko ukrywa plik przed
ls; nie jest zabezpieczeniem.
Zmiana praw: chmod¶
Polecenie chmod zmienia prawa.
W zapisie symbolicznym podajemy komu (u, g, o, a -- wszystkim), jak (+ dodaj, - zabierz, = ustaw dokładnie) i jakie prawa:
chmod u+x skrypt.sh # właścicielowi dodaj x
chmod go-rwx plik # grupie i pozostałym zabierz wszystko
chmod a+r plik # wszystkim dodaj odczyt
chmod u+w,g+rx plik # kilka zmian naraz, po przecinku
W zapisie ósemkowym każda trójka to suma r=4, w=2, x=1, a trzy cyfry to kolejno u, g, o:
chmod 640 plik → rw- r-- --- (6 = 4+2, 4 = 4, 0)
| Tryb | Typowe zastosowanie |
|---|---|
600 |
prywatny plik, np. klucz SSH |
700 |
prywatny katalog, np. ~/.ssh |
644 |
plik czytelny dla wszystkich |
755 |
katalog lub program dostępny dla wszystkich |
711 |
program, który inni mogą uruchomić, ale nie przeczytać |
Liczba ustawia wszystkie trzy trójki naraz, zapis symboliczny zmienia tylko wymienione prawa.
Prawa pliku może zmienić tylko jego właściciel (oraz root).
Trybu 777 nie używamy jako „naprawy” problemów z dostępem: pozwala każdemu zmienić lub podmienić plik.
Właściciel i grupa pliku¶
chgrp zmienia grupę pliku.
Właściciel może ustawić tylko grupę, do której sam należy:
z1234567@student:~$ chgrp users notatki.txt
z1234567@student:~$ ls -l notatki.txt
-rw-rw-r-- 1 z1234567 users 0 Oct 19 10:15 notatki.txt
chown zmienia właściciela.
Wolno to tylko administratorowi (inaczej można by „podrzucić” komuś plik):
z1234567@student:~$ chown root notatki.txt
chown: changing ownership of 'notatki.txt': Operation not permitted (os error 1)
sudo chown anna plik # nowy właściciel
sudo chown anna:projekt plik # właściciel i grupa naraz
sudo chown -R anna katalog # rekurencyjnie: katalog z całą zawartością
Opcja -R działa także w chmod i chgrp.
Prawa nowych plików: umask¶
Nowo tworzone pliki dostają prawa wynikające z maski umask, która zabiera wybrane bity.
Programy zwykle proszą o 666 dla plików i 777 dla katalogów; maska je ogranicza:
z1234567@student:~$ umask
0002
z1234567@student:~$ touch nowy; mkdir nowyk; ls -ld nowy nowyk
-rw-rw-r-- 1 z1234567 z1234567 0 Oct 19 10:20 nowy
drwxrwxr-x 2 z1234567 z1234567 4096 Oct 19 10:20 nowyk
Maska nie zmienia istniejących plików, a nowy plik nigdy nie dostaje automatycznie prawa x.
Uruchamianie programów¶
Powłoka szuka poleceń w katalogach wymienionych w zmiennej PATH (o zmiennych niżej).
Bieżącego katalogu tam nie ma, dlatego program z bieżącego katalogu uruchamiamy, poprzedzając jego nazwę ./:
z1234567@student:~$ echo 'echo Hej' > hej.sh
z1234567@student:~$ ./hej.sh
-bash: ./hej.sh: Permission denied
z1234567@student:~$ chmod u+x hej.sh
z1234567@student:~$ ./hej.sh
Hej
z1234567@student:~$ hej.sh
hej.sh: command not found
Plik hej.sh to skrypt: plik tekstowy z poleceniami dla powłoki.
Pierwsza linijka skryptu może zaczynać się od #!, np. #!/bin/bash; wskazuje wtedy program, który ma ten skrypt wykonać.
Skrypt jest czytany przez interpreter, więc potrzebuje praw r i x.
Program skompilowany (np. z C) uruchamia bezpośrednio jądro systemu, więc wystarczy mu samo x.
Specjalne bity¶
- Sticky bit (
tna miejscu ostatniegox): w takim katalogu każdy może tworzyć pliki, ale usuwać tylko własne. Ma go/tmp:drwxrwxrwt. - Setuid (
sna miejscuxwłaściciela): program działa z prawami swojego właściciela, a nie uruchamiającego. Tak działapasswd, który musi zmienić/etc/shadow:-rwsr-xr-x 1 root root ... /usr/bin/passwd.
Potoki¶
Znak | łączy dwa polecenia: standardowe wyjście pierwszego staje się standardowym wejściem drugiego, bez pliku pośredniego.
Polecenia można łączyć w dłuższe łańcuchy:
z1234567@student:~$ printf 'kawa\nherbata\nkawa\nsok\nherbata\nkawa\n' > napoje
z1234567@student:~$ sort napoje | uniq -c | sort -n
1 sok
2 herbata
3 kawa
z1234567@student:~$ sort napoje | uniq -u
sok
z1234567@student:~$ ls /etc | wc -l
(printf działa jak echo, ale \n w tekście oznacza nową linię.)
uniqporównuje tylko sąsiednie linijki, dlatego zwykle poprzedza gosort.- Program, któremu nie podamy pliku, czyta standardowe wejście; dlatego
uniq -cpo|nie potrzebuje nazwy pliku. - Potok przekazuje dane, nie argumenty. Komunikaty błędów (standardowe wyjście błędów) nadal trafiają na ekran.
tail -f plikwypisuje nowe linijki dopisywane do pliku na bieżąco; kończymy go Ctrl+C.
Zmienne¶
Powłoka pamięta zmienne: nazwy, pod którymi zapisany jest tekst.
z1234567@student:~$ x=kawa
z1234567@student:~$ echo $x
kawa
z1234567@student:~$ echo "Pije $x"
Pije kawa
z1234567@student:~$ echo 'Pije $x'
Pije $x
z1234567@student:~$ x = kawa
x: command not found
z1234567@student:~$ unset x
- Przy przypisaniu nie może być spacji wokół
=; inaczej powłoka uznaxza nazwę polecenia. $xpowłoka zamienia na wartość, zanim uruchomi polecenie. W cudzysłowie"..."zamiana działa, w apostrofach'...'nie.- Zmienną zawierającą ścieżkę piszemy w cudzysłowie (
"$D"), bo wartość może zawierać spacje. - Niektóre zmienne są ustawione od początku:
USER(login),HOME(katalog domowy),PATH(katalogi, w których powłoka szuka programów). - Zmienna istnieje tylko w powłoce, w której ją ustawiono: w drugim terminalu jej nie będzie.
Żeby była ustawiana w każdej nowej powłoce, dopisujemy przypisanie do pliku
~/.bashrc.export xudostępnia zmienną także programom uruchamianym z tej powłoki.
Zmienne przydają się jako skróty: K=/tmp/kopernik/bin/kopernik, a potem "$K" status.
Procesy¶
Program to plik na dysku. Proces to uruchomiony program. Ten sam program może działać jednocześnie w wielu procesach. Każdy proces ma:
- PID -- swój numer,
- PPID -- numer rodzica, czyli procesu, który go uruchomił,
- właściciela (UID),
- stan:
Rdziała,Sśpi (czeka np. na dane),Twstrzymany,Zzombie (zakończony, ale rodzic nie odebrał jeszcze jego wyniku).
Po zakończeniu procesu jego PID może zostać kiedyś użyty ponownie, dlatego zanim coś zrobimy z procesem, sprawdzamy, czy to na pewno ten.
Przeglądanie procesów¶
Polecenie ps:
ps-- nasze procesy w bieżącym terminalu,ps x-- wszystkie nasze procesy, także w innych terminalach,ps ax-- procesy wszystkich użytkowników,ps u,ps ux-- dodatkowo właściciel, zużycie procesora i pamięci, czas startu,ps -o pid,ppid,stat,etime,args-- wybrane kolumny,ps -u "$USER" -o pid,pcpu,comm --sort=-pcpu-- nasze procesy posortowane od największego zużycia procesora.
$$ to PID bieżącej powłoki, a pstree rysuje drzewo procesów:
z1234567@student:~$ sleep 100 &
[1] 31012
z1234567@student:~$ echo $$
30998
z1234567@student:~$ ps -o pid,ppid,stat,args
PID PPID STAT COMMAND
30998 30997 Ss -bash
31012 30998 S sleep 100
31014 30998 R+ ps -o pid,ppid,stat,args
z1234567@student:~$ pstree -p $$
bash(30998)-+-pstree(31025)
`-sleep(31012)
Polecenie pgrep wyszukuje procesy:
-u login -- tylko danego użytkownika, -x -- dokładna nazwa, -a -- pokaż argumenty.
z1234567@student:~$ pgrep -a -u "$USER" -x sleep
31012 sleep 100
Argumenty wywołania procesów są widoczne dla wszystkich użytkowników serwera (ps ax -o user,args).
Dlatego nie przekazujemy haseł w argumentach poleceń.
Informacje o procesach system udostępnia w katalogu /proc: /proc/PID/ dla każdego procesu.
Tryb interaktywny: top i htop¶
top i
htop
pokazują procesy na żywo, odświeżając listę co kilka sekund.
top -u "$USER" pokazuje tylko nasze procesy.
W top: P sortuje po zużyciu procesora, M po pamięci, k wysyła sygnał (o sygnałach niżej), h pomoc, q wyjście.
htop jest wygodniejszy: F6 sortowanie, F5 drzewo, F9 sygnał, F10 wyjście.
Kolumna %CPU to pomiar w czasie: żeby wskazać proces stale zajmujący procesor, trzeba poczekać kilka odświeżeń.
Przydatny do eksperymentów jest program yes, który bez końca wypisuje y:
z1234567@student:~$ nice -n 19 yes > /dev/null &
z1234567@student:~$ top -u "$USER"
Po obejrzeniu kończymy go poleceniem kill %1 (zob. niżej).
Priorytet procesu (nice) to liczba od -20 (najwyższy) do 19 (najniższy), domyślnie 0.
nice -n 19 polecenie uruchamia polecenie z najniższym priorytetem,
a renice -n 19 -p PID zmienia priorytet działającego procesu.
Zwykły użytkownik może priorytet tylko obniżać.
Zadania w powłoce¶
Polecenie uruchomione zwykle działa na pierwszym planie: zajmuje terminal, dopóki się nie skończy.
Zakończone znakiem & działa w tle, a powłoka od razu wypisuje prompt.
Powłoka nazywa takie procesy zadaniami (ang. jobs) i numeruje je osobno: %1, %2, ...
| Polecenie | Działanie |
|---|---|
polecenie & |
uruchom w tle; powłoka wypisze [numer zadania] PID |
| Ctrl+Z | wstrzymaj zadanie z pierwszego planu (proces żyje, stan T) |
jobs -l |
lista zadań tej powłoki z PID-ami i stanem |
bg %1 |
wznów zadanie 1 w tle |
fg %1 |
wznów zadanie 1 na pierwszym planie |
kill %1 |
poproś zadanie 1 o zakończenie |
| Ctrl+C | przerwij zadanie z pierwszego planu |
| Ctrl+D | koniec danych na wejściu (to nie przerwanie) |
z1234567@student:~$ sleep 300
^Z
[1]+ Stopped sleep 300
z1234567@student:~$ bg %1
[1]+ sleep 300 &
z1234567@student:~$ jobs -l
[1]+ 31200 Running sleep 300 &
z1234567@student:~$ fg %1
sleep 300
^C
bg i fg nie uruchamiają nowej kopii: to ciągle ten sam proces z tym samym PID.
Numer zadania istnieje tylko w powłoce, która je uruchomiła; w innym terminalu jobs go nie pokaże, a %1 oznacza coś innego.
PID jest wspólny dla całego systemu.
Więcej: Job Control Basics.
Praca po rozłączeniu¶
Gdy zamykamy terminal lub zrywa się połączenie SSH, procesy uruchomione w tej sesji dostają sygnał HUP i zwykle się kończą, także te w tle.
nohup polecenie &-- polecenie przetrwa zamknięcie terminala; jego wyjście trafi do plikunohup.out.tmux-- sesja terminala działająca na serwerze, z oknami i podziałem ekranu. Ctrl+B D odłącza sesję (dalej działa), atmux attachwraca do niej, także po ponownym zalogowaniu. Ctrl+B C tworzy nowe okno, Ctrl+B N przechodzi do następnego, Ctrl+B ++%++ dzieli ekran.byobu-- nakładka natmuxz paskiem stanu: F2 nowe okno, F3/F4 przełączanie, F6 odłączenie; ponownebyobuwraca do sesji.
Sygnały¶
Jak działają Ctrl+C i Ctrl+Z? Terminal wysyła procesowi sygnał: krótki komunikat od systemu.
Proces może na sygnał zareagować po swojemu, zignorować go albo zachować się domyślnie (zwykle zakończyć).
Wyjątkami są KILL i STOP: tych program nie może przechwycić ani zignorować.
| Sygnał | Jak wysłać | Znaczenie |
|---|---|---|
TERM |
kill PID (domyślny) |
prośba o zakończenie; program może posprzątać |
INT |
Ctrl+C | przerwanie z klawiatury |
TSTP |
Ctrl+Z | prośba o wstrzymanie |
STOP |
kill -STOP PID |
wstrzymanie, zawsze skuteczne |
CONT |
kill -CONT PID, bg, fg |
wznowienie |
KILL |
kill -KILL PID (kill -9) |
natychmiastowe zakończenie, bez sprzątania |
HUP |
zamknięcie terminala | terminal zniknął |
USR1, USR2 |
kill -USR1 PID |
znaczenie ustala autor programu |
Polecenie kill wysyła sygnał -- nazwa myli, bo nie każdy sygnał kończy proces.
Zamiast PID można podać numer zadania (kill %1). kill -l wypisuje nazwy sygnałów,
a pełny opis jest w man 7 signal.
W skrypcie reakcję na sygnał ustawia polecenie trap. Przykładowy skrypt ekspres.sh:
trap 'echo zapisuje; rm szkic.tmp; exit' TERM
trap 'echo odebrano wiadomosc' USR1
touch szkic.tmp
while true; do date >> dziennik; sleep 1; done
Skrypt tworzy plik szkic.tmp, a potem w nieskończonej pętli co sekundę dopisuje datę do pliku dziennik.
Uruchommy go w tle i obserwujmy tail -f dziennik w drugim terminalu:
z1234567@student:~$ sh ekspres.sh &
[1] 4100
z1234567@student:~$ kill -STOP %1 # dziennik przestaje rosnąć
z1234567@student:~$ kill -CONT %1 # i rośnie dalej
z1234567@student:~$ kill -USR1 %1
odebrano wiadomosc
z1234567@student:~$ kill %1
zapisuje
Po TERM skrypt posprzątał: szkic.tmp zniknął.
Gdyby zamiast tego dostał KILL, zakończyłby się natychmiast, a szkic.tmp zostałby na dysku.
Dlatego najpierw wysyłamy TERM, a KILL tylko wtedy, gdy TERM nie działa.
USR1 wysłany do programu, który go nie obsługuje (np. do sleep), zwykle go zakończy.
Kilka procesów naraz:
pkill-- jakpgrep, ale od razu wysyła sygnał wszystkim znalezionym procesom, np.pkill -TERM -u "$USER" -x sleep. Warto najpierw uruchomićpgrepz tymi samymi opcjami i sprawdzić, co zostanie wybrane.killall nazwa-- wysyła sygnał wszystkim procesom o danej nazwie.
Takie polecenia łatwo trafiają w procesy, których nie chcieliśmy zakończyć.
Na przykład pkill -u "$USER" bez nazwy zakończyłby wszystkie nasze procesy, w tym połączenie SSH.
Zwykły użytkownik może wysyłać sygnały tylko do własnych procesów; próba wobec cudzego kończy się błędem Operation not permitted.
Administrator (sudo kill PID) może wysłać sygnał do każdego procesu.
Dobry nawyk: obejrzyj (pgrep -a, ps) → wybierz swój PID → wyślij sygnał → sprawdź efekt.
Rodzic i sierota¶
Proces, którego rodzic się zakończył, staje się sierotą i zostaje przygarnięty przez innego rodzica:
zwykle przez proces numer 1 (init/systemd), czasem przez proces, który zgłosił się jako opiekun swoich potomków (ang. subreaper).
z1234567@student:~$ sh -c 'sleep 333 & echo $!'
4650
z1234567@student:~$ ps -o pid,ppid,args -p 4650
PID PPID COMMAND
4650 1 sleep 333
z1234567@student:~$ kill 4650
sh -c '...' uruchamia nową powłokę z podanymi poleceniami, a $! to PID ostatniego procesu uruchomionego w tle.
Powłoka sh uruchomiła sleep i od razu się zakończyła, więc sleep dostał nowego rodzica.
Odwrotna sytuacja to zombie: proces już się zakończył, ale rodzic nie odebrał jeszcze informacji o tym, jak się zakończył. Zombie nie zużywa procesora i nie da się go zakończyć sygnałem, bo już nie działa; zniknie, gdy rodzic odbierze wynik albo sam się zakończy.
Przydatne skróty klawiaturowe¶
- Up, Down -- historia poleceń,
- Tab -- dopełnianie nazw poleceń i ścieżek,
- Ctrl+R -- wyszukiwanie w historii poleceń,
- Ctrl+L -- czyszczenie ekranu,
- Ctrl+C -- przerwanie zadania z pierwszego planu,
- Ctrl+Z -- wstrzymanie zadania z pierwszego planu,
- Ctrl+D -- koniec danych na wejściu; w pustym wierszu powłoki kończy powłokę.
Więcej: Command Line Editing.