Gunakan /boot/cmdline.txt untuk membuat skrip boot pertama

11

Banyak pertanyaan telah diajukan tentang bagaimana menemukan Pi saya di jaringan saya . Yang lain - termasuk saya sendiri - memiliki masalah yang memakan waktu ketika mencoba untuk menyebarkan sejumlah Pi baru.

Sementara pembuatan gambar khusus dapat menjadi solusi untuk masalah ini, saya bertanya-tanya apakah ada solusi lain.

Dengan (hanya) /bootdirektori terbuka untuk akses pada mesin biasa (Win / OSX), apakah mungkin untuk menggunakan /boot/cmdline.txtpipa teks ke skrip bash, jalankan dan hapus setelah itu?

EDP
sumber
1
Pertanyaan ini sedang dibahas di Meta . Saya ingin mendengar pendapat Anda, jika memungkinkan. Terima kasih.
Thomas Weller

Jawaban:

6

Saya membuat versi ringan dari Raspberian-light yang membahas kebutuhan ini - ia mengeksekusi skrip custom /boot/firstboot.sh Anda saat boot pertama:

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

Ned McClain
sumber
Terima kasih! 4 tahun setelah OP akhirnya ada solusi yang bagus. Bukan terutama ilmu roket untuk membangunnya sendiri, tetapi Anda berada di banyak jam setiap kali ada rilis baru. IMHO ini harus ditambahkan ke firmware utama.
EDP
3

Bagi mereka yang lebih suka solusi yang hanya melibatkan skrip yang dimasukkan ke partisi boot FAT32 , berikut adalah cara melakukannya. [ Sunting: File-file ini sekarang tersedia dalam skrip pi-boot- proyek .]

Seperti disebutkan dalam jawaban lain, ini melibatkan argumen baris perintah yang dengannya kernel Linux dimulai. Argumen tersebut ada di /boot/cmdline.txt .

Saya telah menguji ini pada Raspbian Buster (v10.1) 2019-09-26. Ini berfungsi pada kartu SD yang baru saja di-flash atau pada disk image .img yang diunduh , yang kemudian bisa Anda flash ke sejumlah kartu SD.

1. Edit argumen kernel

Buka file teks /boot/cmdline.txt , hapus init=bagian mana pun darinya, dan tambahkan ini di akhir baris:

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

Kata terakhir pada baris ini adalah nama skrip yang akan dijalankan oleh kernel sebagai proses pertama (PID = 1) alih-alih / sbin / init . The kernel-argumen halaman bantuan mengatakan hanya argumen tanpa .mendapatkan dilewatkan ke init executable, sehingga Anda tidak dapat memanggil script unattended.sh atau hal-hal seperti itu.

2. Letakkan skrip di partisi boot

Simpan yang berikut ini ke partisi boot sebagai / tanpa pengawasan (nama yang Anda masukkan dalam baris perintah):

# 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

Script ini melakukan beberapa persiapan yang diperlukan (bab 1), lalu apa pun yang ingin Anda lakukan (2) dan kemudian bersih-bersih dan boot ulang (3). Ganti barang-barang di bawah 2 dengan perintah yang ingin Anda jalankan.

Untuk beberapa tugas konfigurasi, Anda mungkin memerlukan boot normal untuk memunculkan jaringan dan layanan lainnya, jadi contoh dalam versi ini (dijelaskan di bawah) hanya menyiapkan skrip yang tepat untuk dijalankan ketika Pi reboot.

3. Masukkan file lain yang dibutuhkan skrip Anda pada partisi boot

... jelas.

Contoh

Bersama skrip saya, saya meletakkan folder payload / pada partisi boot, yang menampung file yang ingin saya pindahkan ke partisi Linux. Dalam skrip tanpa pengawasan di atas,

  • line A memindahkan file ke direktori pi-user. Misalnya payload / home / pi / .bashrc dipindahkan ke sistem file root sebagai /home/pi/.bashrc ;
  • baris B memindahkan file-file yang dimiliki oleh root ke partisi Linux, termasuk payload / usr / local / bin / one-time-script.sh yang menjadi /usr/local/bin/one-time-script.sh , dan serupa untuk payload / lib / systemd / system / one-time-script.service ;
  • baris C kemudian membuat symlink ke file terakhir itu, jadi skrip konfigurasi saya one-time-script.sh dijalankan pada boot berikutnya.

Script itu melakukan berbagai penyesuaian yang saya suka: ia membuat dan memformat partisi FAT32 lain dan menambahkannya ke / etc / fstab sehingga pengguna pi dapat menulisnya (untuk log aplikasi dll.); mengubah ukuran partisi & filesystem ext4 ke sisa kartu SD; mengubah lokal, zona waktu, nama host (berdasarkan nomor seri CPU), negara WiFi; menetapkan jaringan dan frasa sandi WiFi; mengaktifkan SSH; memperbaiki masalah pengaturan bahasa untuk sesi SSH; mengkonfigurasi booting ke konsol tanpa login otomatis; menulis beberapa data tentang sistem ke file di partisi boot; dan tentu saja menghapus symlink itu sehingga tidak akan berjalan lagi saat boot.

Sebagian besar pengguna akan menemukan ini tidak perlu dan lebih suka menggunakan PiBakery , pi-init2 , atau gambar ext4 kustom, yang merupakan solusi hebat. Saya lebih suka ini karena saya bisa memahaminya sepenuhnya dan saya tidak harus menjalankan perangkat lunak lain. Dan itu juga berfungsi: dengan file .img Saya telah memasukkan skrip saya, semua mem-flash kartu SD + memasukkannya ke dalam Pi + membiarkannya berjalan untuk mengkonfigurasi sendiri membutuhkan waktu 6 menit.

Sumber Saya menemukan ide skrip sebagai init=argumen kernel, dan mountperintah yang diperlukan untuk membuatnya berfungsi, di skrip init_resize.sh yang berjalan secara default untuk mengubah ukuran partisi Linux.

Jim Danner
sumber
2

Anda BISA menyebabkan kode dieksekusi dengan mengacaukan baris perintah kernel. Metode yang paling jelas adalah mengganti init dengan sesuatu yang lain. Aplikasi yang paling umum dari ini adalah untuk meluncurkan shell sangat awal dalam proses boot, biasanya karena Anda perlu memperbaiki sesuatu atau karena semuanya rusak sangat parah, misalnya:

init=/bin/bash

Perlu diingat bahwa pada titik ini dalam proses boot, sistem file semua masih terpasang hanya-baca. Selain itu, ada banyak hal yang tidak akan berfungsi dengan benar. Karena Anda tidak menjalankan init yang sebenarnya, shutdown dan reboot tidak akan berfungsi. Anda harus secara manual me-remount sistem file root read-only dan memanggil reboot -funtuk reboot, misalnya.

Saya tidak tahu apakah Anda bisa memberikan argumen untuk bash dengan cara ini. Saya belum pernah mencoba. Secara teori, jika Anda bisa lolos -cke bash, Anda dapat mengatakan bahwa proses bash untuk melakukan apa saja. Tapi itu mungkin berubah menjadi argumen yang cukup panjang, dan saya tidak tahu apakah kernel akan mengizinkan hal-hal seperti itu.

Hal kedua yang bisa Anda lakukan. Anda dapat menyalin ramf awal (initramfs) ke sistem file, dan mengkonfigurasi bootloader untuk menggunakannya config.txt. Ada beberapa cara untuk memasukkan skrip ke dalam initramfs untuk melakukan hal-hal khusus. Anda harus menyiapkan initramfs khusus untuk tujuan ini (lihat initramfs-tools (8)), jadi saya tidak yakin apakah ini solusi yang lebih baik daripada gambar kustom.

Anda dapat memasukkan skrip ke / boot (saya menertawakan saran Anda tentang mesin "biasa", tetapi ini akan menjadi bit yang dapat Anda akses dari mesin tersebut) dan mencoba untuk meluncurkannya menggunakan baris init kernel, tetapi file pada sistem file dos tidak tersedia. dieksekusi kecuali Anda membuatnya untuk seluruh sistem file.

Jika itu saya, saya akan membuat gambar khusus yang menggunakan dhcp untuk mengkonfigurasi jaringan, dan yang berisi skrip khusus yang berjalan saat boot. Script ini memeriksa file tertentu yang berfungsi sebagai flag. Jika file ada, jangan lakukan apa pun. Jika tidak, konfigurasikan hal-hal, lalu buat file flag.

Script config Anda bahkan dapat menarik yang asli dari server http. Ini berarti Anda tidak perlu membuat gambar baru jika Anda harus men-tweak sesuatu.

Itu harus menjadi solusi yang paling tidak membuat stres.

Satu kemungkinan terakhir, tetapi Anda harus melakukan ini pada mesin "non-reguler" :-) Anda dapat me-mount sistem file ext4 ke perangkat loop dan menyalin file ke sana tanpa menulis ke kartu sd terlebih dahulu. Untuk gambar Jessie Raspbian standar, itu akan menjadi seperti ini:

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

Saya suka melakukan fsck pada sistem file saya sebelum membuat gambar. Atur jumlah mount ke nol pada boot pertama :-)

EDIT : Setelah berbulan-bulan dan lebih banyak pengalaman. Anda ingin melihat u-boot. Ganti boot-loader dengan u-boot. Ini dapat dilakukan dari "mesin biasa". Setelah Anda memiliki boot-u di tempatnya, Anda dapat mem-boot jaringan dari mana Anda dapat dengan mudah mem-flash kartu-sd, atau secara teori Anda dapat mem-flash kartu secara langsung, meskipun saya tidak tahu seberapa sulitnya.

Pada dasarnya u-boot membawa network-boot ke Raspberry Pi, sesuatu yang tidak didukungnya sendiri.

izak
sumber
Ok, sistem file hanya bisa dibaca pada tahap itu. Bagaimana dengan init=script & init? Script akan berjalan di latar sementara init dijalankan secara normal. Script akan memerlukan beberapa kondisi memeriksa di awal dan misalnya melanjutkan ketika init telah selesai bekerja.
Thomas Weller
1
Menggunakan & untuk melatar belakangi sesuatu adalah sesuatu yang shell. Kecuali Anda memberi tahu kernel untuk menjalankan perintah tertentu dalam sebuah shell (mis: bash -c "perintah & perintah lain") yang tidak akan berfungsi, dan saya sudah berpikir ini adalah ide yang buruk. Tetapi saya memang memperluas jawaban dan menambahkan opsi u-boot, sesuatu yang baru-baru ini saya temukan.
izak
1
Baru saja selesai mencoba ;-) Tidak, itu benar-benar tidak berhasil
Thomas Weller
1

Saya tidak akan merekomendasikan menyentuh apa pun di area boot (selain config.txt) kecuali Anda memiliki pemahaman terperinci tentang apa yang dilakukan barang-barang itu. cmdline.txttidak dirancang untuk menjalankan hal-hal ketika RPi dimulai. Ini digunakan untuk meneruskan parameter ke kernel Linux saat boot.

Saya menyarankan melakukan ini semua melalui SSH. Sebuah skrip di desktop Anda dapat mendorong bash / python / java / c / program apa pun ke RPi, jalankan, dan kemudian hapus ketika sudah selesai. Tambahkan threading ke skrip di desktop Anda dan Anda dapat mengirimkannya ke banyak perangkat yang Anda inginkan secara bersamaan.

Jacobm001
sumber
1
Itulah cara kami melakukannya sekarang, tetapi saya mencari solusi yang lebih mudah.
EDP
1
Baca: jalankan pengaturan yang diprakarsai oleh klien alih-alih yang diprakarsai oleh server
EDP
@EDP: tidak ada cara untuk mendapatkan yang Anda inginkan hanya dengan mengedit posisi boot. Anda bisa menulis skrip yang menarik file dari server pada boot pertama RPi, dan kemudian memiliki program itu menghapus skrip startup. Itu akan mengharuskan Anda untuk menggunakan gambar khusus.
Jacobm001
1
"Sebuah skrip di desktop Anda" - Skrip mana di desktop saya? Saat boot pertama, tidak ada skrip di Desktop. "Melakukan ini semua melalui SSH" - pada boot pertama Pi mungkin tidak memiliki pengaturan Ethernet atau WLAN yang benar.
Thomas Weller
Anda bahkan tidak perlu memasang benang untuk melihat-lihat proyek kain. IIRC satu-satunya pengunduran diri adalah SSH
Steve Robillard
1

Dapat diperdebatkan, jika Anda setuju dengan memodifikasi gambar untuk menjalankan skrip secara otomatis saat boot pertama, Anda bisa memodifikasi gambar seperti yang dilakukan skrip Anda, dan kemudian menyimpan kartu SD itu ke file gambar dan menggunakannya untuk mem-flash Kartu SD yang akan Anda gunakan dengan RPis baru. Misalnya, jika Anda ingin semua RPis Anda memiliki entri tertentu /etc/fstab, Anda bisa memodifikasi /etc/fstabsendiri daripada menulis skrip yang melakukan modifikasi.

Jika Anda benar-benar membutuhkan tindakan skrip (mis. Jika setiap gambar harus dimodifikasi dengan cara yang berbeda), Anda dapat memindahkan /etc/rc.localke /etc/rc.bakdan meletakkan skrip /etc/rc.localyang menggantikannya dengan /etc/rc.bakperintah terakhir. Skrip itu dapat melakukan tindakan boot pertama sendiri, atau skrip tertentu dari /bootpartisi jika Anda mau.

Dimungkinkan untuk menjalankan otomatis dengan hanya menyentuh /bootpartisi, dengan memasok image ramdisk boot khusus ke kernel seperti dijelaskan di sini . Gambar itu akan berisi skrip untuk memodifikasi partisi root dan kemudian menghapus sendiri dari config.txt. Saya tidak yakin apakah itu sepadan dengan masalahnya.

Dmitry Grigoryev
sumber
-2

Anda mungkin ingin melihat proyek saya Nard yang memiliki solusi untuk masalah Anda:

1) Setiap kartu SD dapat diberi ID unik dengan PC Windows biasa seperti yang dijelaskan di sini:
http://www.arbetsmyra.dyndns.org/nard/#devsettingsid

2) Nyalakan semua Pis Anda

3) Nonaktifkan firewall PC jika memungkinkan

4) Buka jendela DOS prompt dan ping alamat broadcast subnet

5) Daftar tabel ARP dengan perintah Windows "arp -a". Dalam daftar Anda akan menemukan alamat MAC dan IP dari semua Raspberry Pi terdekat.

6) Hubungkan ke setiap perangkat dengan telnet (biasanya tersedia di Windows juga). Frasa selamat datang akan menampilkan ID yang diberikan pada langkah 1.

Ronny Nilsson
sumber
Mungkin deskripsi awal saya tidak cukup jelas. Saya tidak terlalu mencari cara untuk mengidentifikasi Pi. Saya sudah memiliki yang tertutup. Yang saya cari adalah menjalankan satu atau lebih perintah bash dengan mengubah file /boot/cmdline.txt. Ini semua tanpa perlu masuk melalui ssh - bahkan sekali.
EDP
Anda mungkin tidak akan bisa 'ping alamat broadcast subnet', Serangan Smurf biasanya dicegah.
CrackerJack9