Witam po Wielkanocy. Skompletowałem sobie aż dwa nowe kamienie, nie przytyłem ani kilograma i jestem w okropnym nastroju. A na dodatek połączenie z Repo znowu zaczyna szwankować. A już było dobrze...
Wrzuciłem nowy snapshot Hierophanta, napisałem krótki opis wszystkich jego poleceń, poprawiłem pozostałą dokumentację w jego dziale. A co nowego w samym Hiero? No, na pewno pousuwałem trochę błędów. hbsinst i hbsremove podają teraz objętość zainstalowanych/usuniętych danych. Pojawił się tryb weryfikacji zainstalowanych plików (opcja -V w hieroq, sprawdza czas modyfikacji i uprawnienia). Hierophant ma teraz prawdziwy plik README oraz prawdziwy Makefile, więc można zrobić "make install". Makefile jest konieczny, bo HBS wzbogacił się o jedną binarkę ("hbshelper") którą należy najpierw skompilować. Dzięki tej binarce pozbyłem się w skryptach hbsinst i hbsremove wywołań takich poleceń jak grep, find, bc, cut, date, head, tail i może jeszcze innych, o których już nie pamiętam. "hbshelper" ulepszył znacznie procedurę porównującą wersje dwóch pakietów przy wykrywaniu downgrade-ów. Jednocześnie poprawił wydajność całego mechanizmu, bo każdą z funkcji które przejął wykonuje szybciej niż miało to miejsce dotychczas. Tak że największą zmianą jest wprowadzenie tej pomocniczej binarki, ale oprócz tego poprawiłem też sporo innych rzeczy, od wielkich błędów jak np. pewien babol w porównywaniu wersji pakietów po malutkie ulepszenia, jak np. rezygnacja z używania sekwencji koloryzujących ANSI w poleceniach hbsremove/hbsinst/hieroq jeśli wykryte zostanie, że ich wyjście jest przekierowywane do pliku lub na fifo.
A z tą binarką to w ogóle "zabawna" historia, bo właśnie przygotowywałem wczoraj wieczorem tę nowszą wersję Hiero do zrzucenia na Repo gdy przypadkiem... skasowałem plik "hbshelper.c". I zostałem bez kodu źródłowego, pozostał mi jedynie gotowy kompilat. Oczywiście to nie jest jakiś wielki projekt, nie ma nawet pół tysiąca wierszy, ale też nie jest to jakiś jednolity kod który można szybko napisać od nowa - to mieszanina kilkunastu malutkich procedur, każda z innej parafii - naprawdę nie miałem ochoty pisać tego od nowa. Więc błyskawicznie zacząłem myśleć jak by tu odzyskać ten kod. Najpierw przejrzałem wszystkie podejrzane katalogi w poszukiwaniu jakiejś kopii. Nie było żadnej. Potem zacząłem szukać ukrytego pliku *.swp vima, który może pozostał jeśli kiedyś przypadkiem ubiłem jakiegoś xterma z uśpionym w nim vimem, więc może dałoby się to tak odtworzyć... ale też jak na złość nic.
No dobra, przecież w mc jest jakaś funkcja ext2undel, może ona podziała? Ale ja mam ext3, więc... więc mc nic nie znalazł. Szybko przepuściłem jeszcze /proc/kcore przez procedurę wyszukującą, licząc że może jeszcze w ramie znajdę gdzieś zbuforowaną kopię pliku, w końcu może gdzieś jeszcze się ostał jakiś vimowy bufor którego nic nie nadpisało? Ale wynik też był negatywny. Pozostało mi szukanie w obrazie partycji - /dev/hda2. 40GB do przeszukania, szacując tempo przepływu danych w prowizorycznie skleconym mechanizmie wyszukującym (grep z opcją "-a" i kontekstem ustawionym dla pewności na 2000 wierszy) wyliczyłem "data flow" na jakieś 1MB/s, co znaczyłoby że partycja zostanie przeglądnięta w ciągu circa jedenastu godzin, choć efekty wyszukiwania musiałem zapisywać na dysku licząc na setki megabajtów danych i bałem się zapętlenia, gdy grep zacznie badać wynik swojej własnej pracy. Tak, teraz jestem pewien że doszłoby do zapętlenia - ale w sytuacjach awaryjnych zawsze przychodzą mi do głowy głupie pomysły, dopiero potem zaczynam logicznie myśleć.
Więc zatrzymałem to grepowanie i sięgnąłem po "debugfs". Krótka sesja z manualem i otrzymałem listing z katalogu w którym leżał kiedyś ów felerny plik. Faktycznie, figurował jako usunięty - nie znalazłem jednak prostego sposobu na odkręcenie tego stanu, a eksperymentowanie z ręcznym alokowaniem bloków, wiązaniu ich z inodami itp. wolałem nie ryzykować - nigdy tego nie robiłem, a wolałem nie pogarszać sytuacji. Ale obiecałem sobie, że kiedyś zrobię ext2 w pliku i poeksperymentuję, taka wiedza może mi się kiedyś bardzo przydać - zwłaszcza że to nie pierwszy raz gdy przez wieczorową senność i wrodzone gapiostwo sam sobie jakieś pliki skasowałem :) Ale dostałem listing inodów plików nadal obecnych w tym katalogu, w tym kilku które zapisywałem równolegle z hbshelper.c. Potem uzyskałem logiczny adres blokowy, który sobie następnie przekształciłem na fizyczny adres blokowy, czymkolwiek by ta cholera nie była. Dla mnie były to wtedy tylko długie ciągi cyferek. Ale posiłkując się kalkulatorem wyszło mi, że ten konkretny katalog leży w okolicach dziewiątego gigabajta dysku. Niezbyt mi to pasowało, bo mam na dysku o parę giga więcej danych i sądziłem, że taki nowy plik jak hbshelper.c powinien wylądować gdzieś dalej... Ale założyłem że to dlatego, iż filesystem jest podzielony na grupy inodów i po prostu tamten katalog z jakiegoś powodu przynależy do grupy nie leżącej tak zupełnie na peryferiach.
Więc wiedząc że interesuje mnie okolica dziewiątego gigabajta sięgnąłem po "dd". Kazałem mu odczytać równo jeden gigabajt dysku poczynając od pozycji 8,7GB i skierować ten strumień na stdout. A tam go przegrepowałem jak poprzednio. Było mi o tyle łatwo że, jak wspomniałem, miałem nadal binarkę skompilowanego hbshelper.c i mogłem z jej ekranu pomocniczego wybrać pewien dosyć unikatowy wiersz, który powinien pomóc grepowi znaleźć odpowiedni fragment danych. A potem musiałem tylko przeczekać grepowanie jednego gigabajta binarnego śmiecia. Rezultatem był plik o wielkości ~0,5MB, bardzo prosty do przejrzenia. Znalazłem w nim mnóstwo znaczków niedrukowalnych i wiele egzemplarzy mojego hbshelper.c, zdeformowanych na różne sposoby i pochodzących z różnych punktów w czasie. Ale w końcu znalazłem też coś, co wyglądało mi na nienaruszoną ostatnią wersję kodu. Wyciąłem ją i eksperymentalnie skompilowałem z identycznymi flagami jak ostatnio, a następnie porównałem za pomocą "cmp" wynikowy kompilat z tym starszym, który mi ocalał. "cmp" stwierdził, że pliki binarne są identyczne - więc miałem w ręku właściwą wersję pliku źródłowego. I nastąpiło długie UUUUFFF :)
Morał z tej historii: Nigdy nie należy odruchowo klepać w enter przy poleceniu "rm". Z drugiej strony można, jak widać, wygrzebać się w z różnych opresji po prostu improwizując, a plik tekstowy odzyskać można za pomocą paru prostych narzędzi... Oczywiście pewien jestem, że odzyskiwanie danych za pomocą dd ożenionego z grepem jest bardzo okrężną drogą, ale jak na sytuację awaryjną, "mój pierwszy raz" i w ogóle, to chyba i tak nieźle sobie poradziłem :)