System Linux Mint to jedna z najsolidniejszych otwartych alternatyw dla dominującego Windowsa. Kibicuję mu z całego serca, a od pewnego czasu tworzę różne poradniki, które ułatwią polskim użytkownikom przejście na ten system.

Jedną z rzeczy, które opisałem, było ustawianie języka polskiego. Pokazałem zarówno klikanie w interfejs, jak i polecenia konsolowe dające ten sam efekt.

…Ale od tamtego czasu odkryłem, że konsola nie do końca daje to samo. W szczególności na Cinnamonie, czyli jednym z wariantów Minta.

Jeśli wyklikam w menu systemu, że chcę polski układ klawiatury, to nie tylko będę mógł wstawiać literę ą przez naciśnięcie Alt+A, ale również zyskam nową ikonę na dolnym pasku. Dzięki niej można przełączać się między układami.
Szybkie polecenie konsolowe setxkbmap pl mi tego nie daje; literki działają, ale pasek się nie zmienia. Do tego układ wraca do poprzedniego stanu po ponownym zalogowaniu.

W jaki sposób sprawić za pomocą konsoli, że na dolnym pasku Cinnamona pojawi się kontrolka od układu klawiatury, ustawiona na język polski? Postanowiłem zanurkować w bebechy systemu, szukając odpowiedzi na to pytanie.

Uwaga

Lojalnie uprzedzam, że wpis nie zawiera odpowiedzi.
Jeśli ktoś chce po prostu zyskać polskie znaki na Mincie, obojętnie w jaki sposób – to polecam menu graficzne oraz mój przewodnik, podlinkowany wyżej.
Obecny wpis może się natomiast przydać osobom chcącym lepiej poznać Minta i stopniowo przechodzić od interfejsu graficznego do debugowania w konsoli. Opisuję całą eksplorację krok po kroku. Z pozycji ucznia, nie mistrza (do którego mi daleko).

Z punktu widzenia użytkowników

Najpierw zobrazuję dokładniej, na ilustracjach, na jakim efekcie mi zależało.

Każda osoba mająca pod ręką myszkę lub touchpada może kliknąć znak Minta w lewym dolnym rogu, następnie ikonkę z lewej kolumny otwierającą Centrum Sterowania Światem. Tam można znaleźć ikonkę odsyłającą do menu odpowiedzialnego za klawiaturę.

Trzy ikonki: logo Minta, ikona Centrum Ustawień, ikona ustawień od klawiatury

W tym menu można z kolei wejść w zakładkę Layouts. Pokaże się lista, na której jest tylko układ angielski. Należy kliknąć plusa pod nią, żeby dodać nowy układ. W kolejnym okienku znaleźć i wybrać polski.

Kolaż pokazujący przyciski, jakie należy kliknąć, żeby dodać polski układ klawiatury do listy wspieranych

Efektem tych działań będzie dodanie flagi USA do dolnego paska. Po jej kliknięciu rozwinie się menu, z którego można wybrać flagę polską. A po jej kliknięciu – zaczną nam działać polskie znaki.

Zrzut ekranu pokazujący wybranie polskiej flagi z dolnego paska Cinnamona

Chciałem osiągnąć ten sam efekt. Mieć jakieś jedno konsolowe polecenie, które daje ikonkę polskiej flagi i działające polskie litery.

Motywacja i oczekiwania

Nie był to pierwszy przypadek, gdy wychodziłem od klikania w interfejs, a potem patrzyłem, co się dzieje pod spodem.

Przykładowo: porównałem kiedyś, jakie pliki otwiera program działający, a jakie niedziałający. Ustaliłem, że w obu przypadkach to te same pliki. A zatem to nie brak czcionek był przyczyną niewłaściwego wyświetlania azjatyckich znaków.

Inny przykład: chciałem ustalić, jak działa program rozpakowujący pliki ZIP. Zwłaszcza że użycie programiku unzip na pliku, z którym ten graficzny dawał radę, kończyło się błędem.
W tamtym przypadku odkryłem, że klikanie w interfejs woła program 7z, czyli 7Zip. Mogłem go użyć zamiast unzipa i zyskać pożądany efekt.

W tym przypadku również liczyłem, że znajdę którąś z dwóch rzeczy:

  1. jakiś plik konfiguracyjny, do którego zapisywane jest konkretne ustawienie;
  2. nazwę i ustawienia programiku konsolowego wołanego przez Centrum Sterowania.

W każdym z tych przypadków mógłbym łatwo stworzyć konsolowy zamiennik, a potem dodać go do jakiegoś większego skryptu, żeby wszystko sobie zautomatyzować.

Nie do końca poszło po mojej myśli, ale wyprzedzam fakty. Póki co – plecak na plecy, czołówka na głowę. Czas na eksplorację ciemnej konsoli.

Zaglądanie za kulisy

Na początek uruchomiłem konsolę kombinacją Ctrl+Alt+T. Obok niej ustawiłem najzwyklejsze okno Centrum Sterowania, z otwartą zakładką od układu klawiatury (jak na obrazku z poprzedniej sekcji, zawierającym słowo Layouts).

Ustalanie odpowiedzialnego programu

Wiedziałem, że za widocznym oknem z ustawieniami musi stać jakiś program-opiekun. Zależało mi na poznaniu jego nazwy, bo była potrzebna do dalszego konsolowego monitoringu.

W konsolę wpisałem polecenie:

xprop | grep WM_CLASS
Objaśnienie

xprop to programik od uzyskiwania informacji na temat okien. Po jego użyciu kursor przyjmuje kształt plusa. Jeśli teraz kliknę dowolne okno, to w konsoli wyświetli się sporo informacji na jego temat.

Te informacje, zamiast do konsoli, lecą do rury (|), a przez nią do innego programu.

Jest nim grep, program od wyszukiwania tekstu. Dostaje informacje o oknie i wyszukuje w nich tekst WM_CLASS; stojący zwyczajowo przy linijce z nazwą programu, do którego przypisane jest okno.

Po kliknięciu okna z ustawieniami znalazło mi linijkę:

Żeby odróżnić treść komend konsolowych od wypluwanego przez nią tekstu, będę oznaczał ten drugi kolorem szarym.

Znaleziony tekst oznacza, że za okno ustawień odpowiada programik cinnamon-settings.py. Skrypt Pythona, bardzo dobrze! W tym języku akurat cośtam „mówię”. Gdybym nie miał innego pomysłu, to zawsze mogę spróbować się w nim rozczytać.

Na razie nie chciałem natomiast zaglądać do kodu, tylko potraktować program jak czarną skrzynkę, którą będę analizował.

Pierwsza rzecz do sprawdzenia: czy dałoby się go wykonać przez konsolę? Tak po prostu wpisując nazwę?

cinnamon-settings.py

Nie. Skrypt widocznie nie znajduje się wewnątrz żadnego z folderów specjalnych Minta i nie wystarczy wołanie go po nazwie.

Żeby skutecznie go wołać, muszę wprost wskazać ścieżkę, jaka do niego prowadzi.
Jak ją ustalić? A chociażby programikiem locate, który przeszukuje systemową bazę nazw plików:

locate cinnamon-settings.py

Znajduje mi dokładnie jeden plik na cały system i wyświetla jego pełną ścieżkę:

Strace

Mając pełną ścieżkę programu, mogłem go uruchamiać przez konsolę. A to pozwala na przykład podpinać pod niego różne analizatory i ustalić, co dokładnie robi.
Takim analizatorem jest choćby strace, domyślnie zainstalowany na Mincie.

Jak działa strace

Za każdym razem, kiedy programy chcą na przykład zajrzeć do wnętrza plików, muszą prosić o to jądro systemu (czyli de facto Linuksa). Te prośby to po angielsku syscalle i dzielą się na różne rodzaje.
Jeśli uznamy, że jądro systemu jest jak król udzielający programom audiencji – to strace jest jak kronikarz, którego wysyłamy do sali tronowej. Zapisuje sobie wszystkie prośby, a następnie zdaje nam dokładną relację.

Polecenie, którego użyłem:

strace -f -o PLIK PROGRAM
  • Argument -f mówi, żeby śledzić nie tylko główny proces, ale również jego „dzieciaki”.
  • Fragment -o PLIK wskazuje, do jakiego pliku strace powinien zapisać wynik swojego działania. Całkiem subiektywnie wybrałem nazwę klawiatura.txt, ale to naprawdę obojętne. Byle w kolejnych komendach była ta sama.
  • Zamiast PROGRAM jest odkryta wyżej długa ścieżka do skryptu.

Po użyciu polecenia uruchamia się typowe okno z ustawieniami – w końcu aktywowałem program, który nim steruje.

Zależało mi na śledzeniu zmian dotyczących układu klawiatury, więc wykonałem wszystkie kroki opisane na początku wpisu, zyskując flagę na dolnym pasku. W tym momencie zamknąłem okno z ustawieniami, a strace przestał notować.

Rezultatem tej dość krótkiej interakcji był spory plik, liczący w moim przypadku 3,9 MB.

Przegląd interakcji z plikami

Czego szukać w kronice strace’a? Dotąd miałem dobre doświadczenia ze sprawdzaniem interakcji z plikami. Dlatego również tutaj poszukałem na początek przypadków użycia funkcji openat (proszącej jądro systemu o otwarcie wskazanego pliku):

grep 'openat' PLIK

Wyskoczy bardzo dużo linijek, z których większość odpowiada ładowaniu elementów podczas samego uruchamiania programu. Może się to wydawać przytłaczające, ale parę intuicyjnych regułek pomaga okiełznać złożoność.

Sposób na odsiewanie wyników ze strace'a

Gdybym miał wskazać regułkę dość uniwersalną – rzeczy interesujące będą raczej pod koniec, a nie na początku.

Programy często po uruchomieniu ładują różne biblioteki, zależności, ikonki… Strace to wszystko łapie. Ale nie będzie tu rzeczy związanych stricte ze zmianą ustawień, dokonaną grubo po załadowaniu programu.

Poza tym przypomnę, że zawęziłem wyniki do funkcji openat, od otwierania plików. W tym kontekście można się wspomagać paroma innymi zasadami.

  • Rzeczy zawierające w swojej ścieżce icons oraz końcówkę pliku .svg albo .png to różne ikonki, raczej mniej ciekawe.
  • Pliki zawierające w ścieżce python3/dist-packages to zapewne różne moduły Pythona, potrzebne do działania obecnemu programikowi (który, przypomnę, sam jest skryptem Pythona).

    Niekoniecznie ciekawe w tym przypadku, bo zapewne są ładowane za każdym razem, gdy włączamy Centrum Sterowania.

  • Pliki zawierające w ścieżce .config/cinnamon/spices to zapewne elementy interfejsu.

    Z pozoru wydają się czymś ciekawym; ale w nazwach widać rzeczy takie jak printers („drukarki”), więc może to być po prostu lista rzeczy ładowanych każdorazowo. Niezwiązana z układem klawiatury.

  • Pliki nieznalezione (z wiadomością No such file or directory na końcu) były dla mnie mało interesujące, bo liczyłem na coś, do czego zapisano ustawienia.

Jeśli ktoś nie chce filtrować na oko i widzi, że szumu w danych jest za dużo, to można rozbudowywać regułkę Grepa, odsiewając stopniowo mniej ciekawe informacje. W tym celu można podać wynik z pierwszego Grepa do kolejnego, ale wykluczającego pewne wzorce (co daje argument -v).

Gdybym na przykład chciał odsiać pliki z ikonami, mające tekst /icons/ w swojej ścieżce, zrobiłbym to tak:

grep 'openat' PLIK | grep -v '/icons/'

W moim przypadku nie rejestrowałem czasu wewnątrz strace’a. Ale gdybym to robił, to dawałoby to kolejną możliwość filtrowania – „wydarzenia ze znacznikiem czasu większym od X”. Mógłbym celowo zawęzić wyniki do ostatnich sekund, kiedy to zmieniłem ustawienia.

Oceniając wyniki na oko, znalazłem parę potencjalnych tropów, takich jak otwieranie plików zawierających w nazwie tekst iso albo zakopanych w głębi folderu o nazwie X11.

Objaśnienie tropów pobocznych

Słowo iso odnosi się zapewne do International Standards Organisation i ogólnie występuje tam, gdzie mamy jakieś oficjalne regulacje. Miary, wagi i te sprawy.

…Czy możliwe, że dwa znalezione pliki z tym słowem w nazwie odnoszą się do dwóch flag wyświetlanych w nowym menu? Żeby to sprawdzić, otworzyłem jeden ze znalezionych plików, kopiując jego ścieżkę przed „uniwersalnego otwieracza”, xdg-open:

xdg-open /usr/share/xml/iso-codes/iso_3166.xml

Po otwarciu pliku mogłem znaleźć w nagłówku komentarz wyjaśniający, czym on jest.

This file gives a list of all countries in the ISO 3166 standard, and is used to provide translations via gettext

Zatem faktycznie rzecz związana ze standardem i językami… Tyle że to wygląda na wewnętrzne informacje ładowane przez system, a nie plik od przechowywania ustawień.

W odmętach strace’a znalazłem również takie coś:

To też mocny trop, bo X11 odpowiada za różne rzeczy na Linuksie. Zarządzanie oknami, dostarczanie do programów zdarzeń z myszy i klawiatury…

Odczytując ten plik, mogłem zobaczyć, że istotnie dotyczy różnych układów klawiatury.

Ale nie ma co się cieszyć na wyrost, bo oprócz plików liczy się to, co robił z nimi program. Za chwilę zobaczymy, że jedynie odczytywał stąd informacje. Nie mogły to być zatem poszukiwane pliki konfiguracyjne.

Spośród plików wyłapanych przez strace’a szczególnie zaciekawił mnie ten:

Występowało tu parę ciekawych, charakterystycznych słów:

  • ui (User Interface, czyli ogólna nazwa na to, co widzi użytkownik),
  • panel (określenie na dolny pasek),
  • chooser (element odpowiedzialny za wybieranie).

Miałem mocne podejrzenie, że to ten plik odpowiada za wszystko. Pojawił się zatem nowy pomysł: wyświetlić teraz wszystkie zapiski ze strace’a, już bez zawężania do funkcji openat. Ale trzymać się tylko tej linijki i późniejszych.

Przegląd pełnych wyników strace’a

Plik stworzony przez strace’a był duży, a przeglądanie go w notatniku byłoby żmudne. Dlatego otwarłem go programikiem less, który ładuje zawartość na raty i radzi sobie z dowolnie wielkimi plikami:

less PLIK

Problemem była duża liczba linijek z komendami recvmsg oraz poll, z których praktycznie wszystkie wyglądały tak samo. Postanowiłem je odsiać, dlatego wyłączyłem lessa (przyciskiem Q) i uruchomiłem ponownie, dostawiając przed nim lekkie filtrowanie:

grep -F -v -e recvmsg -e poll PLIK | less
Omówienie komendy
  • -F wyłącza znaki specjalne i sprawia, że Grep nas nie zaskoczy. Kropka faktycznie jest kropką, a nie oznaczeniem „jakakolwiek rzecz”.

    W tym wypadku ten argument nie robi różnicy, bo szukamy jedynie rzeczy złożonych z prostych liter. Ale warto go znać.

  • -v sprawia, że Grep odrzuca rzeczy pasujące do wzorca.
  • -e TEKST wskazuje tekst do wyszukania, można tego użyć wiele razy w jednej komendzie.

    Poprzednio tego nie używałem, ale teraz to robię, bo chcę znaleźć kilka rzeczy jedną komendą.

    Szukanie kilku wzorców naraz można też zapisać jako 'rzecz1|rzecz2', ale wyraźne wskazywanie każdej z nich z osobna wydaje mi się bardziej przejrzyste.

Po użyciu komendy w konsoli zrobiło się znacznie czyściej. Ale wciąż nie chciało mi się przewijać wielu linijek dotyczących zwykłego ładowania menu.

Żeby przejść w dobre miejsce, użyłem funkcji szukania wbudowanej w lessa: nacisnąłem ukośnik (/), wpisałem layout-chooser (charakterystyczny fragment nazwy pliku, który mnie interesował), po czym nacisnąłem Enter. Przewinęło do odpowiedniej linijki.

Przy interesującym mnie pliku widać było ciekawy wzorzec:

Rozmiar pliku, odczytany z jego metadanych w linijce drugiej, wynosi 8337. Dane o takim samym rozmiarze zostały później wczytane z pliku w linijce trzeciej.
Wniosek: wczytano całą zawartość pliku.

Ponadto plik został otwarty w linijce pierwszej (otrzymując numer 13), a zamknięty w czwartej. Wniosek? Nie nastąpiło nic poza wczytaniem zawartości pliku. Nie był zmieniany.

A to sugeruje, że nie był to plik konfiguracyjny, do którego zapisano jakieś nowe ustawienie. Zamiast tego program sterujący menu Cinnamona wczytał sobie informacje i coś z nimi zrobił.

A co takiego zrobił nasz program? Tego niestety nie ustaliłem. Kolejne linijki strace’a pokazują między innymi użycie komendy sendmsg, na oko z danymi niebędącymi tekstem – może program ulepił coś z informacji i wysłał to do jakiegoś innego procesu systemowego?

W każdym razie nie znalazłem ani zmiany pliku konfiguracyjnego, ani przywołania znanego podprogramu. Inne mechanizmy działania Linuksa są mi na razie mniej znane, więc odłożyłem sprawę na później.

Podsumowanie

Na ten moment nie wyłapałem, co dokładnie zachodzi od momentu wybrania polskiej klawiatury z graficznego menu do pojawienia się ikonki na dolnym pasku Cinnamona.

Znam natomiast nazwę apletu (keyboard@cinnamon.org, odczytana po prawokliknięciu ikony flagi). Wiem również, gdzie szukać programu sterującego całym działaniem. To skrypt Pythona, więc będę w stanie się w nim rozczytać i może wyciągnąć jakieś wnioski. Ogólnie: wyzwanie na później :sunglasses:

Póki co była natomiast eksploracja: xprop, locate, strace do pliku, grep, less, filtrowanie i szukanie na oko… Mam nadzieję, że kronika z tej wyprawy pomoże komuś, kto chce osobiście, krok po kroku, zajrzeć za kurtynę i lepiej odkryć, jak działa Linux.

Ta wiedza się przyda, żeby go doskonalić i pomagać innym osobom w skutecznej migracji (która, mam nadzieję, będzie coraz intensywniejsza).