node36






WYWOŁANIE SYSTEMOWE: msgctl()






















Next: msgtool: Interaktywny manipulator kolejką
Up: Kolejki wiadomości
Previous: WYWOŁANIE SYSTEMOWE: msgsnd()
  Contents





WYWOŁANIE SYSTEMOWE: msgctl()



Podczas tworzenia tych przykładowych funkcji poznałeś proste i eleganckie podejście
do tworzenia i używania kolejek wiadomości. Teraz przedyskutujemy bezpośrednią
manipulację wewnętrznych struktur związanych z daną kolejką.


Aby kontrolować kolejkę używamy wywołania systemowego msgctl().



WYWOŁANIE SYSTEMOWE: msgctl();
PROTOTYP: int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
ZWRACA: 0 - sukces
-1 - błąd: errno = EACCES ( odczyt niedozwolony a cmd jest usawione na IPC_STAT )
EFAULT ( adres wskazywany przez buf jest nieprawidłowy dla
komend IPC_SET i IPC_STAT )
EIDRM ( kolejka została usunięta podczas odczytu (retrieve) )
EINVAL ( nieprawidłowe msgqid lub msgsz ujemne )
EPERM ( komendy IPC_SET lub IPC_RMID zostały wybrane, lecz
proces nie może zapisywać lub nie ma dostępu
do kolejki )
UWAGI:


Logika podpowiada ci, iż bezpośrednia manipulacja wewnętrznych struktur jądra
może prowadzić do nocnych igraszek. Niestety, odpowiedzialność spoczywająca na
programiście może zostać zaklasyfikowana jako zabawa pod warunkiem, że lubisz
zaśmiecać podsystem IPC. Wywołując msgctl() z odpowiednio dobranymi poleceniami
możesz manipulować jednostki, które zbyt łatwo nie doprowadzą systemu do upadku.
Przyjżyjmy się tym komendom:



IPC_STAT



Odczytuje strukturę msqid_ds z kolejki i przechowuje ją pod
adresem wskazywanym przez argument buf.


IPC_SET



Ustawia wartość ipc_perm ( członka struktury msqid_ds ).
Wartość pobierana jest z argumentu buf.


IPC_RMID



Usuwa kolejkę z jądra.





Przypomnij sobie naszą dyskusję na temat struktury msqid_ds.
Jądro przechowuje kopię tej struktury dla każdej kolejki istniejącej w systemie.
Używając polecenia IPC_STAT możemy otrzymać kopię tej struktury.


Przyjżyjmy się funkcji odbierającej i kopiującej tę strukturę pod podany adres:



int get_queue_ds( int qid, struct msgqid_ds *qbuf )
{
if( msgctl( qid, IPC_STAT, qbuf) == -1)
{
return(-1);
}

return(0);
}


Jeżeli nie udało nam się skopiować wewnętrznego bufora zwracamy -1. Jeżeli wszystko
poszło dobrze zwracamy 0, a podany bufor powinien zawierać kopię wewnętrznej struktury
dla kolejki reprezentowanej przez podany identyfikator (qid).


Mamy już kopię wewnętrznej struktury dla kolejki, zdajmy sobie pytanie co możemy
zmienić? Jedynym elementem, który możemy zmienić jest struktura ipc_perm.
Zawiera ona prawa dostępu oraz informacje o twórcy i właścicielu kolejki.
Jednakże, możemy zmienić jedynie mode, uid i gid, czyli
id właściciela, id grupy, oraz prawa dostępu do kolejki.


Utwórzmy funkcję zmieniającą prawa dostępu do kolejki. Musimy je przekazać jako tablicę
znaków ( np.: ``660'').



int change_queue_mode( int qid, char *mode )
{
struct msqid_ds tmpbuf;

/* pobierz kopię wewnętrznej struktury */
get_queue_ds( qid, &tmpbuf);

/* zmień prawa dostępu używając starego triku */
sscanf(mode, "%ho", &tmpbuf.msg_perm.mode);

/* uaktualnij wewnętrzną strukturę */
if( msgctl( qid, IPC_SET, &tmpbuf) == -1)
{
return(-1);
}

return(0);
}


Pobieramy kopię struktury za pomocą wywołania naszej funckji get_queue_ds.
Następnie wywołujemy sscanf() aby zmienić mode w strukturze msg_perm.
Zmian dokonuje wywołanie msgctl() z poleceniem IPC_SET.


BĄDŻ OSTROŻNY! Istnieje możliwość zablokowania siebie zmieniając prawa dostępu
dla kolejki! Pamiętaj, że takie obiekty IPC nie znikają do czasu poprawbengo usunięcia
lub restartu systemu. Nawet jeżeli nie możesz zobaczyć kolejki za pomocą ipcs
nie oznacza to że jej tam nie ma.



Aby to zademonstrować przedstawię pewną zabawną anegdotę. Kiedy uczyłem
budowy wewnętrznej Unixa na Uniwersytecie Południowej Florydy wpadłem w pewną
zawstydzającą blokadę. Dzień wcześniej przed zajęciami połączyłem się z serwerem
laboratoryjnym w celu kompilacji
i przetestowania pracy laboratoryjnej na dany tydzień. Podczas testowania
zdałem sobie sprawę, iż zrobiłem literówkę w kodzie odpowiedzialnym za zmianę
praw dostępu
do kolejki. Jednakże gdy próbowałem zmienić prawa dostępu z "660" na "600" straciłem
prawa do własnej kolejki. Nie mogłem przetestować programu
w tym samym obszarze katalogu domowego, ponieważ użyłem ftok() do utworzenia
klucza IPC ( próbowałem użyć kolejki do której nie miałem prawa ). Zakończyło się
to na skontaktowaniu się z lokalnym administratorem rano przed zajęciami,
tłumaczeniu mu przez godzinę czym jest kolejka wiadomości i dlaczego potrzebuję
uruchomić ipcrm. grrrr.




Po pomyślnym odebraniu wiadomości zostaje ona usunięta z kolejki. Jednak, jak
wspomniałem wcześniej, obiekty IPC pozostają w systemie do czasu usunięcia lub
restartu. Zatem, nasza kolejka istnieje wewnątrz jądra, gotowa do użytku długo po
tym jak nasza wiadomość znikneła. Aby dokończyć cyklu życiowego kolejki powinniśmy
ją usunąć za pomocą msgctl(), podając jako polecenie IPC_RMID:



int remove_queue( int qid )
{
if( msgctl( qid, IPC_RMID, 0) == -1)
{
return(-1);
}

return(0);
}


Powyższa funkcja zwraca 0 po usunięciu kolejki, jeżeli się to nie udało zwracane jet -1.
Usuwanie kolejki jest z natury atomowe, zatem jakiekolwiek próby dostępu do kolejki
zakończoną się marnie.













Next: msgtool: Interaktywny manipulator kolejką
Up: Kolejki wiadomości
Previous: WYWOŁANIE SYSTEMOWE: msgsnd()
  Contents



2000-03-01








Wyszukiwarka

Podobne podstrony:
node36
node366
node36
node36 F4DCN3Q7W36PUMUTAORSAEFBJPX3X524GUM2G2Y
node36
node36 WZ7U3H32JFMC2MRTFAY562XESPPZOUSVG6QBP3I
node36 XZUDJDE4JCLBXKFUKO5JBFQWS2FBX3CYIQCG24A
node36

więcej podobnych podstron