Використовуйте /boot/cmdline.txt для створення сценарію першого завантаження


11

Було задано багато запитань про те, як знайти в моїй мережі Pi . Інші - включаючи мене, - займають багато часу, намагаючись розгорнути партію свіжих пі.

Хоча створення нестандартних зображень може бути вирішенням цих питань, мені цікаво, чи є інші рішення.

Маючи (лише) /bootкаталог, відкритий для доступу на звичайних машинах (Win / OSX), чи можна було б використовувати /boot/cmdline.txtтекст для передачі тексту до сценарію bash, запустити його та видалити його згодом?


1
Це питання обговорюється на Meta . Я хотів би почути вашу думку, якщо це можливо. Дякую.
Thomas Weller

Відповіді:


6

Я створив злегка модифіковану версію Raspberian-light, яка відповідає цій потребі - вона виконує ваш власний /boot/firstboot.sh сценарій під час першого завантаження:

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


Дякую! Через 4 роки після ОП нарешті хороше рішення. Не особливо ракетна наука, щоб створити її самостійно, але ви працюєте протягом багатьох годин кожного разу, коли з'явиться новий випуск. IMHO це слід додати до основної прошивки.
EDP

3

Для тих, хто вважає за краще рішення, що включає лише сценарії, завантажені в завантажувальний розділ FAT32 , ось як це зробити. [ Редагувати: файли тепер доступні в пі-завантажувальному сценарії проекту .]

Як згадується в інших відповідях, він включає аргументи командного рядка, за допомогою якого запускається ядро ​​Linux. Ці аргументи знаходяться у /boot/cmdline.txt .

Я перевірив це на Raspbian Buster (v10.1) 2019-09-26. Він працює на нещодавно прошитій SD-картці або на завантаженому зображенні .img диска, який потім можна прошивати на будь-яку кількість SD-карт.

1. Відредагуйте аргументи ядра

Відкрийте текстовий файл /boot/cmdline.txt , видаліть init=з нього будь-яку частину та додайте це в кінці рядка:

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

Останнє слово в цьому рядку - це назва сценарію, який повинен виконувати ядро ​​як перший процес (PID = 1) замість / sbin / init . На довідковій сторінці ядра-аргументи вказуються лише аргументи без .передачі у виконуваний файл init, тому ви не можете викликати скрипт без нагляду.sh або подібні речі.

2. Помістіть скрипт на завантажувальний розділ

Збережіть наступне у завантажувальному розділі як / без нагляду (назва, яку ви ввели в командний рядок):

# 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

Цей сценарій виконує необхідну підготовку (глава 1), потім все, що ви хочете зробити (2), а потім очищення та перезавантаження (3). Замініть матеріал під 2 командами, які потрібно виконати.

Для деяких завдань конфігурації вам, мабуть, потрібна звичайна завантажувальна програма для підключення до мереж та інших служб, тому приклад у цій версії (пояснюється нижче) готує лише відповідний сценарій для запуску, коли Pi перезавантажується.

3. Помістіть будь-які інші файли, потрібні вашому сценарію, на завантажувальний розділ

... очевидно.

Приклад

Разом зі своїм сценарієм я розміщую папку корисного навантаження / на завантажувальний розділ, який вміщує файли, які я хочу перемістити до розділу Linux. У сценарії без нагляду вище,

  • рядок A переміщує файли в каталог користувача pi. Наприклад, корисне навантаження / home / pi / .bashrc переміщується в кореневу файлову систему як /home/pi/.bashrc ;
  • рядок B переміщує файли, що належать кореням , у розділ Linux, включаючи payload / usr / local / bin / one-time-script.sh, який стає /usr/local/bin/one-time-script.sh , і подібне для корисного навантаження / lib / systemd / system / one-time-script.service ;
  • рядок C потім створює символьне посилання на цей останній файл, тому мій сценарій конфігурації one-time-script.sh запускається при наступному завантаженні.

Цей сценарій виконує різні налаштування, які мені подобаються: він створює та форматує інший розділ FAT32 та додає його до / etc / fstab, щоб користувач pi міг писати до нього (для журналів додатків тощо); змінює розмір розділу файлів і файлів ext4 до залишку SD-карти; змінює місцевість, часовий пояс, ім'я хоста (на основі серійного номера процесора), країну WiFi; встановлює мережу Wi-Fi та пароль; вмикає SSH; виправляє проблему налаштування мови для сеансів SSH; налаштовує завантаження в консоль без автоматичного входу; записує деякі дані про систему у файл на завантажувальному розділі; і, звичайно, він видаляє це символьне посилання, щоб воно не запускалося знову під час завантаження.

Більшість користувачів вважають це зайвим і вважають за краще використовувати PiBakery , pi-init2 або користувацьке зображення ext4, які є чудовими рішеннями. Я вважаю за краще це, оскільки можу це повністю зрозуміти, і мені не потрібно запускати інше програмне забезпечення. І це також працює: з файлом .img, в який я розмістив свої сценарії, миготіння SD-карти + поміщення її в Pi +, запускаючи її для налаштування, займає 6 хвилин.

Джерело Я знайшов ідею сценарію як init=аргументу ядра та mountкоманд, необхідних для його роботи, у скрипті init_resize.sh, який працює за замовчуванням, щоб змінити розмір розділу Linux.


2

Ви МОЖЕТЕ викликати виконання коду, возившись з командним рядком ядра. Найбільш очевидний метод - замінити init чимось іншим. Найпоширенішим застосуванням цього є запуск оболонки дуже рано в процесі завантаження, як правило, тому, що вам потрібно щось виправити або через те, що все інше дуже погано зламано, наприклад:

init=/bin/bash

Майте на увазі, що на даний момент процесу завантаження файлові системи все ще змонтовані лише для читання. Крім того, є ціла купа речей, які просто не працюватимуть правильно. Оскільки у вас немає справжнього запуску init, вимкнення та перезавантаження не працюватимуть. Ви повинні вручну reboot -fперезавантажити кореневу файлову систему лише для читання та закликати перезавантажити, наприклад.

Я не маю поняття, чи можете ви передавати аргументи, щоб бити таким чином. Я ніколи не пробував. Теоретично, якщо ви можете перейти -cдо bash, ви можете сказати, що цей баш робити будь-що. Але це може обернутися досить довгим аргументом, і я не знаю, чи дозволило б ядро ​​подібні речі.

Друге, що ти можеш зробити. Ви можете скопіювати початкову рамбу (initramfs) у файлову систему та налаштувати завантажувач для її використання config.txt. Існує кілька способів залучення сценаріїв до initramfs, щоб робити спеціальні речі. Для цього вам доведеться підготувати спеціальну програму initramfs (див. Initramfs-tools (8)), тому я не впевнений, що це краще рішення, ніж зображення на замовлення.

Ви можете включити скрипт в / boot (я сміявся з вашої пропозиції щодо "звичайних" машин, але це був би біт, до якого ви можете отримати доступ з цих машин) і спробувати запустити це, використовуючи рядок init рядок ядра, але файли в dos файлових системах aren виконується, якщо ви не зробите це для всієї файлової системи.

Якби це я, я створив би нестандартне зображення, яке використовує dhcp для налаштування мережі, і містить спеціальний сценарій, який працює під час завантаження. Цей скрипт перевіряє наявність конкретного файлу, який діє як прапор. Якщо файл існує, нічого не робіть. Якщо ні, конфігуруйте речі, тоді створіть файл прапора.

Ваш сценарій конфігурації навіть може витягнути реальну річ із http-сервера. Це означає, що вам не доведеться створювати нове зображення, якщо вам доведеться щось підправити.

Це має бути найменш стресовим рішенням.

Остання остання можливість, але вам доведеться це зробити на "не регулярній" машині :-) Ви можете встановити файлову систему ext4 на циклічний пристрій і скопіювати файли в неї, не записуючи її на sdcard. Для стандартного зображення Raspbian Jessie це було б щось подібне:

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

Мені подобається робити примусовий fsck у своїх файлових системах перед створенням зображень. Встановлює кількість монтажу до нуля під час першого завантаження :-)

EDIT : Після багатьох місяців і більше досвіду. Ви хочете подивитися на u-boot. Замініть завантажувач на u-boot. Це можна зробити з "звичайної машини". Після того, як у вас завантажиться u-boot, ви можете або завантажити мережевий дистрибутив, з якого ви зможете легко прошивати sd-карту, або теоретично ви могли би прошивати карту безпосередньо, хоча я не маю уявлення, наскільки це буде важко.

По суті, u-boot приносить завантаження мережі до Raspberry Pi, те, що воно не підтримує самостійно.


Гаразд, файлова система читається лише на цьому етапі. Про що init=script & init? Сценарій буде працювати у фоновому режимі, коли init запускається нормально. Сценарій потребує певної перевірки стану на початку та, наприклад, продовження, коли init закінчив свою роботу.
Томас Веллер

1
Використання & для того, щоб тло щось було - це оболонка. Якщо ви не скажете ядро ​​виконувати певну команду в оболонці (наприклад: bash -c "деяка команда та інша команда"), яка не буде працювати, і я вже думаю, що це погана ідея. Але я продовжив свою відповідь і додав варіант u-boot, що я нещодавно виявив.
izak

1
Щойно закінчив пробувати ;-) Ні, це справді не виходить
Томас Веллер

1

Я б не рекомендував торкатися нічого в області завантаження (крім config.txt), якщо ви не маєте детального розуміння того, що робить цей матеріал. cmdline.txtне розроблений для запуску речей при запуску RPi. Він використовується для передачі параметрів ядра Linux під час завантаження.

Я б запропонував зробити це все через SSH. Сценарій на робочому столі може підштовхнути програму bash / python / java / c / будь-яку до RPi, виконати її та видалити після завершення. Додайте потоки до сценарію на робочому столі, і ви можете надіслати його на стільки пристроїв, скільки хочете, щоб усі одночасно.


1
Ось як ми це робимо зараз, але я шукаю більш простого рішення.
EDP

1
Прочитайте: запустіть програму, налаштовану клієнтом, а не ініційованим сервером
EDP

@EDP: немає способу отримати те, що ви хочете, просто відредагувавши позицію завантаження. Ви можете написати сценарій, який витягує файл з сервера під час першого завантаження RPi, а потім змусити програму видалити сценарій запуску. Для цього знадобиться користувальницьке зображення.
Jacobm001

1
"Сценарій на робочому столі" - Який сценарій на моєму робочому столі? Під час першого завантаження на робочому столі немає сценарію. "Робити це все через SSH" - при першому завантаженні Pi може не мати правильних налаштувань Ethernet або WLAN.
Томас Веллер

Вам навіть не потрібна різьба, щоб перевірити проект тканини. IIRC єдиним перемогою є SSH
Стів Робіллард

1

Можливо, якщо ви все в порядку зі зміною зображення для автоматичного запуску сценарію під час першого завантаження, ви можете просто змінити зображення таким чином, як ваш сценарій, а потім зберегти цю SD-карту у файл зображення та використовувати її для спалаху SD-карт, які ви будете використовувати з новими RPis. Наприклад, якщо ви хочете, щоб усі ваші RPis мали певний запис /etc/fstab, ви можете просто змінити /etc/fstabсебе замість того, щоб писати сценарій, який робить модифікацію.

Якщо вам абсолютно потрібні сценарії дії (наприклад, якщо кожне зображення має бути змінено по-іншому), ви можете перемістити свій файл /etc/rc.localдо /etc/rc.bakта поставити сценарій, /etc/rc.localякий замінює себе /etc/rc.bakв останній команді. Цей скрипт міг виконувати перші дії завантаження самостійно, або він може викликати певний скрипт із /bootрозділу, якщо ви хочете.

Автоматичний запуск можна зробити, торкнувшись лише /bootрозділу, надавши ядро ​​спеціальне зображення завантажувальної рамки, як описано тут . Це зображення міститиме сценарії для зміни кореневого розділу, а потім самостійного видалення з config.txt. Я не впевнений, чи варто цього клопоту.


-2

Ви можете подивитися на мій проект Nard, який має рішення для вашої проблеми:

1) Кожній SD-картці може бути призначений унікальний ідентифікатор за допомогою звичайного ПК з Windows, як описано тут:
http://www.arbetsmyra.dyndns.org/nard/#devsettingsid

2) Включіть усі ваші Піси

3) Вимкніть брандмауер ПК, якщо це можливо

4) Відкрийте вікно підказок DOS та вкажіть адресу трансляції підмережі

5) Перерахуйте таблицю ARP з командою Windows "arp -a". У списку ви знайдете MAC та IP адреси усіх сусідніх Raspberry Pi.

6) Підключіться до кожного пристрою за допомогою telnet (зазвичай це також доступно і в Windows). У вітальній фразі буде відображено ідентифікатор, призначений на кроці 1.


Можливо, мій початковий опис був недостатньо зрозумілим. Я не особливо шукаю способу ідентифікації пі-пі. Я вже це висвітлював. Що я шукаю - це запустити одну або кілька команд bash, змінивши файл /boot/cmdline.txt. Це все без необхідності входу в систему через ssh - навіть один раз.
EDP

Ви, ймовірно, не зможете "пінг-адреси трансляції підмережі", атаки Smurf зазвичай запобігають.
CrackerJack9
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.