Jeśli zastanawialiście się kiedyś, jak wyłączać dyski twarde lub resetować komputer używając tylko oprogramowania (nie naciskając żadnych przycisków), to w tym artykule powinniście znaleźć odpowiedź na wszystkie wasze pytania.
Oczywiście, jak na porządny system przystało, nie możemy operować bezpośrednio na dysku twardym. Ale umożliwi na to sam system, poprzez funkcję systemową sys_ioctl.
Poniżej przedstawiam działający (choć, aby otworzyć plik urządzenia dysku twardego, musiałem mieć uprawnienia roota) kod zatrzymujący dysk twardy. Kod ten napisałem dzięki analizie kodu źródłowego programu hdparm (i tam, oraz do stron podręcznika man: ioctl, ioctl_list, odsyłam po szczegóły). Dla tych, którzy nie korzystają z mojej biblioteki, podaję liczbowe odpowiedniki stałych.
Oto program (składnia NASM):
%include "bibl/incl/linuxbsd/nasm/n_system.inc" ; stałe systemowe section .text global _start _start: mov eax, sys_open ; =5. otwieramy plik.... mov ebx, dysk ; ....twardego dysku mov ecx, O_RDONLY|O_NONBLOCK ; 04000q ósemkowo int 80h cmp eax, 0 jle koniec ; jeśli wystąpił błąd, ; wychodzimy od razu mov ebx, eax ; zachowujemy deskryptor pliku mov eax, sys_ioctl ; =54 ; EBX = deskryptor pliku mov ecx, 0x031f ; komenda specjalna dysku mov edx, args1 ; pierwsze argumenty int 80h mov eax, sys_ioctl ; EBX = deskryptor pliku mov ecx, 0x031f ; komenda specjalna dysku mov edx, args2 ; drugie argumenty int 80h mov eax, sys_close ; =6 ; EBX = deskryptor pliku int 80h ; zamykamy otwarty plik koniec: mov eax, sys_exit ; =1 xor ebx, ebx int 80h ; wychodzimy z programu section .data args1 db 0e6h, 0, 0, 0 ; skopiowane z hdparm.c args2 db 99h, 0, 0, 0 ; też skopiowane dysk db "/dev/hda",0 ; pierwszy dysk,hdb = drugi
UWAGA: należy odczekać chwilę,
aż program się zakończy. Przez czas działania programu komputer może przestać reagować.
Po zatrzymaniu twardego dysku można go uruchomić wykonując dowolną operację na systemie plików
(na przykład wyświetlić zawartość bieżącego katalogu).
Do zresetowania komputera posłuży nam funkcja systemowa sys_reboot, której podamy odpowiednie parametry. Oto program natychmiast resetujący komputer:
%include "bibl/incl/linuxbsd/nasm/n_system.inc" section .text global _start _start: mov eax, sys_reboot ; =88 mov ebx, 0fee1deadh ; wymagana stała mov ecx, 672274793 ; wymagana stała ; EDX = tryb restartu. U nas: zwykły reset mov edx, LINUX_REBOOT_CMD_RESTART ; =0x01234567 int 80h ; to, co jest poniżej nigdy nie zostanie wykonane. mov eax, sys_exit ; =1 xor ebx, ebx int 80h
A oto program natychmiast wyłączający komputer:
%include "bibl/incl/linuxbsd/nasm/n_system.inc" section .text global _start _start: mov eax, sys_reboot ; =88 mov ebx, 0fee1deadh ; wymagana stała mov ecx, 672274793 ; wymagana stała ; EDX = tryb restartu. U nas: wyłączenie prądu mov edx, LINUX_REBOOT_CMD_POWER_OFF ; =0x4321FEDC int 80h ; to, co jest poniżej nigdy nie zostanie wykonane. mov eax, sys_exit ; =1 xor ebx, ebx int 80h
UWAGA: ze względu na to, że podane programy wyłączają/resetują komputer natychmiast po uruchomieniu, NIE zalecam ich stosowania, gdyż może to być niezdrowe dla systemu plików.
No może nie zupełnie będzie to wyłączenie monitora, ale istotnie, obrazu nie będzie. Do wyłączenia obrazu wykorzystamy bibliotekę svgalib (do kompilacji potrzebny będzie też pakiet svgalib-devel).
Całość jest bardzo prosta: inicjujemy bibliotekę funkcją vga_init, wyłączamy obraz funkcją vga_screenoff, czekamy na klawisz (funkcja systemowa sys_read czytająca ze standardowego wejścia) i ponownie włączamy obraz funkcją vga_screenon. Funkcje vga nie przyjmują żadnych argumentów.
Cały program wygląda tak:
; Program wyłączający monitor z wykorzystaniem SVGAlib ; ; Autor: Bogdan D., bogdandr (at) op.pl ; kompilacja: ; nasm -O999 -f elf -o mon_off.o mon_off.asm ; gcc -o mon_off mon_off.o -lvga section .text global main extern vga_screenoff extern vga_screenon extern vga_init %idefine stdin 0 %idefine sys_read 3 main: call vga_init call vga_screenoff mov eax, sys_read ; funkcja czytania z pliku mov ebx, stdin ; standardowe wejście mov ecx, znak ; adres, dokąd czytać mov edx, 1 ; wczytaj 1 bajt int 80h call vga_screenon ret section .data znak db 0
Zwróćcie uwagę na sposób kompilacji.
Skoro korzystamy z bibliotek języka C, to do kompilacji użyjemy GCC.
Wtedy zaś funkcja główna musi się nazywać main - tak samo,
jak w programach w języku C (i tak samo, jak w C, można
ją zakończyć instrukcją RET
). Potrzebne funkcje po prostu deklarujemy jako zewnętrzne (extern).
Program ten uruchomiłem też w środowisku graficznym. Nic złego się nie stało, ale po zakończeniu programu należy przejść na konsolę tekstową i wrócić na graficzną, aby odzyskać obraz.
Do działania programu pod X-ami potrzebne mogą być uprawnienia do pliku /dev/console a pod konsolą tekstową - do pliku /dev/mem.