Wywołania systemowe w systemie GNU/Linux
Na początku krótkie wyjaśnienie tego czym jest wywołanie systemowe w ogólnym tego słowa znaczeniu. Wywołanie systemowe (System Call) to funkcja używana przez proces w celu zażądania od systemu operacyjnego (a ściślej - jądra) określonej usługi. Wywołania systemowe są generowane przez przerwania w samym programie (procesie).
Nowoczesne procesory przetwarzają instrukcje w kilkudziesięciu trybach dostępu (różniących się poziomem bezpieczeństwa oraz np. czasem trwania). W systemie GNU/Linux, definiujemy tylko dwa tryby - Tryb Użytkownika oraz Tryb Nadzorcy. Poziomy dostępu zostały stworzone po to, aby system mógł w prosty i jasny sposób decydować o przyznaniu dostępu do zasobów dla procesu. Jądro systemu operacyjnego GNU/Linux uruchamiane jest zawsze w uprzywilejowanym trybie - z oczywistej przyczyny - musi przyznawać dostęp do warstwy sprzętowej dla aplikacji (warstwy programowej), zarządzać przerwaniami, zmieniać tryb dostępu procesora czy też zarządzać pamięcią (tutaj przychodzi ku pomocy sheduler, którego opisałem całkiem niedawno).
Jednak system (kernel) sam w sobie nie potrafi kontrolować mechanizmu zmiany trybu dostępu. Aby zapewnić obsługę sytuacji, w której mnie uprzywilejowany kod transferuje swoje dane (lub jakiekolwiek wygenerowane przez niego) do wyżej uprzywilejowanego kodu potrzebujemy małego "włamu" i przełamania zabezpieczeń. Oczywiście - nie dosłownie. Nie możemy dopuścić do hipotetycznej sytuacji, w które mniej uprzywilejowany proces stara się wymusić na procesie o wyższym priorytecie np. błąd stosu. Standardowo system operacyjny dostarczany jest z biblioteką obsługującą zdarzenia i pośredniczącą między jądrem a procesem. W GNU/Linux tą biblioteką jest libc (Biblioteka C). To ona zarządza i nadzoruje wszystkie niskopoziomowe przepływy informacji pomiędzy procesami i kernelem, a także dzięki niej odbywa się "magiczna zamiana" trybu pracy procesora (z mniej uprzywilejowanego na bardziej lub na odwrót).
Posiadamy więc bibliotekę, którą użytkownik może wywołać w swoim programie i skorzystać z jej funkcji, aby przekazać "coś" "gdzieś" (mówiąc kolokwialnie:)). Przyjrzyjmy się zatem troszkę bliżej libc a w szczególności tematem wywołań systemowych. Jako przykład zatem - kawałek kodu odpowiedzialny za ustawienie UID w GNU/Linuksie.
_syscall1(int,setuid,uid_t,uid); _setuid: subl $4,%exp pushl %ebx movzwl 12(%esp),%eax movl %eax,4(%esp) movl $23,%eax movl 4(%esp),%ebx int $0x80 movl %eax,%edx testl %edx,%edx jge L2 negl %edx movl %edx,_errno movl $-1,%eax popl %ebx addl $4,%esp ret L2: movl %edx,%eax popl %ebx addl $4,%esp ret
Jak widać - operujemy assemblerem. Każda funkcja posiada co najmniej 2 argumenty: numer wywołania systemowego i rodzaj (definicję) działania tegoż wywołania. Każda funkcja wywołania systemowego biblioteki libc zwalnia przerwanie 0x80. Z tego adresu możemy pobrać (np. strace'm) wszystkie wywołania systemowe dowolnego programu. Gdy przerwanie zwolni się (najczęściej po określonym w jądrze "tiku"(czasie)) kod wyjścia jest pobierany z pamięci i możliwy do odczytania przez inną funkcję, bądź też przez wymieniony strace. Argumenty przekazywane są w rejestrach w następującej kolejności: eax, ebx, ecx, edx, edi, esi, ebp. Numer funkcji systemowej jest przekazywany w eax.
Całą pracę za wywołania przejmuje system przerwań. Po wywołaniu funkcji system_call() "praca" rozpoczyna się w 'adresie wejścia', który jest zdefiniowany w arch/i386/kernel/entry. Niestety, rutyny te zapisane są w języku niezrozumiałym dla przeciętnego człowieka. Stąd też krótki algorytm, jako ilustracja tego co dzieje się w czasie wywołania systemowego:
zwraca typ system_call(sys_call_number, sys_call_arguments)
{
Zapisz rejestry procesu;
Sprawdź, czy sys_call_number reprezentuje prawdziwą wartość wywołania;
jeśli nie pokaż błąd
w innym wypadku
{
Sprawdź flagę PF_TRACESYS wybranego procesu;
Wywołaj planistę (jeśli potrzebny);
Przekaż sygnały;
Swolnij rejestry procesu;
}
}
I krótkie wyjaśnienie//opis opisanego algorytmu. Dwie zmienne są przekazywane do rutyny: Sys_call_number odwołuje się do wcześniej zdefiniowanej liczby identyfikującej wywołanie systemowe. Sys_call_arguments przekazuje kolejne argumenty dla wywołania (jeśli potrzebne). Zapisanie rejestrów jest potrzebne, gdyż bez tego wywołanie planisty w późniejszym czasie mogłoby skutkować SIGSEGV. Następnie - sprawdzenie czy numer wywołania jest prawidłowy. Flaga PF_TRACESYS pozwala stwierdzić, czy dany proces nie ma procesu-rodzica. Tutaj wchodzi do gry funkcja syscall_trace (oto jej kod źródłowy arch/i386/kernel/ptrace.c). Jeśli wykryje rodzica przesyła mu SIGTRAP, wcześniej ustawiając procesowi potomnemu flagę TASK_STOPPED. Tutaj wkracza nasz dzielny planista i robi co do niego należy - zajmuje się pamięcią obu procesów (bądź jednego, jeśli proces nie miał rodzica). Jeśli wysłaniu sygnału SIGTRAP i pracy planisty proces dostał//wysłał jakikolwiek sygnał zostaje on przetworzony w tym momencie, po czym przywracane są rejestry.
I na koniec przykład użycia. Oto kawałek strace dla /bin/true:
brk(0) = 0x804a308 brk(0x804b308) = 0x804b308 brk(0x804c000) = 0x804c000 _exit(0)
Przepiękny pogląd na funkcję brk(), która poprzez przerwanie (wywołanie systemowe) odwołała się do pamięci (adres 0x804a308). Program bez praw dostępu do pamięci (przynajmniej bezpośrednio - nie działający w trybie uprzywilejowanym) poprzez System Call odwołał się do jądra, aby ten dał mu mały fragment wolnej pamięci.
Celowo nie opisuję sposobu tworzenia własnych wywołań systemowych. Zainteresowani zajrzą zapewne do Google, a niezainteresowani w końcu skończą czytać ten nudny wpis :-).
I tą oto jogg-notką powracam do żywych :-) Witajcie już oficjalnie! Następny odcinek mam już praktycznie napisany - a w nim... DCOP - jedna z rzeczy za które kocham KDE! :-) Stay Tuned!
Debug pamięci w Linuksie (pamięć od strony technicznej)
Artykuł ten będzie traktował o debugingu pamięci operacyjnej w środowisku GNU/Linux. I w zasadzie nie jest przeznaczony dla ZU (choć starałem się opisać to w jak najprzystępniejszy sposób) :-), adresowany jest głównie do programistów oraz tzw. hackerów jądra - osób, które mają udział w procesie powstawania jądra systemu GNU/Linux. Na początek garść potrzebnej teorii.
Wszystkie programy korzystają z pamięci operacyjnej (nawet te, które pozornie nic nie robią lub też ich nie widzimy). Zła implementacja zarządzania pamięcią w programie skutkuje zazwyczaj poważnymi błędami, wyciekami oraz niestabilnym działaniem. Postaram opisać się pokrótce takie zachowania, przyczyny ich występowania oraz sposoby jak sobie z nimi radzić. No to lecimy!
Pamięć jest urządzeniem do przechowywania informacji, które pochodzą z uruchomionych//działających aplikacji. Proces zazwyczaj przechowywany jest w określonym, zaadresowanym przedziale pamięci (zapisujemy ten przydział komórki za pomocą systemu heksadecymalnego), może on jednak rezydować na dysku twardym (w swap'ie) w sytuacji gdy nie jest używany lub gdy system operacyjny nie potrafi zaalokować odpowiedniej ilości pamięci dla programu. Pamięć użytkownika (wydzielony dział pamięci operacyjnej, do którego użytkownik ma pełen dostęp) jest zarządzana na dwa sposoby - przez jądro samo w sobie oraz użycie funkcji wywołań pamięci takich jak malloc() i pochodne.
Pamięć jądra
Jądro systemu operacyjnego zarządza zapotrzebowaniem procesów na pamięć operacyjną. Gdy użytkownik uruchamia aplikację, kernel automagicznie alokuje przestrzeń adresową w pamięci użytkownika dla tego procesu. W kolejnym etapie sam proces rozpoczyna zarządzanie przydzieloną mu strukturą pamięci, adresując i dzieląc ją wedle danego schematu:
- Tekst -- przechowywane są tutaj dane '"tylko do odczytu" programu, zazwyczaj stosowane do bieżącej funkcji. Wielokrotne instancje tego samego programu potrafią współdzielić ten obszar pamięci (decyduje o tym kernel).
- Dane statyczne -- miejsce alokacji danych statycznych ("dobrze-znanych"). Generalnie jest to miejsce przechowywania zmiennych globalnych oraz statycznych atrybutów klas C++. System alokuje tą część pamięci dla każdej instancji programu osobno.
- "Pole walki" (często nazywane "przestrzenią miejsca") -- miejsce przetrzymywania dynamicznych bibliotek, binarek etc. Jest to zaalokowany stos (heap()), z najniższym elementem o najwyższym priorytecie, przechowujący strukturę pamięci alokowanej dynamicznie. Adresacja pamięci w stosie odbywa się w sposób przyrostowy - od najniższych rejestrów do najwyższych.
- Stos -- gdy tylko program odwołuje się do zadeklarowanej funkcji, obecny stan musi zostać zaaplikowany na stos. Stos rośnie w dół, od najwyższych adresacji do najniższych. Stos ten przydzielany jest dla każdego procesu osobno.
Pamięć użytkownika
Pamięć użytkownika składana jest na stosie (nie, nie palona jak w średniowieczu ;-)) w "polu walki". Miejsce to jest zarządzane przez funkcje malloc(), realloc(), free() oraz calloc(). Są one częścią biblioteki libc. Z ciekawostek warto wymienić fakt, iż użytkownik 'root' zawsze ma dostęp do pamięci użytkownika, użytkownik nigdy nie ma dostępu do przestrzeni adresowej 'roota' oraz żaden z nich nie potrafi wpisywać danych do przestrzeni adresowej jądra (za wyłączeniem specjalnych wywołań do systemu /proc, które konfigurujemy w czasie kompilacji jądra). Zatem bzdurą są opowiastki, jakoby to użytkownik wyrzucił dump'a z /proc/kmem i uzyskał informacje zastrzeżone. Chociaż, zdarzają się sytuacje, w których root musi przesłać coś bezpośrednio do kernela. To tzw. SysRq, o których pisałem już kiedyś. Ale to nie o tym mówić chciałem! Wróć!
Inne funkcje pamięci
W systemach GNU/Linux programy zwiększają swoje miejsce w pamięci w przekalkulowanych, wcześniej zdefiniowanych inkrementacjach, zazwyczaj o jedną stronę pamięci lub alokację do granicy obecnej strony. Gdy tylko stos będzie potrzebował więcej 'miejsca' niż obecnie zadeklarowała pamięć użytkownika (przy starcie procesu), wywołana jest funkcja systemowa brk(), która żądają więcej pamięci od kernela. Co ciekawe, ilość przydzielonej pamięci może być definiowana funkcją sbrk()!
Aby obejrzeć obecny stos oraz "pole walki", zobacz na /proc//maps konkretnego procesu. Ujrzysz, z jakich bibliotek korzysta program, ile każda z nich zabiera pamięci użytkownika, możesz podejrzeć adresację pamięci i popatrzeć jak działa stos (watch). Mniam ;-)
Struktura
Za każdym razem gdy malloc() alokuje pamięć - tak naprawdę alokuje jej więcej niż funkcja sbrk() kazała. "Memory routines" (czyli schematy zarządzania pamięcią) używają tej dodatkowej przestrzeni do dbania o stabilność procesu (swoisty zapętlony maintance). Aby zadeklarować dokładnie taką wartość pamięci, jaką potrzebujemy, użyjmy wywołania malloc_usable_space(). Paczka pamięci alokowanej jest zazwyczaj o 8 bitów większa, z tym musimy się już pogodzić.
A jak wygląda taka paczka? Struktura paczki (strony) jest odpowiednio ustalona. Na początku znajduje się pole zawierające wielkość poprzedniej strony, dalej kolejno wielkość obecnej strony, żądana pamięć (wraz z nadmiarem pamięci (wspomniane min. 8 bit)) i na końcu znowu wielkość strony. Ostatnie pole zawiera flagę, która wskazuje, czy system zarządzania pamięcią ma zająć się stroną od razu po zakończeniu poprzedniej (ciągłe dane).
Schemat zarządzania pamięcią w GNU/libc używa tzw. "koszyków" aby utrzymać strony pamięci w podobnych rozmiarach dla zwiększenia wydajności i zapobieżeniu fragmentacji pamięci (nieużywane, bardzo małe strony pamięci między wielkimi stronami nigdy nie zostałyby użyte (wymagałoby to przepisania praktycznie każdego obecnie używanego programu)). Obecne systemy zarządzania tym procesem są bardzo dobrze dobrane i wyważone, nie są jednak zorientowane na szybkość operacji (jedynie na bezpieczeństwo tejże). Tutaj nadal pozostaje pole do popisu dla hackerów jajka. I to ogromne!
i wreszcie:
Debug
Pamięć może sprawiać problemy. Np. przez użycie już zadeklarowanej przez proces pamięci w innym wątku//z odwołaniem do innej strony, bądź też próbą zwolnienia (free()) pamięci już zwolnionej. Choć zazwyczaj nie zaczyna to być problemem samym w sobie, zazwyczaj coś idzie źle gdy proces chce przejąć ponownie źle zaalokowany//zwolniony przydział pamięci. W rezultacie - adres jest używany dwukrotnie (pierwszy - ten "źle" wykonany, drugi - obecne odwołanie), co zazwyczaj powoduje zrzut pamięci (core dump) w sytuacji gdy adres zawiera wskaźniki do innych części pamięci lub offsety zadokowane statycznie.
Kolejnym znanym problemem jest "łażenie" po preambule strony pamięci. Proces potrafi dowolnie modyfikować pola strony, w ten sposób może też zastąpić całą preambułę strony. Zazwyczaj powoduje to całkowitą odmowę posłuszeństwa ze strony zarządcy pamięci i w czasie odwołań do danej strony - początek memory leaka. (wycieku pamięci)
Czasem nadpisywany jest właściwy stos danych - a to prowadzi do całkowitego zniszczenia danych. Użytkownik widzi taką sytuację na ekranie monitora zazwyczaj jako nagłe i nieoczekiwane zakończenie programu nad którym prowadził pracę z całkowitą stratą danych, którymi program owy zarządzał (Microsoft Word jest tutaj dobrym przykładem). Podobne zachowanie reprezentuje bardzo często Mozilla Firefox, Opera oraz OpenOffice. Zazwyczaj takie zniszczenie danych w stronie pamięci nie zakańcza procesu od razu. Użytkownik często zaczyna dostawać przeróżne, dziwne komunikaty (znane "pamięć nie może być read") bądź też zauważyć dziwne zachowanie programu (wolne działanie, wysyłanie na ekran dziwnych znaków, problemy z myszką). W takiej sytuacji ZU powinien natychmiast zamknąć program zapisując swoją pracę.
Podobnie, jeśli zapis nagłówka strony zostanie zniszczony, zarządca zwróci błąd na głównej pętli (co zaowocuje podobnym przypadkiem jak powyżej).
Użycie niezaalokowanej pamięci w "polu bitwy" także może spowodować błędy. Najczęstszą sytuacją, która ma miejsce, jest zapis do pamięci poza stosem, lecz ciągle w stronie pamięci. W zasadzie sytuacja taka nie powoduje błędu, dopóki nowo zaalokowana pamięć (np. poprzez jądro) nie odwoła się do wcześniej zadeklarowanej i zapisanej pamięci poza stosem.
Najczęstszym jednak błędem zarządcy pamięci jest moment, w którym program próbuje użyć pamięci poza obszarem zadeklarowanej dla danego procesu przestrzeni adresowej. Rezultatem takiej operacji jest uwielbiany przez programistów SIGSEGV (segmentation violation fault), a program automatycznie zrzuca pamięć (tzw. memory dump, core dump). Najprostszym sposobem zaimplikowania takiej sytuacji jest kompilacja i uruchomienie poniższego programu:
#include <stdio.h>
int main(){ printf(*"Hello World!"); return 0;}
ciekawostka: jest to najszybszy sposób edycji popularnego Hello World zważając na kryterium minimalnej odległości Levenshteina, aby wyrzucił on SIGSEGV. ;-)
Jednak najbardziej destruktywną sytuacją, która może się przydarzyć, jest sytuacja, w której cały stos pamięci w stronie jest uszkodzony. Program traci wówczas wszystkie zmienne lokalne, parametry, rejestry poprzednich ramek//stron i co najgorsze - zwraca adres komórki pamięci do stosu. W takim przypadku program staje się niemożliwy do debugowania, gdyż ramki są renderowane i przekazywane do samych siebie. Aby wykryć tego typu uszkodzenia pamięci należy użyć jednego z płatnych debuggerów, które potrafią zastąpić kod wykonywalny w samej binarce i już na etapie przetwarzania stosu sygnalizować błędy. Niestety, nigdy takich programów nie używałem i nie potrafię Wam polecić jednego, konkretnego.
A żeby sobie ułatwić życie:
memprof - debugujemy graficznie!
Mając dość bawienia się w gdb czy inne, konsolowe debuggery zechcemy może użyć jednego z narzędzi graficznych na licencji GNU/GPL. Takim narzędziem jest memprof. Korzysta on z wywołań gdb, które w odpowiedni sposób parsuje wyrzucając miłe dla oka komunikaty :-). Kontroluje on procesy poprzez BFD (binary file descriptor) i w zasadzie nie sprawia problemów. Interfejs graficzny oferuje poprzez bilbioteki GTK1.2 oraz GTK2.
I to by było w zasadzie tyle. Artykuł ten miał na celu otwarcie oczu programistom, którzy czasem podchodzą do swojego programu "ok, kompiluje się, działa, jest odporny na głupotę użytkownika!", po czym okazuje się, że za 1056 uruchomieniem na komputerze nasz kochany program się wywala.... Debugujcie swoje dzieła! Nie bądźmy jak Microsoft ;-)))
Bardzo był bym rad, gdy któryś ze zwykłych użytkowników Linuksa dzięki temu artowi zainteresował się głębiej jądrem i procesami. Hackerzy jądra ciągle są poszukiwani. :-)
I na koniec - dziękuję Tobie - za to że przeczytałeś ten artykuł i dobrnąłeś do końca. Zdaję sobie sprawę, że tematyka odbiega znacznie od tego, co robiłem na tym joggerze do tej pory. Cóż - w końcu to w założeniu miał być blog techniczny :-). W następnym cyklu - używanie gdb, czyli szybki tutorial krok po kroczku.
Enjoy!
Skrypt pokazujący status dowolnych usług na dowolnej ilości serwerów
Czytając techbloga natknąłem się na taki oto wpis. Rozwiązanie ciekawe, ale niezbyt efektywne. Postanowiłem podzielić się swoim sposobem - wydaje mi się on ciekawszy i co najważniejsze - lepszy. Możemy sprawdzać dowolną ilość usług na dowolnych serwerach.
LINK DO SKRYPTU
A tutaj można podejrzeć jak on się sprawuje.
Conky jako monitor aktualizacji w Ubuntu
Conky to potężny monitor systemowy przeznaczony dla systemów GNU/Linux – używam go już od bardzo dawna i z błyskiem w oku testuję nowe funkcje pojawiające się z każdą kolejną edycją tego wspaniałego programu. Czasem jednak przypominam sobie o najważniejszej jego funkcji wewnętrznej. Mówię tutaj o ${execi}. Wtedy powstają rzeczy dziwne… Tak jak mój ostatni twór, który można podziwiać na obrazku (obok głównego okna Conky’iego). Podoba się?
Przezroczysty monitor aktualizacji na pulpicie Ubuntu!
Proces wdrożenia przebiega w kilku etapach, w których użytkownik musi sam przeprowadzać drobne przeróbki plików konfiguracyjnych w celu personalizacji. Postaram się omówić wszystkie kroki jak najdokładniej.
1. Instalacja Conky
Załóżmy, że użytkownik nigdy nie posiadał programu Conky. Możemy zainstalować go z repozytoriów:
sudo apt-get install conky
Jednak polecam własną kompilację gdyż wersja zawarta w repozytoriach jest bardzo stara i posiada pewne błędy. Postaram się udostępnić nowo skompilowane paczki w ciągu kilku dni roboczych. Na razie tyle o Conkym – za chwilę do niego wrócimy.
2. Prekonfiguracja monitora systemu
Skorzystamy w tym miejscu z mojego skryptu, który napisałem na tą okazję:
sudo nano -w /etc/init.d/UPGRADE.MONITOR
Gdzie wpisujemy:
#!/bin/bash
apt-get update
sh -c "apt-get dist-upgrade -s | grep Inst | cut -c 6- > /var/log/upgrades.log"
Oraz wywołujemy:
sudo chmod +x /etc/init.d/UPGRADE.MONITOR
Zasadą działania skryptu jest wrzucenie w plik tekstowy obecnie dostępnych aktualizacji w repozytoriach. Zauważyć należy, że skrypt nie instaluje żadnego oprogramowania bez naszej wiedzy.
3. Cron – czyli make it work!
Chcemy teraz, aby nasz malutki skrypt uruchamiał się co pewien wybrany przez nas, okres czasu i sprawdzał dostępne aktualizacje. Użyjemy do tego celu narzędzia systemowego „Cron”, który w skrócie można określić jako „sheduler”. Wykonamy w tym celu prosty zabieg:
sudo nano -w /etc/crontab
Wpiszmy do niego na samym końcu podaną regułkę:
10,20,30,40,50,59 * * * * root /etc/init.d/UPGRADE.MONITOR
Po czym uaktualniamy pliki konfiguracyjne cron'a.
sudo /etc/init.d/cron reload
Krótkie wyjaśnienie – jedyne o czym powinien zamartwić się użytkownik to pierwsze wartości, wpisywane po przecinku. Jest to definicja minut w wymiarze godziny, w których ma się uruchamiać nasz skrypt. Używane przeze mnie ustawienie wywołuje aktualizację monitora w 10, 20 (..) minucie każdej godziny. Jest to wygodne rozwiązanie, gdyż przy łączu 1mb/s nie zauważam w ogóle spadku wydajności łącza (aktualizacja repozytoriów przebiega w 100% transparentnie!). W wartościach każdy użytkownik powinien sam znaleźć „złoty środek” dla jego rodzaju łącza.
4. Conky – jak to pokazać na pulpicie?
Została nam już tylko kosmetyka. Dla celu monitora wywołajmy osobną, niezależną instancję Conky’iego. Pozwoli nam to używać równolegle naszego monitora systemowego i monitora aktualizacji (jak na powyższym screenie).
nano -w ~/.conkyrc2
Przykład pliku konfiguracyjnego
Uwaga – plik konfiguracyjny jest dostosowany do moich potrzeb. W celu powiększenia swojej wiedzy na temat pliku konfiguracyjnego programu Conky należy udać się na tą stronę co też doradzam. Najważniejszą linijką jest tutaj ${execi 20 cat /var/log/upgrades.log}, powoduje ona wyświetlanie się naszych aktualizacji na ekranie.
Jedyne co nam pozostaje to dodać poniższą linijkę do Autostartu naszego środowiska graficznego:
conky -d -c ~/.conkyrc2 &
Voila! Przezroczysty monitor aktualizacji apt’a na pulpicie. :)
Zainteresowanym polecam lekturę manpages dla wszystkich użytych w HowTo poleceń oraz zagłębienie się w struktury konfiguracji programu Conky. Do powyższego HowTo bardzo łatwo dodać powiadamianie sms’em o aktualizacjach (co podałem kilka dni temu), powiadamianie na Jabbera (poprzez sendxmpp) oraz kilka innych ciekawostek, które w ogólnym rozrachunku potrafią bardzo uprzyjemnić życie.
Enjoy!
Powiadamianie sms’em w systemie Linux
Ostatnio wykonałem szybką i sprawną migrację całego mojego sprzętu na dystrybucję GNU/Linux Gentoo (spokojnie, nie opuszczam Ubuntu ani nie odwracam się tylem do Community!). Potrzebowałem narzędzia, które informowałoby mnie w każdym momencie i w każdym czasie o zakończeniu kompilacji na moim komputerze domowym. Pomyślałem oczywiście o powiadamianiu SMS. Przykładowy scenariusz:
Wychodzę na uczelnię z domu zostawiając kompilację kdebase. W trakcie 3 wykładu przychodzi do mnie sms informujący mnie o stanie wykonanej czynności, ostatnio zainstalowanych pakietach, czasie kompilacji. Loguję się poprzez ssh z komórki na mój komp, odświeżam pliki konfiguracyjne i zamykam system.
Niemożliwe? Bynajmniej!! Możliwe w 100%! Krótki i treściwy How To:
Zaznaczam, że powiadamianie sms’em możliwe jest na tą chwilę tylko i wyłącznie dla użytkowników posiadających konto GMail oraz komórkę w sieci PlusGSM. W najbliższej przyszłości (czyt. po sesji :P) mam zamiar przerodzić projekt w większą aplikację do powiadamiania użytkownika o dowolnej czynności. HowTo jest tylko szkicem! Aplikacja „mail” powinna znajdować się w paczce „sendmail”.
Konfiguracja powiadamiania SMS'em w Linuksie
1. Konfigurujemy sSMTP. Oczywiście komendy typowe dla systemu Gentoo zamieniamy na typowe dla Ubuntu (sudo apt-get install itp.). Gdyby ktoś bardzo chciał mogę dać zaproszenie do GMail.
2. Tworzymy plik wykonywalny (w dowolnym miejscu, może być np. /opt/powiadom) i wpisujemy doń:
#!/bin/bash Po czym modyfikujemy do dla swoich potrzeb. Powyższy przeznaczony jest do powiadamiania o statusie wykonania Emerge. Po drobnej modyfikacji może on służyć do powiadamiania o statusie wykonania dist-upgrade lub innej czynności związanej z apt-get.
if [ $? = 0 ];
then
{
echo "Emerge zakonczone, ostatni zainstalowany pakiet:";
genlop -lnu | sed -e "s/.*\([/]\+\)/\1/" | tail -n 2;
} | mail -s "LOG" -c 48xxxxxxxxx@text.plusgsm.pl 48xxxxxxxx@text.plusgsm.pl;
else { echo "EMERGE NIEUDANE"; } | mail -s "LOG" -c 48xxxxxxxxxxxxxxx@text.plusgsm.pl 48xxxxxxxxxxxx@text.plusgsm.pl ;
fi
Modyfikacje wnosić możemy w dowolny sposób, pamiętając o zachowaniu składni języka BASH.
3. Dodajemy dowiązanie symboliczne naszego pliku wykonywalnego do /usr/sbin/powiadom
4. Przykładowe wywołanie skryptu:
$ sudo apt-get dist-upgrade; sudo powiadom
# emerge -vaD world; powiadom
Skrypt jest na razie tylko skryptem. Nie ponoszę odpowiedzialności za jego działanie. Jest to pomysł na większe dzieło, którym zamierzam się zając w najbliższych tygodniach. Rozszerzenie funkcji powiadamiania na inne sieci GSM + uniezależnienie skryptu od GMail + zwiększenie funkcjonalności + działanie na wszystkich systemach + uniwersalność. To będzie mój cel w najbliższym czasie. Dodatkowym celem będzie rozszerzenie funkcjonalności na serwery XMPP.
