Systemy operacyjne

Transkrypt

Systemy operacyjne
Systemy operacyjne
część 2
Artur Gramacki
Instytut Informatyki i Elektroniki
getopt()
1
Argumenty programu, funkcja getopt()
Prosty przykład
$ ./args -a plik -b cos-innego
#include <stdio.h>
argument 0: ./args
int main (int argc, char *argv[]) {
option: a
int i;
argument 2: plik
for (i = 0; arg < argc; arg++) {
option: b
if (argv[arg][0] == '-')
argument 4: cos-innego
printf ("option: %s\n", argv[arg]+1);
else
printf ("argument %d: %s\n", i, argv[arg]);
}
exit(0);
przykłady (jeżeli nie zaznaczono inaczej) pochodzą z [4]
}
… a co powiesz, gdy trzeba obsłużyć coś takiego:
tar
[ - ] A --catenate --concatenate | c --create | d --diff --compare | r --append | t
--list | u --update | x -extract --get [ --atime-preserve ] [ -b, --block-size N ] [ -B,
--read-full-blocks ] [ -C, --directory KATALOG ] [ --checkpoint
] [ -f, --file [HOSTNAME:]F ] [ --force-local
] [ -F, --info-script F --new-volume-script F ] [ -G, --incremental ] [ -g, --listed-incremental F ] [ -h, --dereference ] [ -i, --ignore-zeros ] [ -j,
--bzip2 ] [ --ignore-failed-read ] [ -k, --keep-old-files ] [ -K, --starting-file F ] [ -l,
--one-file-system ] [ -L, --tape-length N ] [ -m, --modification-time ] [ -M, --multi-volume ] [ -N, --after-date DATA, --newer DATA ] [ -o, --old-archive, --portability ] [ -O,
--to-stdout ] [ -p, --same-permissions, --preserve-permissions ] [ -P, --absolute-names ] [
--preserve
] [ -R, --record-number ] [ --remove-files ] [ -s, --same-order, --preserve-order ] [ --same-owner ] [ --numeric-owner ] [ -S, --sparse ] [ -T, --files-from F ]
[ --null
] [ --totals
] [ -v, --verbose ] [ -V, --label NAZWA ] [ --version ] [ -w,
--interactive, --confirmation ] [ -W, --verify
] [ --exclude PLIK ] [ -X, --exclude-from
PLIK ] [ -Z, --compress, --uncompress ] [ -z, --gzip, --ungzip
] [ --use-compress-program PROG ] [ --block-compress ] [ --rsh-command POLECENIE ] [ -[0-7][lmh]
]
3
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
funkcja getopt()
• Istnieją trzy warianty tej funkcji
– getopt()
– getopt_long()
– getopt_long_only()
• W powłoce bash istnieje bardzo podobne w działaniu
polecenie getopt
• Pozwala na bardzo łatwą obsługę podawanych opcji.
Akceptuje różne warianty, przykładowo:
•
•
•
•
-t kolor –w /tmp/plik.out –k -b
-kb –-tryb=kolor -w
-k –b –t kolor –-wynik=/tmp/plik.out
--tryb=cz_b --kompresja --blokowo
• i inne kombinacje
• opcje, które nie mają dalszych argumentów
mogą być grupowane za jednym myślnikiem
• po każdej opcji jako oddzielny argument
może pojawić się wartość dla tej opcji
4
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
2
funkcja getopt(), c.d.
• Rezultatem zwracanym przez getopt jest następny znak opcji
znaleziony w argv (jeżeli jakiś tam jest). Funkcję getopt
wywołujemy rekurencyjnie. Działa ona następująco:
– jeżeli opcja dopuszcza jakąś wartość, to ta wartość jest
wskazywana przez zewnętrzna zmienną optarg
– getopt zwraca -1, gdy nie ma już więcej opcji do przetworzenia
– zwraca ?, gdy napotka nierozpoznawalną opcję, którą zapisze w
zewnętrznej zmiennej optopt
– jeżeli jakaś opcja wymaga podania wartości, a nie zostanie ona
podana, getopt zwraca : (dwukropek)
– zewnętrzna zmienna optind jest przyrównywana do indeksu
następnego argumentu, który ma być przetwarzany. getopt
wykorzystuje go do zapamiętania, jak daleko doszła
#include <unistd.h>
int getopt(int argc, char *const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
5
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
funkcja getopt(), c.d.
#include <stdio.h>
#include <unistd.h>
int main (int argc, char *argv[]) {
int opt;
while ((opt = getopt (argc, argv, "if:lr")) != -1) {
switch(opt) {
case 'i':
case 'l':
case 'r':
printf("option: %c\n", opt);
break;
case 'f':
printf("filename: %s\n", optarg);
break;
case ':':
printf("option needs a value\n");
break;
case '?':
printf("unknown option: %c\n", optopt);
break;
}
}
for(; optind < argc; optind++)
printf("argument: %s\n", argv[optind]);
exit(0);
}
• rozpoznawane opcje
to: i, f, l, r.
• po opcji f wymagany
jest argument
• argumenty pozostałych
opcji są niewymagane
koniec przetwarzania
argument po opcji
zapisywana jest tutaj
zwraca :, gdy nie podano
wymaganego argumentu
zwraca ?, gdy napotkano
nieznaną opcję
nieznana opcja
zapisywana jest tutaj
getopt ponownie
zapisuje tablicę argv. Tu
znajdą się wszystkie
argumenty nie będące
opcjami
6
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
3
funkcja getopt(), c.d.
• Przykłady działania
$ ./argopt -i -f -l -r
option: i
filename: -l
option: r
$ ./argopt -i -f plik -l -r
option: i
filename: plik
option: l
option: r
$ ./argopt -ilf -f plik
option: i
option: l
filename: r
argument: plik
$ ./argopt -a
./argopt: invalid option -- a
unknown option: a
$ ./argopt -i xxx -l yyy -r zzz -f plik
option: i
option: l
option: r
filename: plik
argument: xxx
argument: yyy
argument: zzz
$ ./argopt -il -f plik
option: i
option: l
filename: plik
$ ./argopt --i
./argopt: invalid option -- unknown option: option: i
Aby uniknąć tego „niechcianego”
komunikatu należy dodać dwukropek
na początku opcji, tj. :if:lr
7
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
funkcja getopt(), c.d.
• Przykłady użycia z poziomu powłoki bash
#!/bin/sh
echo "Before getopt"
for i do
echo $i
done
set -- `getopt abc:d $*`
echo "After getopt"
for i do
echo "-->$i"
done
for i do
case "$i" in
-a|-b) shift; echo "flag a or b set";;
-c) shift; echo "flag c set to $1";shift;;
-d) shift; echo "flag d set";;
esac
done
$ ./test.sh -abc plik -d -e
Before getopt
-abc
plik
-d
getopt: invalid option -- e
After getopt
-->-a
-->-b
Aby uniknąć tego
-->-c
„niechcianego” komunikatu
-->plik
należy dodać dwukropek
-->-d
na początku opcji, tj.
-->-:abc:d
flag a or b set
flag a or b set
flag c set to plik
flag d set
przykład opracowany na podstawie
podręcznika man getopt
8
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
4
funkcja getopt(), c.d.
• Parę uwag na temat polecenia shift
#!/bin/sh
while [ "$1"
echo \$1:
echo \$*:
echo \$#:
echo ""
shift
done
!= "" ]; do
"$1"
"$*"
"$#"
Polecenie shift przesuwa wszystkie zmienne
parametryczne w dół o jedna pozycję, tak więc
$2 staje się $1, $3 staje się $2 itd. Poprzednia
wartość $1 jest kasowana, natomiast $0
pozostaje niezmieniona
Polecenie to jest często używane do
przeszukiwania parametrów.
przykład własny
$ ./_shift one two three
$1: one
$*: one two three
$#: 3
$1:
$*:
$#:
two
two three
2
$1:
$*:
$#:
three
three
1
9
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Wywołania systemowe
5
Wywołania systemowe – uwagi wstępne
• Każdy kod (program) w Linuxie działa w jednym z dwóch
trybów: trybie użytkownika lub trybie jądra. Tryb jądra używamy
pisząc takie programy jak np. jądro, sterowniki urządzeń.
• Programy w trybie użytkownika podlegają wielu ograniczeniom,
aby nie mogły uszkodzić samego systemu. Ogólnie: pamięć i
zasoby zaalokowane dla programu A nie mogą być użyte w
programie B.
• Tryb jądra daje pełen i nieskrępowany dostęp do całego
systemu. Może więc wszystko popsuć! Np. pisząc sterownik
urządzenia musimy mieć pełen dostęp do sprzętu, czyli np. do
jego BIOS-u i … o wypadek nietrudno ☺
11
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Wywołania systemowe – uwagi wstępne, c.d.
• Czyli: zadaniem jądra jest dostarczenie aplikacjom różnych
usług przy jednoczesnym zapewnieniu integralności i
bezpieczeństwa systemu. Innymi słowy: kod aplikacji w trybie
użytkownika żąda różnych usług od jądra. Robi to poprzez
wywołania systemowe, które w bezpieczny dla systemu
sposób mogą uzyskać dostęp do chronionych zasobów.
• Wywołania systemowe są tak zaprojektowane, że wyglądają
jak standardowe funkcje C. Moża powiedzieć, że „prawdziwe”
wywołania systemowe są „opakowane” w wygodny interfejs,
jaki daje język C.
12
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
6
Wywołania systemowe – uwagi wstępne, c.d.
• Pewne ograniczenie w.s.: wszystkie dane, jakie przekazujemy
do jądra za pośrednictwem wywołań systemowych są
przekazywane przez adres. W praktyce oznacza to, że przy
wywoływaniu funkcji systemowych musimy używać
wskaźników do struktur a nie samych struktur.
• Do czego więc używać wywołań systemowych? Gdy
potrzebujemy usług, których kod użytkownika (np. w języku C)
nie jest w stanie sam dostarczyć.
• Ile jest usług systemowych? W najnowszej wersji jądra Linuxa
ponad 200. Dokładna lista patrz: /usr/include/asm/unistd.h
13
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Wywołania systemowe – uwagi wstępne, c.d.
• Wszystkie usługi systemowe można podzielić na:
– zarządzanie procesami (np. fork, exec, setgid, setuid)
– obsługa sygnałów (np. sigaction, sigsuspend, sigreturn)
– obsługa plików i katalogów (np. mkdir, chdir, read, write,
open, close)
– zarządzanie pamięcią (np. mmap, mlock, munlock)
– usługi sieciowe (np. sethostname, gethostname)
• Bardzo często korzystamy z wywołań systemowych nie zdając
sobie z tego sprawy. Np. printf korzysta z write a malloc z
brk, sbrk. Można więc np. napisać własną wersję malloc z
obsługą tzw. garbage collection.
14
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
7
Wywołania systemowe – uwagi wstępne, c.d.
• Jak używa się wywoływania systemowe?
– praktycznie tak samo jak zwykłe funkcje
– aby ich użyć trzeba włączyć plik nagłówkowy <unistd.h>
– szczegółowa dokumentacja w man
• sekcja 2: zachowanie, parametry, zwracane wartości
• sekcja 3: wywołania systemowe mają odpowiadające im
funkcje biblioteczne o podobnej nazwie, więc i tu warto
zaglądać
15
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Kilka przykładów z tabeli błędów
• Tabela podaje możliwe błędy zwracane przez wywołania
systemowe
• Pełna dokumentacja w man
• Kody błędów zdefiniowane przez POSIX (Linux dobrze go
wspiera) są udokumentowane w sekcji 3 podręcznika errno
(man 3 errno)
• Przykłady
– ENOENT – proces próbuje skorzystać z nieistniejącego pliku lub
katalogu
– ESRCH – nie istnieje taki proces
– E2BIG – lista argumentów dla exec zbyt długa
– REOFS – próba zapisu do systemy plików tylko do odczytu
– EIO – pojawił się błąd wej/wyj
– EACCESS – odmowa dostępu do pliku lub innego zasobu
16
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
8
Kody zwracane przez wywołania systemowe
• 0 – gdy sukces, liczba ujemna (zwykle -1) gdy pojawi się błąd
• Przykłady (oba są równoważne, pierwszy chyba częściej
spotykany)
// Porównanie zwróconego kodu do 0
Otwarcie pliku do odczytu.
if (open ("plik", O_RDONLY)) {
/* kod obsługi błędu */
}
else {
/* otwarcie pliku zakończone sukcesem */
}
Systemowa obsługa plików i
katalogów będzie dokładnie
omówiona później.
// Sprawdzamy wprost, czy open zwróciło wartość ujemną
if (open ("plik", O_RDONLY) < 0) {
/* kod obsługi błędu */
}
else {
/* otwarcie pliku zakończone sukcesem */
}
przykłady z [2]
17
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Obsługa błędów
• Istnieją dwa sposoby sprawdzenia, czy wystąpił błąd i obsługi
błędów. Pierwszy pokazano na poprzednim slajdzie. Drugi
sposób to użycie globalnej zmiennej errno (<errno.h>).
Wywołania systemowe oraz różne funkcje biblioteczne
ustawiają errno, gdy pojawi się błąd.
• Istnieją dwa sposoby ustawienia tej zmiennej:
– wywołanie funkcji void perror (const char *s), która
wyświetla łańcuch s, po którym pojawia się znak dwukropka oraz
związany z errno komunikat (<stdio.h>)
– użycie funkcji char *strerror (int errnum) (<string.h>),
która zwraca łańcuch opisujący kod błędu errnum
18
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
9
Obsługa błędów
• perror
...
if ((pfile = fopen ("plik", "r")) == NULL) {
perror ("fopen");
exit (EXIT_FAILURE);
}
else {
frpintf (stdout, "OK.");
fclose (pfile);
}
...
exit (EXIT_SUCCESS)
...
przykłady z [2]
// fopen: No such file or directory
• strerror
...
if ((pfile = fopen ("plik", "r")) == NULL) {
fprintf (stderr, "fopen: %s", strerror (errno));
exit (EXIT_FAILURE);
}
else {
frpintf (stdout, "OK.");
fclose (pfile);
}
...
exit (EXIT_SUCCESS)
...
// fopen: No such file or directory
19
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Zmienne środowiskowe
• Zwykle każdy system definiuje ich dość dużo
Najpopularniejsze zmienne to np. HOME, PATH, PS1, LC_ALL
oraz inne
• Zmienna środowiskowa ma postać nazwa=wartosc
• Zmienna środowiskowa zachowuje się trochę jak zmienna
globalna i może czasem zmieniać działanie programu oraz
utrudniać jego debugowanie !
• Programowo dostęp do zmiennych środowiskowych odbywa
się za pomocą funkcji getenv oraz setenv
• getenv: 3 przypadki
– zmienna nie istnieje (funkcja zwraca null)
– zmienna istnieje ale nie ma wartości (zwracany jest ciąg,
którego pierwszym bajtem jest null)
– zmienna istnieje i ma przypisaną wartość (zwraca wskaźnik na
pierwszy znak ciągu)
20
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
10
Zmienne środowiskowe, c.d.
• putenv
– pobiera ciąg o postaci nazwa=wartość i dodaje go do bieżącej
sesji
– gdy błąd, to zwraca -1
– zwróci ENOMEM, gdy zmienna nie będzie mogła być ustawiona z
powodu braku pamięci
• W systemie najwygodniej zmienne ustawiać w tzw. login
Zwykle dostępny tylko dla root-a.
skryptach
– ogólnodostępny: /etc/profile (odczytywany jako pierwszy)
– „osobiste startowe”: ~/.bash_profile, ~/.bash_login,
~/.profile (szuka w tej właśnie kolejności i wykonuje pierwszy,
który się da odczytać)
Kropka na początku nazwy:
plik ukryty.
– „osobiste kończące”: ~/.bash_logout
– --noprofile (zakazujemy odczytywać skrypty)
– szczegóły man bash (lub inna uzywana powłoka, np. sh)
• Zmienne mają zasięg ograniczony tylko do bieżącej sesji
21
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Zmienne środowiskowe, c.d.
• Przykład 1
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
...
int main (int argc, char *argv[]) {
char *var, *value;
}
var = argv[1];
value = getenv (var);
if (value)
printf ("%s %s\n", var, value);
else
printf ("%s jest NULL\n", var);
// Tworzymy string w postaci: name=value
// i wołamy putenv.
if (argc == 3) {
char *string;
value = argv[2];
}
strcpy (string, var);
strcat (string, "=");
strcat (string, value);
if(putenv(string) != 0) {
fprintf(stderr,"putenv failed\n");
free(string);
exit(1);
}
// Sprawdzamy, czy zmienna została ustawiona
value = getenv (var);
if (value)
printf ("%s %s\n", var, value);
else
printf("%s jest NULL?\n", var);
}
exit(0);
}
...
22
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
11
Zmienne środowiskowe, c.d.
• Przykład 2
– program przechodzi przez zmienną environ (tablica łańcuchów)
i drukuje jej zawartość, czyli wartości wszystkich zdefiniowanych
w danej sesji zmiennych środowiskowych
Tablica ciągów w postaci
nazwa=wartość jest bezpośrednio
dostępna dla programisty za
pośrednictwem zmiennej environ
zadeklarowanej jako:
#include <stdlib.h>
#include <stdio.h>
extern char **environ;
#include <stdlib.h>
extern char **environ;
int main() {
char **env = environ;
while (*env) {
printf ("%s\n",*env);
env++;
}
exit(0);
}
23
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Data i godzina
• Wszystkie systemy UNIX-owe przyjmują za „początek epoki”
datę 01-01-1970 i podają ile sekund upłynęło od tego
momentu
– czas jest zdefiniowany za pomocą predefiniowanego typu
time_t (typu long)
– pytanie: kiedy pojemność licznika sekund się skończy?
– funkcja systemowa time zwraca „niskopoziomową” wartość
Funkcja zwraca liczbę sekund od początku epoki oraz zwracaną
czasu
wartość zapisuje dodatkowo w zmiennej wskazywanej przez
tloc, jeśli nie jest ona wskaźnikiem pustym.
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
time_t time (time_t *tloc)
Funkcję time
int main() {
wywołujemy ze
int i;
wskaźnikiem pustym
time_t the_time;
jako argumentem.
for(i = 1; i <= 10; i++) {
the_time = time ((time_t *) 0);
printf("The time is %ld\n", the_time);
sleep(2);
}
exit(0);
}
LONG_MAX 2147483647
1 dzień = 60 * 60 * 24 = 86400 sek.
1 rok = 86400 * 365 = 31.536.000 sek.
2147483647 / 31536000 = 68,096 lat
czyli gdzieś na początku roku 2038 będą problemy 24
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
12
Data i godzina, c.d.
• Za pomocą funkcji gmtime można otrzymać bardziej czytelną
dla człowieka (oddzielnie minuty, sekundy, data itd.)
Universal Coordinated Time (Greenwich Mean Time)
#include <time.h>
srtuct tm *gmtime (const time_t *tloc)
#include <time.h>
#include <stdio.h>
int main() {
struct tm *tm_ptr;
time_t the_time;
(void) time (&the_time);
tm_ptr = gmtime (&the_time);
struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
/*
/*
/*
/*
/*
/*
/*
/*
/*
Seconds. [0-60]
Minutes. [0-59]
Hours. [0-23]
Day.
[1-31]
Month. [0-11]
Year - 1900.
Day of week. [0-6]
Days in year.[0-365]
DST.
[-1/0/1]
$ ./gmtime; date
Raw time is 1173286054
gmtime gives:
date: 107/03/07
time: 16:47:34
śro mar 7 17:47:34 CET 2007
*/
*/
*/
*/
*/
*/
*/
*/
*/
Czy wiesz, dlaczego rok
wydrukował się „z błędem”?
Czy wiesz dlaczego godziny
są rożne?
printf ("Raw time is %ld\n", the_time);
printf ("gmtime gives:\n");
printf ("date: %02d/%02d/%02d\n", tm_ptr->tm_year, tm_ptr->tm_mon+1, tm_ptr->tm_mday);
printf ("time: %02d:%02d:%02d\n", tm_ptr->tm_hour, tm_ptr->tm_min,
Funkcję time tm_ptr->tm_sec);
wywołujemy ze
exit (0);
wskaźnikiem pustym jako argumentem.
}
25
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Data i godzina, c.d.
• gmtime zwraca zawsze czas w GMT a czas zimowy w Polsce
jest przesunięty w zimie o +1 godzinę
• UTC oraz GMT
– Czas uniwersalny (ang. universal time, UT, Greenwich Mean Time, GMT) –
czas słoneczny średni na południku zerowym za który przyjęto południk
przechodzący przez obserwatorium astronomiczne w miejscowości Greenwich w
Wielkiej Brytanii. Jest czasem strefowym pierwszej strefy czasowej, od którego
liczy się czas pozostałych stref. Czas uniwersalny został zaproponowany przez
kanadyjskiego wynalazcę Sandforda Fleminga (źródło: Wikipedia)
– Uniwersalny czas koordynowany, UTC (ang. Coordinated Universal Time) wzorcowy czas uwzględniający nieregularność ruchu obrotowego Ziemi i
koordynowany względem czasu słonecznego. By zapewnić, że Słońce średnio w
ciągu roku przechodzi nad południkiem Greenwich o godz. 12:00 UTC, z
dokładnością nie mniejszą niż 0.9 s, od czasu do czasu do UTC dodawana jest
tzw. przestępna sekunda. Operację tę przeprowadza IERS (ang. International
Earth Rotation Service) (źródło: Wikipedia)
– gdy różnica około 0.9 sekundy jest dla nas nieistotna, to UTC jest tym samym co
GMT
– sposób zapisu daty i czasu podaje norma ISO 8601:2004
– aby poznać lokalny czas należy użyć funkcji localtime (działa identycznie jak
gmtime)
26
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
13
Informacja u użytkowniku
• Każdy użytkownik ma niepowtarzalny identyfikator (UID) oraz
należy do przynajmniej jednej grupy (GID)
• Każdy uruchomiony program działa w imieniu jakiegoś
użytkownika
• Za pomocą polecenia su można „stać” się innym
użytkownikiem
$ id -u
1000
$ users
artur
$
$ su - root
Password:
Użycie: su [OPCJE] [-] [username [ARGUMENTY]]
uczyń to powłoką logowania
-c, --command=<polecenie>
przekaż polecenie do wywołanej powłoki używając jej
opcji -c
-m, -p, --preserve-environment
nie resetuj zmiennych środowiskowych i użyj tej
samej powłoki
-s, --shell=<powłoka>
użyj powłoki zamiast domyślnej z /etc/passwd
$
$ id -u
0
$ users
artur
• Informacje o użytkowniku zapisane są w plikach /etc/passwd
oraz /etc/shadow (jest to rodzaj bazy danych)
27
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Informacja u użytkowniku, c.d.
• Pliki z danymi o użytkownikach
Szczegóły budowy patrz:
man 5 passwd (shadow)
/etc/passwd
lab999:x:1655:100:lab999:/home/lab/lab999:/bin/bash
/etc/shadow
lab999:$1$MYm8jjg0$4ccdXaykf45.SqRPu0nQ9/:13427:0:99999:7:::
• Dostęp do danych na temat użytkowników (odczyt)
zapewniają funkcje getuid, geteuid, getgid, getegid
– getuid zwraca rzeczywisty ID użytkownika dla aktualnego
procesu
– geteuid zwraca efektywny ID użytkownika dla aktualnego
procesu
– getgid zwraca rzeczywisty ID grupy bieżącego procesu
– getegid zwraca efektywny ID grupy bieżącego procesu
– rzeczywisty ID odpowiada ID dla procesu wywołującego
Efektywny ID odpowiada bitowi set UID dla uruchomionego
pliku
28
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
14
Informacja u użytkowniku, c.d.
• Dostęp do danych na temat użytkowników (ustawianie)
zapewniają funkcje setuid, seteuid, setgid,
setegid
– funkcje set* może wywoływać tylko użytkownik
uprzywilejowany (root)
– seteuid ustawia rzeczywisty ID użytkownika dla
aktualnego procesu
– seteuid ustawia efektywny ID użytkownika dla aktualnego
procesu
– setgid ustawia rzeczywisty ID grupy bieżącego procesu
– setegid ustawia efektywny ID grupy bieżącego procesu
29
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Informacja u użytkowniku. c.d.
• Przykład
#include <sys/types.h> #include <pwd.h> #include <stdio.h> #include <unistd.h>
int main () {
uid_t uid;
gid_t gid;
struct passwd *pw;
uid = getuid ();
gid = getgid ();
printf ("User is %s\n", getlogin ());
printf ("User IDs: uid=%d, gid=%d\n", uid, gid);
#include <unistd.h>
#include <sys/types.h>
uid_t getuid(void);
char *getlogin(void);
pw = getpwuid (uid);
printf ("UID passwd entry:\n name=%s, uid=%d, gid=%d, home=%s, shell=%s\n",
pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_dir, pw->pw_shell);
pw = getpwnam ("root");
printf ("root passwd entry:\n");
printf ("name=%s, uid=%d, gid=%d, home=%s, shell=%s\n",
pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_dir, pw->pw_shell);
exit(0);
}
User is artur
User IDs: uid=1000, gid=50
UID passwd entry:
name=artur, uid=1000, gid=50, home=/home/users/artur, shell=/bin/bash
root passwd entry:
name=root, uid=0, gid=0, home=/root, shell=/bin/bash
30
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
15
Informacje o komputerze
• Polecenia uname, gethostip
• wywołania systemowe uname, gethostname
$ uname -a
Linux mykonos 2.4.18-bf2.4 #1 Son Apr 14 09:53:28 CEST 2002 i686 GNU/Linux
$ gethostip mykonos
mykonos.iie.uz.zgora.pl 192.168.21.130 C0A81582
#include <sys/utsname.h>
int uname (struct utsname *buf);
struct utsname {
char sysname[];
char nodename[];
char release[];
char version[];
char machine[];
#ifdef _GNU_SOURCE
char domainname[];
#endif
};
#include <unistd.h>
int gethostname(char *name, size_t len);
Zapisuje nazwę sieciową
komputera w zmiennej name.
Zakłada się, że ciąg ten ma
co najmniej długość len. 0 –
sukces, -1 – w przeciwnym
wypadku.
uname zapisuje dane o
komputerze w strukturze
wskazywanej przez buf.
31
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Informacje o komputerze, c.d.
• Przykład
#include <sys/utsname.h>
#include <unistd.h>
#include <stdio.h>
int main() {
char computer[256];
struct utsname uts;
if (gethostname (computer, 255) != 0 || uname (&uts) < 0) {
fprintf (stderr, "Could not get host information\n");
exit(1);
}
printf ("Computer host name is %s\n", computer);
printf ("System is %s on %s hardware\n", uts.sysname, uts.machine);
printf ("Nodename is %s\n", uts.nodename);
printf ("Version is %s, %s\n", uts.release, uts.version);
exit(0);
}
$ ./gethost
Computer host name is mykonos
System is Linux on i686 hardware
Nodename is mykonos
Version is 2.4.18-bf2.4, #1 Son Apr 14 09:53:28 CEST 2002
32
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
16
Rejestr systemowy
Rejestr systemowy
•
Wiele programów potrafi zapisywać dane do logów systemowych
(zwykle w katalogu /var/log)
– typowe nazwy plików to messages, syslog, auth, cron, kern
– pliki logów są zwykle rotowane (auth.log, auth.log.0, auth.1.gz
itd.)
• parametry rotowania są w pliku /etc/logrotate.conf
• typowe okresy to: codziennie, co tydzień, raz w miesiącu
– obsługą logów zajmują się specjalne programy rejestrujące (ang.
system logger), są to klogd oraz syslogd
• pierwszy rejestruje tylko komunikaty jądra i (w typowych konfiguracjach)
przesyła je do drugiego, który oprócz tego rejestruje inne istotne komunikaty
• pracują jako demony (programy działające nieprzerwanie i reagujące na
określone zdarzenia)
– konfiguracja zwykle w pliku /etc/syslog.conf
• przykładowy wpis: kern.* /var/log/kern.log
– logi wysyłane są do programu rejestrującego za pomocą funkcji
systemowej syslog
• na poziomie poleceń powłoki pisanie do logów zapewnia polecenie logger
– istnieje możliwość wysyłania logów w trybie on-line na inna maszynę
• np. wpis: *.* @willow.iie.uz.zgora.pl każe wszystkie logi wysyłać
na wskazany serwer
• wskazany serwer musi oczywiście zgodzić się na przyjmowanie obcych
logów
34
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
17
Rejestr systemowy, c.d.
• Każdy komunikat zawiera przynajmniej datę i czas
zarejestrowania, nazwę serwera oraz treść
–
Mar 11 12:31:16 mykonos sshd[17142]: (pam_unix) session closed for user lab303
• Każdy komunikat wysłany za pomocą syslog posiada
„sygnaturę” określającą poziom ważności oraz podsystem
– podawane jako para: podsystem.poziom (ang. facility.priority)
• podsystem: podaje jaki rodzaj programu wysyła komunikat.
Aktualnie obsługiwane są następujące podsystemy: auth authpriv
cron daemon ftp kern lpr mail mark news syslog user uucp
local0 local1 local2 local3 local4 local5 local6 local7
• poziom ważności: określa ważność komunikatu. Aktualnie
obsługiwane są następujące wartości (podano w kolejności od
najbardziej do najmniej ważnego): emerg alert crit err
warning notice info debug
35
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Rejestr systemowy, c.d.
• Przykład użycia – polecenie logger
$ logger -p auth.emerg -t "Artur" "Komunikat testowy AG"
$
Message from syslogd@mykonos at Mon Mar 12 19:29:04 2007 ...
mykonos Artur: Komunikat testowy AG
$ tail -1 /var/log/auth.log
Mar 12 19:29:04 mykonos Artur: Komunikat testowy AG
Komunikat pojawia się
również na konsoli.
$ logger -p local7.info -t "Artur" "Komunikat testowy AG"
$ tail -1 /var/log/messages
Mar 12 19:31:24 mykonos Artur: Komunikat testowy AG
Ten komunikat nie pojawia się
na konsoli.
#!/bin/sh
PROG=`basename "$0"`
FACILITIES='
auth authpriv cron daemon ftp kern lpr mail mark news syslog
user uucp local0 local1 local2 local3 local4 local5 local6 local7'
PRIORITIES='
emerg alert crit err warning notice info debug'
Wszystkie możliwe
kombinacje priorytetów i
poziomów ważności.
for f in $FACILITIES; do
for p in $PRIORITIES; do
logger -p $f.$p "$PROG[$$]: testowanie $f.$p"
done
done
Skrypt może służyć do
testowania poprawnej pracy
rejestratora systemowego.
36
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
18
Rejestr systemowy, c.d.
• Przykład użycia – funkcja systemowa syslog
– openlog służy do zmiany sposobu prezentowania komunikatów.
• ident: ciąg, który będzie dodawany na początku naszych komunikatów (może
to być np. nazwa programu)
• option: flagi, które sterują zachowaniem się funkcji. Np. LOG_PID powoduje,
że w logach będzie umieszczany identyfikator procesu, który spowodował
wysłanie logu
• facility: podaje domyślną wartość dla podsystemu (ang. facility)
• użycie tej funkcji jest opcjonalne. Gdy nie użyjemy jawnie, to syslog zrobi to
za nas
– closelog: zamyka deskryptor pliku logów. Użycie opcjonalne
– syslog: generuje logi systemowe, które są „przechwytywane” przez
demona syslogd. Parametr priority tworzony jest jako połączenie za
pomocą operatora OR wartości dla poziomu ważności oraz podsystemu
#include <syslog.h>
void openlog (const char *ident, int option, int facility);
void syslog (int priority, const char *format, ...);
void closelog (void);
37
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Rejestr systemowy, c.d.
• Przykład użycia – funkcja systemowa syslog
#include <syslog.h>
#include <stdio.h>
int main() {
FILE *f;
f = fopen ("not_here", "r");
if (!f)
syslog (LOG_ERR | LOG_USER, "oops - %m\n");
exit(0);
}
Poziom ważności (ang. priority)
Podsystem (ang. facility)
%m – wstawia ciąg komunikatu błędu
związany z bieżącą wartością zmiennej
błędu errno (patrz poprzednie slajdy)
U nas: No such file or directory
$ ./syslog
$
$ tail -1 /var/log/syslog
Mar 12 21:10:11 mykonos mysyslog: oops - No such file or directory
$
Logi zapisywane są w tym pliku.
Decyduje o tym odpowiedni wpis w
pliku /etc/syslog.conf.
38
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
19
Rejestr systemowy, c.d.
• Przykład użycia – funkcja systemowa syslog
Ciąg, który będzie dodawany na początku
naszych komunikatów.
#include <syslog.h>
#include <stdio.h>
#include <unistd.h>
int main() {
int logmask;
Będzie też umieszczany identyfikator procesu.
Gdy komunikat nie może zostać zarejestrowany,
to jest wysyłany na konsolę.
Domyślna wartość podsystemu użytkownika.
openlog ("logmask", LOG_PID | LOG_CONS, LOG_USER);
syslog (LOG_INFO, "informative message, pid = %d", getpid());
syslog (LOG_DEBUG, "debug message, should appear");
syslog (LOG_CRIT | LOG_AUTH, "Critilal cond. while auth.");
logmask = setlogmask (LOG_UPTO (LOG_NOTICE));
// logmask = setlogmask (LOG_MASK (LOG_NOTICE));
syslog (LOG_DEBUG,"debug message, should not appear");
exit(0); }
Komunikaty o poziomie
ważności mniejszym lub
równym niż wskazany nie są
wysyłane do logów.
Kolejność jest taka: emerg
alert crit err warning
notice info debug
LOG_MASK – jak wyżej, ale
Ten komunikat już nie zostanie zarejestrowany.
tylko jeden wybrany poziom.
$ tail -1 /var/log/messages
Mar 12 21:29:00 mykonos logmask[32528]: informative message, pid = 32528
$ tail -1 /var/log/debug
Mar 12 21:29:00 mykonos logmask[32528]: debug message, should appear
$ tail -1 /var/log/auth.log
Mar 12 21:52:09 mykonos logmask[731]: Critilal cond. while auth.
39
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Rejestr systemowy, c.d.
• Wyciąg z dokumentacji man syslog (kody podsystemów)
security/authorization messages (private)
LOG_CRON
clock daemon (cron and at)
LOG_DAEMON
system daemons without separate facility value
LOG_FTP
ftp daemon
LOG_KERN
kernel messages
LOG_LOCAL0 through LOG_LOCAL7
reserved for local use
LOG_LPR
line printer subsystem
LOG_MAIL
mail subsystem
LOG_NEWS
USENET news subsystem
LOG_SYSLOG
messages generated internally by syslogd
LOG_USER (default)
generic user-level messages
LOG_UUCP
UUCP subsystem
LOG_AUTHPRIV
void openlog (const char *ident, int option, int facility);
void syslog (int priority, const char *format, ...);
void closelog (void);
40
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
20
Rejestr systemowy, c.d.
• Wyciąg z dokumentacji man syslog (kody poziomów
ważności, podano w kolejności zmniejszającej się ważności)
LOG_EMERG
LOG_ALERT
LOG_CRIT
LOG_ERR
LOG_WARNING
LOG_NOTICE
LOG_INFO
LOG_DEBUG
system is unusable
action must be taken immediately
critical conditions
error conditions
warning conditions
normal, but significant, condition
informational message
debug-level message
void openlog (const char *ident, int option, int facility);
void syslog (int priority, const char *format, ...);
void closelog (void);
41
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
Rejestr systemowy, c.d.
• Wyciąg z dokumentacji man openlog (kody opcji)
The option argument to openlog() is an OR of any of these:
LOG_CONS
LOG_NDELAY
LOG_NOWAIT
LOG_ODELAY
LOG_PERROR
LOG_PID
Write directly to system console if there is an error while
sending to system logger
Open the connection immediately (normally, the connection is
opened when the first message is logged)
Don't wait for child processes that may have been created
while logging the message. (The GNU C library does not
create a child process, so this option has no effect on Linux.)
The converse of LOG_NDELAY; opening of the connection
is delayed until syslog() is called. (This is the default, and
need not be specified)
Print to stderr as well
Include PID with each message
void openlog (const char *ident, int option, int facility);
void syslog (int priority, const char *format, ...);
void closelog (void);
42
dr inż. Artur Gramacki, Instytut Informatyki i Elektroniki, UZ (wersja: 0.99)
21