Jak stworzyć system Linux, który uruchamia pojedynczą aplikację?

17

Próbuję uruchomić aplikację dla systemu Linux i wszystko, co chcę uruchomić, to ta jedna aplikacja po uruchomieniu. Potrzebuję sieci i to wszystko (bez wyświetlacza, urządzeń peryferyjnych itp.). Nie chcę, aby inne aplikacje działały, więc aplikacja, którą uruchamiam, ma 100% procesora. czy to możliwe?

dschatz
źródło
Nie będzie w stanie złapać 100% CPU, ponieważ Twój system operacyjny wciąż potrzebuje zasobów.
n0pe
@MaxMackie Oczywiście, ale chciałbym, aby system operacyjny przejął tylko w imieniu aplikacji (na przykład w celach sieciowych).
dschatz
1
Zdajesz sobie sprawę, że nawet przy załadowanym środowisku pulpitu, ale gdy siedzisz bezczynnie, nie używa to czasu procesora, prawda? A używany przez niego suwak podlega wymianie, jeśli wymagają tego inne aplikacje.
psusi
@dschatz Byłoby pomocne, gdybyś podał więcej szczegółów w swoim pytaniu. Na przykład powiedz nam więcej o tym, jaką aplikację chcesz uruchomić, jak ma ona działać i jakiego sprzętu używasz.
NN
Jeśli to możliwe, chciałbym wiedzieć, dlaczego tego chcesz. Z tego, co rozumiem, chcesz usunąć wszystko z systemu operacyjnego (dołączona konsola), aby uruchomić aplikację. Wzrost wydajności będzie marginalny, więc po co mieć tyle pracy?
nmat

Odpowiedzi:

13

Minimalny program initrd CPIO hello world krok po kroku

wprowadź opis zdjęcia tutaj

Skompiluj cześć świata bez żadnych zależności, które kończą się nieskończoną pętlą. init.S:

.global _start
_start:
    mov $1, %rax
    mov $1, %rdi
    mov $message, %rsi
    mov $message_len, %rdx
    syscall
    jmp .
    message: .ascii "FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n"
    .equ message_len, . - message

Nie możemy użyć sys_exit, inaczej jądro wpadnie w panikę.

Następnie:

mkdir d
as --64 -o init.o init.S
ld -o init d/init.o
cd d
find . | cpio -o -H newc | gzip > ../rootfs.cpio.gz
ROOTFS_PATH="$(pwd)/../rootfs.cpio.gz"

Tworzy to system plików z naszym hello world /init, który jest pierwszym programem dla użytkowników, który uruchomi jądro. Moglibyśmy również dodać więcej plików d/i byłyby one dostępne z /initprogramu podczas działania jądra.

Następnie cdw drzewie jądra Linux, kompilacja jest jak zwykle i uruchom ją w QEMU:

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v4.9
make mrproper
make defconfig
make -j"$(nproc)"
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd "$ROOTFS_PATH"

I powinieneś zobaczyć linię:

FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR

na ekranie emulatora! Pamiętaj, że nie jest to ostatni wiersz, więc musisz spojrzeć nieco dalej.

Możesz także użyć programów C, jeśli połączysz je statycznie:

#include <stdio.h>
#include <unistd.h>

int main() {
    printf("FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR FOOBAR\n");
    sleep(0xFFFFFFFF);
    return 0;
}

z:

gcc -static init.c -o init

Możesz działać na prawdziwym sprzęcie z włączonym USB /dev/sdXi:

make isoimage FDINITRD="$ROOTFS_PATH"
sudo dd if=arch/x86/boot/image.iso of=/dev/sdX

Świetne źródło na ten temat: http://landley.net/writing/rootfs-howto.html Wyjaśnia także, jak używać gen_initramfs_list.sh, czyli skryptu z drzewa źródeł jądra Linux, który pomaga zautomatyzować proces.

Następny krok: skonfiguruj BusyBox, aby móc współpracować z systemem: /unix/2692/what-is-the-smallest-possible-linux-implementation/203902#203902

Testowane na Ubuntu 16.10, QEMU 2.6.1.

Ciro Santilli
źródło
3

możesz uruchomić jądro z init=/path/to/myappparametrem zdefiniowanym w bootloaderze.

Michał Šrajer
źródło
2
To dość ekstremalne rozwiązanie. Zastąpienie skryptu uruchamiania aplikacją użytkownika spowoduje, że aplikacja będzie działać bez sieci, bez zamontowanych systemów plików innych niż rootfs (bez sysfs lub proc lub tmpfs) i możliwe, że niektóre węzły urządzeń nie zostaną utworzone.
trociny
2
@sawdust: Całkowicie się zgadzam. Ale pytanie było również nieco ekstremalne ... :-)
Michał Šrajer
2

Wygląda na to, że próbujesz założyć kiosk . Większość przewodników po Internecie koncentruje się na przeglądarce internetowej, takiej jak Firefox, jako pojedyncza aplikacja, która działa. Spójrz na ten przewodnik po pomysły.

William Jackson
źródło
2
Hmm, naprawdę próbuję uruchomić pojedynczą aplikację z obsługą sieci. Nie chcę, aby X i jak najmniej innych aplikacji działało, jak to możliwe. Nie rozumiem, w jaki sposób ogranicza to działanie wszystkich niepotrzebnych demonów.
dschatz
czy aplikacja może działać bez X?
Journeyman Geek
2

Z pewnością możesz uruchomić tylko jedną aplikację użytkownika po uruchomieniu jądra. Ale nie będzie miał 100% CPU, ponieważ będą musiały istnieć inne procesy związane z jądrem. Zwykle odbywa się to w urządzeniach z wbudowanym systemem Linux, np. Routerach bezprzewodowych. Mam również doświadczenie z pierwszej ręki, robiąc to dla aplikacji wielowątkowej.

Po uruchomieniu jądra uruchamiany jest skrypt inicjujący lub startowy. Przeczytaj o poziomach pracy systemu Linux i procesie init. W użyciu są różne schematy uruchamiania, więc nie można być konkretnym. Ale Linux pozwoli ci dokładnie skonfigurować, które aplikacje i demony będą wykonywane w twojej sytuacji. Inne niż plik startowy w katalogu głównym, pliki wymagające modyfikacji znajdują się w / etc , a w szczególności /etc/init.d

BTW, chyba że jesteś jakimś superprogramerem lub zanim uruchomisz zdalny serwer GDB, będziesz potrzebować jakiegoś rodzaju konsoli debugowania (konsoli PC lub portu szeregowego) dla swojej aplikacji. Umożliwi to otrzymywanie powiadomień o błędach seg, błędach magistrali i błędach asercji. Więc planuj mieć coś w rodzaju „peryferyjnego” oprócz „sieci”.

trociny
źródło
1

Istnieje kilka aplikacji systemowych, które należy uruchomić, poza nimi, oczywiście, możesz poświęcić resztę zasobów komputera tej aplikacji. Aby mieć minimum, możesz rzucić okiem na naprawdę małe dystrybucje Linuksa, takie jak TinyCore Linux itp.

Również zależałoby to od samej aplikacji, wymaganych usług poza siecią itp.

Myślę, że jeśli możesz podać bardziej szczegółowe informacje, uzyskasz bardziej szczegółową odpowiedź.

Podoba mi się rodzaj aplikacji itp.

bakytn
źródło
Moja aplikacja korzysta z biblioteki pthread do uruchamiania niektórych obciążeń wielowątkowych (operacje arytmetyczne) i można jej polecić wykonywanie różnych obliczeń na podstawie danych wejściowych z tcp / ip. Patrząc na TinyCore Linux, uruchamia się w środowisku pełnego pulpitu, czego nie chcę.
dschatz
TinyCore ma mniejszego brata o imieniu MicroCore. Brak GUI, sprawdź to.
n0pe
1
@ MaxMackie Naprawdę nie chcę interfejsu na samym komputerze poza stosem tcp / ip. Aplikacja może blokować na porcie i może być kontrolowana za pomocą pakietów tcp wysyłanych do tego portu.
dschatz
1
Poleciłbym środowisko z uruchomionymi niewielkimi usługami (sprawdź to linuxhelp.blogspot.com/2006/04/... ) i prawie nic poza aplikacją i zainstalowanymi zależnościami.
n0pe
1
@dschatz dobrze, wtedy musisz zhakować jądro, usunąć wszystko inne i skompilować w nim swoją aplikację. bez uderzenia nic innego. tylko twoja aplikacja..lol.
bakytn
1

Jeśli naprawdę nie chcesz niczego poza jądrem Linuksa, obsługą sieci i aplikacją, jedynym sposobem na to jest:

  • Musisz uczynić swoją aplikację modułem jądra - upewnij się, że jest debugowana i dobrze przetestowana. Ten moduł jądra musiałby inicjować czynności zwykle wykonywane w przestrzeni użytkownika, takie jak ustawianie adresów IP interfejsów i wszystkie te dobre rzeczy.
  • Będziesz musiał pobrać i skonfigurować ( make menuconfig) własne niestandardowe jądro i usunąć wszystkie funkcje niezwiązane z uruchomieniem systemu i sieci. Będziesz chciał wyłączyć blokowanie warstwy, nie wiem jak to zrobić w ostatnich jądrach make menuconfig.
  • Następnie musisz dołączyć swój moduł do jądra, aby był on częścią jądra, a nie modułem ładowalnym. Prawdopodobnie wyłączysz moduły ładowalne w powyższym kroku. Jeśli znasz wystarczająco dużo C / C ++, aby utworzyć moduł jądra, powinno to być dla Ciebie łatwe.
  • Musisz zmodyfikować dowolną część jądra, która wpadnie w panikę, jeśli inittego nie zrobi, lub przygotuj się na 1 dodatkowy proces przestrzeni użytkownika.

Wiem, że moduły jądra mogą tworzyć procesy - prosty ps auxpokazałby wiele w typowym systemie (wszystkie są w nawiasach). Prawdopodobnie chcesz, aby Twój moduł utworzył proces jądra. Aby pozbyć się wszystkich procesów tworzonych przez jądro poza twoim, musisz wyłączyć wątki [ kthreadd], zarządzanie energią [ pm], warstwę zdarzeń [ events] i inne.


Jeśli chcesz bardziej praktycznej konfiguracji procesu przestrzeni użytkownika w jądrze + 1, jest to możliwe.

Linux ma opcję wiersza polecenia jądra o nazwie init=- właśnie to jądro uruchomi się po zakończeniu ładowania. Program musi znajdować się na urządzeniu głównym określonym za pomocą root=lub w pliku initrd (ładowanym przez program ładujący).

Jeśli ten program zakończy działanie, Linux wpadnie w panikę, więc upewnij się, że nigdy się nie zakończy.

Wiele współczesnych dystrybucji Linuksa ma to ustawione, więc initprogram w initrd wykonuje pewne dodatkowe inicjowanie przestrzeni użytkownika przed uruchomieniem /sbin/initlub /sbin/systemd. Musisz dowiedzieć się, co robi twoja dystrybucja tutaj (informacje o Debianie są tutaj ) i dowiedzieć się, gdzie możesz określić końcowy program „przekazywania”, a następnie możesz powiedzieć mu, aby uruchomił aplikację zamiast initlub systemd.

systemdzarządza wieloma podstawowymi funkcjami, takimi jak budowanie /dev, ustawianie nazwy hosta i inne rzeczy, więc jeśli jesteś elastyczny, możesz zamiast tego rozważyć konfigurację systemdodrodzenia pojedynczego procesu i opcjonalnie uruchom go ponownie, jeśli się nie powiedzie. Jeśli się nie mylę, robi to zasadniczo w trybie pojedynczego użytkownika lub w trybie odzyskiwania - uruchamia powłokę.

Będziesz miał uruchomione 2 procesy ( systemdi twój program), ale system nie będzie panikował, jeśli Twój program zakończy działanie lub ulegnie awarii.

Rozważ też po prostu lekką instalację Debiana - instalacja „netinst” nie ma wiele innych uruchomień niż jądro, powłoka i kilka usług - lub rozważ OpenWRT / LEDE - ma domyślnie serwer WWW dla Luci i kilka innych usług, ale można je łatwo wyłączyć.

LawrenceC
źródło