ใช้ /boot/cmdline.txt เพื่อสร้างสคริปต์บูตครั้งแรก


11

คำถามที่หลายคนได้รับการถามเกี่ยวกับวิธีการหาพี่ของฉันในเครือข่ายของฉัน อื่น ๆ - รวมถึงตัวฉันเอง - มีปัญหาที่ต้องใช้เวลามากในขณะที่พยายามปรับใช้ชุด Pi สด

ในขณะที่การสร้างภาพที่กำหนดเองอาจเป็นทางออกสำหรับปัญหาเหล่านี้ฉันสงสัยว่ามีวิธีแก้ปัญหาอื่น ๆ อีกหรือไม่

ด้วย (เฉพาะ) /bootไดเรกทอรีที่เปิดสำหรับการเข้าถึงบนเครื่องปกติ (Win / OSX) เป็นไปได้ไหมที่จะใช้/boot/cmdline.txtไพพ์ข้อความไปยังสคริปต์ทุบตีเรียกใช้และลบทิ้งในภายหลัง


1
คำถามนี้อยู่ภายใต้การอภิปรายเกี่ยวกับ Meta ฉันต้องการฟังความคิดเห็นของคุณถ้าเป็นไปได้ ขอบคุณ
โทมัสเวลเลอร์

คำตอบ:


6

ฉันสร้างRaspberian-light รุ่นที่ได้รับการดัดแปลงเบา ๆซึ่งตอบสนองความต้องการนี้ - มันรันสคริปต์ /boot/firstboot.sh ที่กำหนดเองของคุณเมื่อบูตครั้งแรก:

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


ขอบคุณ! 4 ปีหลังจาก OP ในที่สุดก็มีทางออกที่ดี ไม่ใช่วิทยาศาสตร์จรวดโดยเฉพาะที่จะสร้างมันด้วยตัวเอง แต่คุณอยู่ในหลายชั่วโมงทุกครั้งที่มีการเปิดตัวใหม่ ควรเพิ่ม IMHO นี้ในเฟิร์มแวร์หลัก
EDP

3

สำหรับผู้ที่ต้องการวิธีการแก้ปัญหาที่เกี่ยวข้องกับสคริปต์เท่านั้นที่ถูกทิ้งลงในพาร์ติชันสำหรับบู๊ต FAT32 นี่คือวิธีการทำเช่นนั้น [ แก้ไข:ขณะนี้ไฟล์พร้อมใช้งานในโครงการpi-boot-script ]

ดังกล่าวในคำตอบอื่น ๆ มันเกี่ยวข้องกับอาร์กิวเมนต์บรรทัดคำสั่งที่เคอร์เนล 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"

คำสุดท้ายในบรรทัดนี้เป็นชื่อของสคริปต์ที่จะทำงานโดย kernel เป็นกระบวนการแรก (PID = 1) แทน/ sbin / init หน้าวิธีใช้kernel-argumentsบอกว่ามี แต่อาร์กิวเมนต์เท่านั้นโดยไม่.ถูกส่งไปยัง executable init ดังนั้นคุณไม่สามารถเรียกสคริปต์unattended.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. ใส่ไฟล์อื่น ๆ ที่สคริปต์ของคุณต้องการบนพาร์ติชันสำหรับบูต

อย่างเห็นได้ชัด ...

ตัวอย่าง

เมื่อรวมกับสคริปต์ของฉันฉันวางโฟลเดอร์payload /ไว้ในพาร์ติชันสำหรับบูตซึ่งเก็บไฟล์ที่ฉันต้องการย้ายไปยังพาร์ติชัน Linux ในสคริปต์แบบอัตโนมัติด้านบน

  • บรรทัด A ย้ายไฟล์ไปยังไดเรกทอรีของผู้ใช้ pi เช่นpayload / home / pi / .bashrcถูกย้ายไปยังระบบไฟล์รูทเป็น/home/pi/.bashrc ;
  • ย้ายสาย B ไฟล์รากที่เป็นเจ้าของลงไปในพาร์ทิชันลินุกซ์รวมทั้งน้ำหนักบรรทุก / usr / local / bin / one-time-script.shซึ่งจะกลายเป็น/usr/local/bin/one-time-script.shและคล้ายกันสำหรับน้ำหนักบรรทุก / lib / systemd / system / ครั้งเดียว script.service ;
  • บรรทัด C จากนั้นสร้าง symlink ไปยังไฟล์สุดท้ายดังนั้นสคริปต์การกำหนดค่าของฉันone-time-script.shจะถูกเรียกใช้ในการบูตครั้งถัดไป

สคริปต์นั้นทำการปรับแต่งต่าง ๆ ที่ฉันชอบ: มันสร้างและฟอร์แมตพาร์ติชัน FAT32 อีกอันและเพิ่มลงใน/ etc / fstabเพื่อให้ผู้ใช้ pi สามารถเขียนได้ (สำหรับบันทึกแอปพลิเคชัน ฯลฯ ); ปรับขนาดพาร์ติชัน ext4 & ระบบไฟล์เป็นส่วนที่เหลือของการ์ด SD; เปลี่ยนโลแคลเขตเวลาชื่อโฮสต์ (ขึ้นอยู่กับหมายเลขซีเรียลของ CPU) ประเทศ WiFi ตั้งค่าเครือข่าย WiFi และวลีรหัสผ่าน; เปิด SSH แก้ไขปัญหาการตั้งค่าภาษาสำหรับเซสชัน SSH กำหนดค่าการบูทเข้าสู่คอนโซลโดยไม่ต้องล็อกอินอัตโนมัติ เขียนข้อมูลบางอย่างเกี่ยวกับระบบไปยังไฟล์บนพาร์ติชันสำหรับเริ่มระบบ และแน่นอนว่ามันจะลบ symlink นั้นออกไปดังนั้นมันจะไม่ทำงานอีกในตอนบูต

ผู้ใช้ส่วนใหญ่จะพบว่าไม่จำเป็นและต้องการใช้PiBakery , pi-init2หรือรูปภาพ ext4 ที่กำหนดเองซึ่งเป็นโซลูชันที่ยอดเยี่ยม ฉันชอบสิ่งนี้เพราะฉันสามารถเข้าใจได้อย่างเต็มที่และไม่ต้องเรียกใช้ซอฟต์แวร์อื่น และยังใช้งานได้: ด้วยไฟล์. img ที่ฉันใส่ไว้ในสคริปต์การกระพริบการ์ด SD ทั้งหมด + วางไว้ใน Pi + ปล่อยให้มันรันเพื่อกำหนดค่าตัวเองใช้เวลา 6 นาที

ที่มาฉันพบความคิดของสคริปต์เป็นinit=อาร์กิวเมนต์เคอร์เนลและmountคำสั่งที่จำเป็นเพื่อให้ทำงานในสคริปต์init_resize.shที่ทำงานตามค่าเริ่มต้นเพื่อปรับขนาดพาร์ติชัน Linux


2

คุณสามารถทำให้โค้ดถูกเรียกใช้งานโดย messing กับบรรทัดคำสั่งเคอร์เนล วิธีที่ชัดเจนที่สุดคือการแทนที่ init ด้วยวิธีอื่น แอปพลิเคชั่นที่พบบ่อยที่สุดของการทำเช่นนี้คือการเปิดตัวเชลล์ในช่วงต้น ๆ ของกระบวนการบู๊ตซึ่งโดยปกติจะเป็นเพราะคุณจำเป็นต้องแก้ไขบางสิ่งบางอย่าง

init=/bin/bash

โปรดทราบว่า ณ จุดนี้ในกระบวนการบูตระบบไฟล์ทั้งหมดยังคงติดตั้งเป็นแบบอ่านอย่างเดียว นอกจากนี้ยังมีสิ่งต่าง ๆ มากมายที่ไม่สามารถทำงานได้อย่างถูกต้อง เนื่องจากคุณไม่มีการเริ่มต้นใช้งานจริงการปิดและเริ่มต้นใหม่จะไม่ทำงาน คุณต้องติดตั้งระบบไฟล์รูทแบบอ่านอย่างเดียวและreboot -fทำการรีบูต

ฉันไม่รู้ว่าคุณสามารถส่งผ่านข้อโต้แย้งเพื่อทุบตีในลักษณะนี้ ฉันไม่เคยลอง ในทางทฤษฎีถ้าคุณสามารถส่งผ่าน-cไปยัง bash คุณสามารถบอกได้ว่ากระบวนการทุบตีนั้นจะทำอะไร แต่มันอาจกลายเป็นข้อโต้แย้งที่ค่อนข้างยาวและฉันไม่รู้ว่าเคอร์เนลจะอนุญาตสิ่งต่าง ๆ หรือไม่

สิ่งที่สองที่คุณสามารถทำได้ คุณสามารถคัดลอก ramfs ครั้งแรก (initramfs) เพื่อระบบแฟ้มและกำหนดค่า bootloader config.txtที่จะใช้ใน มีหลายวิธีในการทำให้สคริปต์เป็นแบบเริ่มต้นเพื่อทำสิ่งพิเศษ คุณจะต้องเตรียม initramfs พิเศษเพื่อจุดประสงค์นี้ (ดูที่ initramfs-tools (8)) ดังนั้นฉันไม่แน่ใจว่านี่เป็นวิธีที่ดีกว่าภาพที่กำหนดเองหรือไม่

คุณสามารถรวมสคริปต์ไว้ใน / boot (ฉันหัวเราะตามคำแนะนำของคุณเกี่ยวกับเครื่องจักร "ปกติ" แต่นี่จะเป็นบิตที่คุณสามารถเข้าถึงได้จากเครื่องเหล่านั้น) และพยายามเปิดใช้งานโดยใช้เคอร์เนลบรรทัด init แต่ไฟล์บนระบบไฟล์ DOS ไม่สามารถดำเนินการได้จนกว่าคุณจะทำเช่นนั้นสำหรับระบบไฟล์ทั้งหมด

ถ้าเป็นฉันฉันจะสร้างภาพที่กำหนดเองที่ใช้ 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 บังคับในระบบไฟล์ของฉันก่อนที่จะสร้างภาพ ตั้งค่าจำนวนเมานต์เป็นศูนย์ในการบู๊ตครั้งแรก :-)

แก้ไข : หลังจากหลายเดือนและประสบการณ์มากขึ้น คุณต้องการดู u-boot แทนที่ boot-loader ด้วย u-boot สามารถทำได้จาก "เครื่องปกติ" เมื่อคุณมี u-boot แล้วคุณสามารถเลือก network-boot จากการที่คุณสามารถ flash sd-card ได้อย่างง่ายดายหรือในทางทฤษฎีก็สามารถ flash การ์ดได้โดยตรง แต่ฉันก็ไม่รู้ว่ามันจะยากขนาดไหน

โดยพื้นฐานแล้ว u-boot จะนำเครือข่าย 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
Steve Robillard

1

เนื้อหาถ้าคุณตกลงกับการปรับเปลี่ยนภาพเพื่อเรียกใช้สคริปต์โดยอัตโนมัติในการบู๊ตครั้งแรกคุณสามารถแก้ไขภาพได้อย่างที่สคริปต์ของคุณต้องการจากนั้นบันทึก SD การ์ดนั้นลงในไฟล์ภาพแล้วใช้แฟลช การ์ด SD ที่คุณจะใช้กับ RPis ใหม่ ตัวอย่างเช่นหากคุณต้องการให้ RPis ทั้งหมดของคุณมีรายการบางอย่าง/etc/fstabคุณสามารถแก้ไขได้/etc/fstabเองแทนที่จะเขียนสคริปต์ที่ทำการแก้ไข

หากคุณต้องการแอ็คชั่นที่ใช้สคริปต์อย่างแน่นอน (เช่นถ้าแต่ละอิมเมจควรได้รับการแก้ไขด้วยวิธีที่แตกต่างกัน) คุณสามารถย้าย/etc/rc.localไปที่/etc/rc.bakและวางสคริปต์/etc/rc.localที่แทนที่ตัวเองด้วย/etc/rc.bakในคำสั่งสุดท้าย สคริปต์นั้นสามารถทำการบู๊ตแรกได้หรืออาจเรียกสคริปต์เฉพาะจาก/bootพาร์ติชั่นหากคุณต้องการ

มันเป็นไปได้ที่จะทำให้การทำงานอัตโนมัติโดยการสัมผัสเพียง/bootพาร์ทิชันโดยการจัดหาพิเศษภาพบูต ramdisk เคอร์เนลตามที่อธิบายไว้ที่นี่ config.txtภาพที่จะมีสคริปต์ในการปรับเปลี่ยนพาร์ทิชันรากแล้วตัวเองลบจาก ฉันไม่แน่ใจว่ามันคุ้มค่ากับปัญหาหรือไม่


-2

คุณอาจต้องการดู Nard โครงการของฉันซึ่งมีวิธีแก้ไขปัญหาของคุณ:

1) การ์ด SD แต่ละตัวสามารถกำหนด ID เฉพาะให้กับพีซี Windows ปกติดังที่อธิบายไว้ที่นี่:
http://www.arbetsmyra.dyndns.org/nard/#devsettingsid

2) เปิด Pis ของคุณทั้งหมด

3) ปิดการใช้งานไฟร์วอลล์พีซีถ้าเป็นไปได้

4) เปิดหน้าต่างพร้อมต์ของ DOS และ ping address subnet broadcast

5) รายการตาราง ARP ด้วยคำสั่ง Windows "arp -a" ในรายการคุณจะพบที่อยู่ MAC และ IP ของ Raspberry Pi ที่อยู่ใกล้เคียงทั้งหมด

6) เชื่อมต่อกับอุปกรณ์แต่ละเครื่องด้วย telnet (โดยปกติจะมีใน Windows ด้วย) วลีต้อนรับจะแสดง ID ที่กำหนดในขั้นตอนที่ 1


บางทีคำอธิบายเบื้องต้นของฉันอาจไม่ชัดเจนพอ ฉันไม่ได้กำลังมองหาวิธีการระบุตัวตนของ Pi โดยเฉพาะ ฉันมีที่ครอบคลุมแล้ว สิ่งที่ฉันกำลังมองหาคือการรันคำสั่ง bash หนึ่งคำสั่งหรือมากกว่าโดยการแก้ไขไฟล์ /boot/cmdline.txt ทั้งหมดนี้ไม่จำเป็นต้องเข้าสู่ระบบผ่านทาง ssh - แม้แต่ครั้งเดียว
EDP

คุณอาจจะไม่สามารถ 'ส่ง Ping ที่อยู่ Subnet Broadcast' โดยปกติแล้ว Smurf Attacks จะถูกป้องกัน
CrackerJack9
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.