Użyj /boot/cmdline.txt do utworzenia skryptu pierwszego uruchomienia


11

Zadano wiele pytań, jak znaleźć moje Pi w mojej sieci . Inni - w tym ja - mają czasochłonne problemy, próbując wdrożyć partię świeżych Pi.

Chociaż tworzenie niestandardowych obrazów może być rozwiązaniem tych problemów, zastanawiam się, czy istnieją inne rozwiązania.

Gdyby (tylko) /bootkatalog był otwarty dla dostępu na zwykłych komputerach (Win / OSX), czy można byłoby użyć /boot/cmdline.txtdo potokowania tekstu do skryptu bash, uruchomić go i usunąć później?


1
To pytanie jest omawiane na Meta . Jeśli to możliwe, chciałbym usłyszeć twoją opinię. Dzięki.
Thomas Weller

Odpowiedzi:


6

Stworzyłem lekko zmodyfikowaną wersję Raspberian-light, która zaspokaja tę potrzebę - uruchamia niestandardowy skrypt /boot/firstboot.sh przy pierwszym uruchomieniu:

https://github.com/nmcclain/raspberian-firstboot


Dzięki! 4 lata po OP jest wreszcie dobre rozwiązanie. Nie jest to szczególnie nauka rakietowa, aby zbudować ją samodzielnie, ale jesteś za wiele godzin za każdym razem, gdy pojawi się nowe wydanie. IMHO należy to dodać do głównego oprogramowania układowego.
EDP

3

Dla tych, którzy wolą rozwiązanie obejmujące tylko skrypty upuszczone na partycję rozruchową FAT32 , oto jak to zrobić. [ Edycja: Pliki są teraz dostępne w skrypcie projektu pi-boot .]

Jak wspomniano w innych odpowiedziach, dotyczy to argumentów wiersza poleceń, z którymi jądro Linux jest uruchamiane. Te argumenty znajdują się w /boot/cmdline.txt .

Przetestowałem to na Raspbian Buster (wersja 10.1) 26.09.2019. Działa na nowo flashowanej karcie SD lub na pobranym obrazie dysku .img , który można następnie sflashować na dowolną liczbę kart SD.

1. Edytuj argumenty jądra

Otwórz plik tekstowy /boot/cmdline.txt , usuń init=z niego dowolną część i dodaj to na końcu wiersza:

init=/bin/bash -c "mount -t proc proc /proc; mount -t sysfs sys /sys; mount /boot; source /boot/unattended"

Ostatnie słowo w tym wierszu to nazwa skryptu uruchamianego przez jądro jako pierwszy proces (PID = 1) zamiast / sbin / init . Strona pomocy kernel-arguments zawiera tylko argumenty, które nie .są przekazywane do pliku wykonywalnego init, więc nie można wywołać skryptu bez nadzoru.sh lub podobnych rzeczy.

2. Umieść skrypt na partycji rozruchowej

Zapisz następujące elementy na partycji rozruchowej jako / nienadzorowane (nazwa podana w wierszu poleceń):

# 1. MAKING THE SYSTEM WORK. DO NOT REMOVE
mount -t tmpfs tmp /run
mkdir -p /run/systemd
mount / -o remount,rw
sed -i 's| init=.*||' /boot/cmdline.txt

# 2. THE USEFUL PART OF THE SCRIPT
# Example:
[[ -d /boot/payload/home/pi ]] && sudo -u pi cp --preserve=timestamps -r\
 /boot/payload/home/pi /home/ && rm -rf /boot/payload/home/pi              # A
[[ -d /boot/payload ]] && cp --preserve=timestamps -r /boot/payload/* /\
 && rm -rf /boot/payload                                                   # B
ln -s /lib/systemd/system/one-time-script.service\
 /etc/systemd/system/multi-user.target.wants/                              # C

# 3. CLEANING UP AND REBOOTING
sync
umount /boot
mount / -o remount,ro
sync
echo 1 > /proc/sys/kernel/sysrq
echo b > /proc/sysrq-trigger
sleep 5

Ten skrypt wykonuje niezbędne przygotowania (rozdział 1), następnie wszystko, co chcesz zrobić (2), a następnie czyszczenie i ponowne uruchamianie (3). Zamień elementy poniżej 2 na polecenia, które chcesz uruchomić.

W przypadku niektórych zadań konfiguracyjnych prawdopodobnie potrzebujesz normalnego rozruchu, aby uruchomić sieć i inne usługi, więc przykład w tej wersji (wyjaśniony poniżej) przygotowuje tylko odpowiedni skrypt do uruchomienia po ponownym uruchomieniu Pi.

3. Umieść inne pliki, których potrzebuje skrypt na partycji rozruchowej

...oczywiście.

Przykład

Wraz ze skryptem umieszczam folder ładunku / na partycji rozruchowej, w której znajdują się pliki, które chcę przenieść na partycję Linux. W skrypcie nienadzorowanym powyżej

  • linia A przenosi pliki do katalogu użytkownika pi. Np. Ładunek / home / pi / .bashrc zostaje przeniesiony do głównego systemu plików jako /home/pi/.bashrc ;
  • linia B przenosi pliki będące własnością root na partycję Linux, w tym ładunek / usr / local / bin / one-time-script.sh, który staje się /usr/local/bin/one-time-script.sh , i podobny do ładunku / lib / systemd / system / one-time-script.service ;
  • linia C tworzy następnie dowiązanie symboliczne do tego ostatniego pliku, więc mój skrypt konfiguracyjny one-time-script.sh jest uruchamiany przy następnym uruchomieniu.

Ten skrypt wykonuje różne dostosowania, które mi się podobają: tworzy i formatuje kolejną partycję FAT32 i dodaje ją do / etc / fstab, aby użytkownik pi mógł do niej pisać (logi aplikacji itp.); zmienia rozmiar partycji i systemu plików ext4 na pozostałą część karty SD; zmienia ustawienia regionalne, strefę czasową, nazwę hosta (na podstawie numeru seryjnego procesora), kraj WiFi; ustawia sieć Wi-Fi i hasło; włącza SSH; naprawia problem z ustawieniami języka dla sesji SSH; konfiguruje ładowanie do konsoli bez automatycznego logowania; zapisuje niektóre dane o systemie do pliku na partycji rozruchowej; i oczywiście usuwa to dowiązanie symboliczne, aby nie uruchomiło się ponownie podczas uruchamiania.

Większość użytkowników uzna to za niepotrzebne i woli używać PiBakery , pi-init2 lub niestandardowego obrazu ext4, które są świetnymi rozwiązaniami. Wolę to, ponieważ mogę to w pełni zrozumieć i nie muszę uruchamiać innego oprogramowania. I to też działa: z plikiem .img , w którym umieściłem swoje skrypty, wszystkie flashowanie karty SD + włożenie jej do Pi +, uruchomienie jej do konfiguracji zajmuje 6 minut.

Źródło Znalazłem pomysł skryptu jako init=argumentu jądra oraz mountpoleceń niezbędnych do jego działania, w skrypcie init_resize.sh, który jest domyślnie uruchamiany w celu zmiany rozmiaru partycji Linux.


2

MOŻESZ spowodować, że kod zostanie wykonany przez zakłócenie linii poleceń jądra. Najbardziej oczywistą metodą jest zastąpienie init czymś innym. Najczęstszą aplikacją tego jest uruchamianie powłoki na bardzo wczesnym etapie procesu rozruchu, zwykle dlatego, że trzeba coś naprawić lub ponieważ wszystko inne jest bardzo zepsute, np .:

init=/bin/bash

Należy pamiętać, że na tym etapie procesu uruchamiania wszystkie systemy plików są nadal montowane tylko do odczytu. Ponadto istnieje cała masa rzeczy, które po prostu nie będą działać poprawnie. Ponieważ nie masz uruchomionego prawdziwego init, zamknięcie i ponowne uruchomienie nie będzie działać. Musisz ręcznie zamontować główny system plików tylko reboot -fdo odczytu i na przykład uruchomić ponownie komputer.

Nie mam pojęcia, czy potrafisz przekazać argumenty do bashowania w ten sposób. Nigdy nie próbowałem. Teoretycznie, jeśli możesz przejść -cdo bash, możesz powiedzieć, że ten proces bash zrobi cokolwiek. Ale może to przerodzić się w dość długi argument i nie wiem, czy jądro pozwoli na takie rzeczy.

Druga rzecz, którą możesz zrobić. Możesz skopiować początkowy ramfs (initramfs) do systemu plików i skonfigurować bootloader, aby go używał config.txt. Istnieje kilka sposobów na przeniesienie skryptów do initramfs, aby robić specjalne rzeczy. W tym celu będziesz jednak musiał przygotować specjalne initramfs (zobacz initramfs-tools (8)), więc nie jestem pewien, czy jest to lepsze rozwiązanie niż obraz niestandardowy.

Możesz dołączyć skrypt do katalogu / boot (śmiałem się z twoich sugestii na temat „zwykłych” maszyn, ale byłby to kawałek, do którego można uzyskać dostęp z tych maszyn) i spróbować uruchomić go za pomocą linii inicjującej jądro, ale pliki na systemach plików dos nie są nie jest wykonywalny, chyba że zrobisz to dla całego systemu plików.

Gdybym to był ja, stworzyłbym niestandardowy obraz, który używa dhcp do konfiguracji sieci, i który zawiera niestandardowy skrypt uruchamiany podczas uruchamiania. Ten skrypt sprawdza określony plik, który działa jak flaga. Jeśli plik istnieje, nie rób nic. Jeśli nie, skonfiguruj rzeczy, a następnie utwórz plik flagi.

Twój skrypt konfiguracyjny może nawet wyciągnąć prawdziwą rzecz z serwera http. Oznacza to, że nie musisz tworzyć nowego obrazu, jeśli musisz coś ulepszyć.

To powinno być najmniej stresujące rozwiązanie.

Ostatnia możliwość, ale musisz to zrobić na „nietypowej” maszynie :-) Możesz zamontować system plików ext4 na urządzeniu pętlowym i skopiować na niego pliki bez uprzedniego zapisania go na sdcard. W przypadku standardowego obrazu Raspbian Jessie byłoby to mniej więcej tak:

sudo losetup /dev/loop0 /tmp/gw.img -o 62914560
sudo mount /dev/loop0 /mnt
sudo cp /my/superduper/script.sh /mnt
sudo umount /dev/loop0
sudo fsck -f /dev/loop0 # This is optional
sudo losetup -d /dev/loop0

Lubię robić wymuszony fsck na moich systemach plików przed tworzeniem obrazów. Ustawia liczbę montowania na zero przy pierwszym uruchomieniu :-)

EDYCJA : Po wielu miesiącach i więcej doświadczeniu. Chcesz spojrzeć na u-boot. Zamień boot-loader na u-boot. Można to zrobić z „zwykłej maszyny”. Kiedy już uruchomisz u-boot, możesz albo uruchomić system z sieci, z którego możesz łatwo sflashować kartę SD, albo teoretycznie możesz sflashować kartę bezpośrednio, chociaż nie mam pojęcia, jak trudne byłoby to.

Zasadniczo u-boot zapewnia rozruch sieciowy na Raspberry Pi, czego nie obsługuje samodzielnie.


Ok, na tym etapie system plików jest tylko do odczytu. Co init=script & init? Skrypt działałby w tle, podczas gdy init uruchamia się normalnie. Skrypt wymagałby sprawdzenia warunków na początku i np. Kontynuowałby po zakończeniu pracy przez init.
Thomas Weller,

1
Używanie & do tła jest kwestią powłoki. Chyba że powiesz jądru, aby uruchomiło określone polecenie w powłoce (np. Bash -c „jakieś polecenie i inne polecenie”), które nie zadziała, a ja już uważam, że to zły pomysł. Ale rozszerzyłem swoją odpowiedź i dodałem opcję u-boot, coś, co odkryłem niedawno.
izak

1
Właśnie skończyłem próbować ;-) Nie, to naprawdę nie działa
Thomas Weller

1

Nie zalecałbym dotykania czegokolwiek w obszarze rozruchowym (poza config.txt), chyba że dokładnie rozumiesz, co robią te rzeczy. cmdline.txtnie jest przeznaczony do uruchamiania rzeczy po uruchomieniu RPi. Służy do przekazywania parametrów do jądra Linux podczas rozruchu.

Sugerowałbym zrobienie tego przez SSH. Skrypt na pulpicie może wypchnąć bash / python / java / c / dowolny program do RPi, wykonać go, a następnie usunąć po zakończeniu. Dodaj wątki do skryptu na pulpicie i możesz wysłać go na dowolną liczbę urządzeń jednocześnie.


1
Tak właśnie to robimy teraz, ale szukam prostszego rozwiązania.
EDP

1
Przeczytaj: uruchom instalację zainicjowaną przez klienta, a nie inicjację serwera
EDP

@EDP: nie ma sposobu, aby uzyskać to, co chcesz, po prostu edytując pozycję rozruchową. Możesz napisać skrypt, który pobiera plik z serwera przy pierwszym uruchomieniu RPi, a następnie poprosić ten program o usunięcie skryptu startowego. Wymagałoby to użycia niestandardowego obrazu.
Jacobm001

1
„Skrypt na pulpicie” - Który skrypt na moim pulpicie? Przy pierwszym uruchomieniu nie ma skryptu na pulpicie. „Robiąc to wszystko przez SSH” - przy pierwszym uruchomieniu Pi może nie mieć prawidłowych ustawień Ethernet lub WLAN.
Thomas Weller,

Nie potrzebujesz nawet nawlekania sprawdź projekt tkaniny. IIRC jego jedyną przebudową jest SSH
Steve Robillard

1

Prawdopodobnie, jeśli nie masz nic przeciwko modyfikowaniu obrazu w celu automatycznego uruchomienia skryptu przy pierwszym uruchomieniu, możesz po prostu zmodyfikować obraz w sposób zgodny ze skryptem, a następnie zapisać tę kartę SD w pliku obrazu i użyć go do flashowania Karty SD, których będziesz używać z nowymi RPis. Na przykład, jeśli chcesz, aby wszystkie RPis miały określony wpis /etc/fstab, możesz po prostu zmodyfikować /etc/fstabsię zamiast pisać skrypt, który dokonuje modyfikacji.

Jeśli koniecznie musisz skryptów działania (np jeśli każdy obraz powinien zostać zmieniony w inny sposób), można przenieść swój /etc/rc.localdo /etc/rc.baki umieścić skrypt w /etc/rc.localktórym zastępuje się ze /etc/rc.bakw ostatnim poleceniu. Ten skrypt może wykonać pierwsze akcje rozruchowe lub może wywołać określony skrypt z /bootpartycji, jeśli wolisz.

Możliwe jest automatyczne uruchomienie poprzez dotknięcie tylko /bootpartycji, poprzez dostarczenie do jądra specjalnego obrazu ramdysku rozruchowego, jak opisano tutaj . Ten obraz zawierałby skrypty modyfikujące partycję główną, a następnie usuwające się z niej config.txt. Nie jestem jednak pewien, czy warto.


-2

Możesz spojrzeć na mój projekt Nard, który ma rozwiązanie twojego problemu:

1) Każdej karcie SD można przypisać unikalny identyfikator za pomocą zwykłego komputera z systemem Windows, jak opisano tutaj:
http://www.arbetsmyra.dyndns.org/nard/#devsettingsid

2) Włącz wszystkie swoje Pisy

3) Wyłącz zaporę komputera, jeśli to możliwe

4) Otwórz okno zachęty DOS i pinguj adres rozgłoszeniowy podsieci

5) Wyświetl tabelę ARP za pomocą polecenia systemu Windows „arp -a”. Na liście znajdziesz adresy MAC i IP wszystkich pobliskich Raspberry Pi.

6) Połącz się z każdym urządzeniem za pomocą usługi telnet (zwykle dostępnej także w systemie Windows). Fraza powitalna wyświetli identyfikator przypisany w kroku 1.


Być może mój początkowy opis nie był wystarczająco jasny. Nie szukam szczególnie sposobu identyfikacji Pi. Już to mam. To, czego szukam, to uruchomienie jednego lub więcej poleceń bash poprzez zmianę pliku /boot/cmdline.txt. Wszystko to bez konieczności logowania przez ssh - nawet raz.
EDP

Prawdopodobnie nie będziesz w stanie „pingować adresu rozgłoszeniowego podsieci”, zwykle zapobiega się atakom Smurf.
CrackerJack9
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.