Sử dụng /boot/cmdline.txt để tạo tập lệnh khởi động đầu tiên


11

Nhiều câu hỏi đã được hỏi về cách tìm Pi của tôi trên mạng của tôi . Những người khác - bao gồm cả bản thân tôi - gặp vấn đề tốn thời gian trong khi cố gắng triển khai một loạt Pi mới.

Mặc dù việc tạo ra các hình ảnh tùy chỉnh có thể là một giải pháp cho những vấn đề này, tôi tự hỏi liệu có giải pháp nào khác không.

Với (chỉ) /bootthư mục mở để truy cập trên các máy thông thường (Win / OSX), liệu có thể sử dụng /boot/cmdline.txtđể chuyển văn bản thành tập lệnh bash, chạy và xóa nó sau đó không?


1
Câu hỏi này đang được thảo luận trên Meta . Tôi muốn nghe ý kiến ​​của bạn, nếu có thể. Cảm ơn.
Thomas Weller

Câu trả lời:


5

Tôi đã tạo một phiên bản Raspberian-light được sửa đổi nhẹ để đáp ứng nhu cầu này - nó thực thi tập lệnh /boot/firstboot.sh tùy chỉnh của bạn trong lần khởi động đầu tiên:

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


Cảm ơn! 4 năm sau OP cuối cùng cũng có một giải pháp tốt. Không phải khoa học tên lửa đặc biệt để tự xây dựng nó, nhưng bạn sẽ ở trong nhiều giờ mỗi khi có một bản phát hành mới. IMHO này nên được thêm vào phần sụn chính.
EDP

2

Bạn có thể khiến mã được thực thi bằng cách làm rối với dòng lệnh kernel. Phương pháp rõ ràng nhất là thay thế init bằng thứ khác. Ứng dụng phổ biến nhất của việc này là khởi chạy shell rất sớm trong quá trình khởi động, thường là do bạn cần sửa một cái gì đó hoặc vì mọi thứ khác bị hỏng rất nặng, ví dụ:

init=/bin/bash

Hãy nhớ rằng tại thời điểm này trong quá trình khởi động, các hệ thống tập tin vẫn được gắn kết chỉ đọc. Ngoài ra, có cả đống thứ không hoạt động chính xác. Bởi vì bạn không có init thực sự đang chạy, tắt máy và khởi động lại sẽ không hoạt động. Bạn phải truy xuất thủ công hệ thống tập tin gốc chỉ đọc và gọi reboot -fđể khởi động lại, ví dụ.

Tôi không biết nếu bạn có thể truyền đối số cho bash theo cách này. Tôi chưa bao giờ thử. Về lý thuyết, nếu bạn có thể chuyển -csang bash, bạn có thể nói rằng quá trình bash đó để làm bất cứ điều gì. Nhưng nó có thể biến thành một cuộc tranh luận khá dài và tôi không biết liệu kernel có cho phép những thứ đó không.

Điều thứ hai bạn có thể làm. Bạn có thể sao chép một ramfs ban đầu (initramfs) vào hệ thống tập tin và cấu hình bộ tải khởi động để sử dụng nó config.txt. Có một số cách để đưa các tập lệnh vào một initramfs để làm những điều đặc biệt. Tuy nhiên, bạn sẽ phải chuẩn bị một initramfs đặc biệt cho mục đích này (xem initramfs-tools (8)), vì vậy tôi không chắc đây có phải là giải pháp tốt hơn hình ảnh tùy chỉnh hay không.

Bạn có thể bao gồm tập lệnh in / boot (Tôi đã cười theo gợi ý của bạn về các máy "thông thường", nhưng đây sẽ là bit bạn có thể truy cập từ các máy đó) và cố gắng khởi chạy bằng cách sử dụng dòng init kernel, nhưng các tệp trên hệ thống tập tin dos Không thể thực thi trừ khi bạn làm như vậy cho toàn bộ hệ thống tập tin.

Nếu là tôi, tôi sẽ tạo một hình ảnh tùy chỉnh sử dụng dhcp để định cấu hình mạng và chứa tập lệnh tùy chỉnh chạy khi khởi động. Kịch bản lệnh này kiểm tra một tệp cụ thể hoạt động như một cờ. Nếu tập tin tồn tại, không làm gì cả. Nếu không, cấu hình mọi thứ, sau đó tạo tệp cờ.

Tập lệnh cấu hình của bạn thậm chí có thể lấy dữ liệu thật từ máy chủ http. Điều này có nghĩa là bạn không phải tạo một hình ảnh mới nếu bạn phải chỉnh sửa một cái gì đó.

Đó nên là giải pháp ít căng thẳng nhất.

Một khả năng cuối cùng, nhưng bạn sẽ phải thực hiện điều này trên máy "không thường xuyên" :-) Bạn có thể gắn hệ thống tệp ext4 vào thiết bị lặp và sao chép tệp vào đó mà không cần ghi vào sdcard trước. Đối với một hình ảnh Jessie Raspbian tiêu chuẩn, nó sẽ giống như thế này:

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

Tôi thích làm một fsck bắt buộc trên các hệ thống tập tin của tôi trước khi tạo hình ảnh. Đặt số lần gắn kết về 0 trong lần khởi động đầu tiên :-)

EDIT : Sau nhiều tháng và nhiều kinh nghiệm. Bạn muốn nhìn vào u-boot. Thay thế bộ tải khởi động bằng u-boot. Điều này có thể được thực hiện từ một "máy thông thường". Khi bạn đã có u-boot, bạn có thể khởi động mạng một bản phân phối mà từ đó bạn có thể dễ dàng flash thẻ sd, hoặc về lý thuyết bạn có thể flash thẻ trực tiếp, mặc dù tôi không biết điều đó sẽ khó đến mức nào.

Về cơ bản, u-boot mang lại khả năng khởi động mạng cho Raspberry Pi, một thứ mà nó không hỗ trợ.


Ok, hệ thống tập tin chỉ đọc ở giai đoạn đó. Thế còn init=script & init? Kịch bản sẽ chạy trong nền trong khi init khởi động bình thường. Kịch bản sẽ cần một số điều kiện kiểm tra lúc đầu và ví dụ như tiếp tục khi init hoàn thành công việc.
Thomas Weller

1
Sử dụng & để làm nền một cái gì đó là một điều vỏ. Trừ khi bạn bảo kernel chạy một lệnh cụ thể trong shell (ví dụ: bash -c "một số lệnh & lệnh khác") sẽ không hoạt động và tôi đã nghĩ rằng đây là một ý tưởng tồi. Nhưng tôi đã mở rộng câu trả lời của mình và thêm tùy chọn u-boot, một thứ tôi phát hiện ra gần đây.
izak

1
Chỉ cần thử xong ;-) Không, nó thực sự không hoạt động
Thomas Weller

2

Đối với những người thích một giải pháp chỉ liên quan đến các tập lệnh được thả vào phân vùng khởi động FAT32 , đây là cách thực hiện. [ Chỉnh sửa: Các tệp hiện có sẵn trong tập lệnh pi-boot-script .]

Như đã đề cập trong các câu trả lời khác, nó liên quan đến các đối số dòng lệnh mà hạt nhân Linux được khởi động. Các đối số đó nằm trong /boot/cmdline.txt .

Tôi đã thử nghiệm điều này trên Raspbian Buster (v10.1) 2019-09-26. Nó hoạt động trên thẻ SD mới được flash hoặc trên hình ảnh đĩa .img đã tải xuống , sau đó bạn có thể flash vào bất kỳ số lượng thẻ SD nào.

1. Chỉnh sửa các đối số kernel

Mở tệp văn bản /boot/cmdline.txt , xóa bất kỳ init=phần nào khỏi nó và thêm phần này vào cuối dòng:

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

Từ cuối cùng trên dòng này là tên của tập lệnh được chạy bởi kernel là tiến trình đầu tiên (PID = 1) thay vì / sbin / init . Các kernel-đối số trang trợ giúp nói chỉ lập luận mà không .có được thông qua vào init thực thi, vì vậy bạn không thể gọi kịch bản unattended.sh hoặc những thứ tương tự.

2. Đặt tập lệnh vào phân vùng khởi động

Lưu phần sau vào phân vùng khởi động dưới dạng / không giám sát (tên bạn đặt trong dòng lệnh):

# 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

Kịch bản này thực hiện một số chuẩn bị cần thiết (chương 1), sau đó bất cứ điều gì bạn muốn làm (2), sau đó dọn dẹp và khởi động lại (3). Thay thế các công cụ dưới 2 bằng các lệnh bạn muốn chạy.

Đối với một số tác vụ cấu hình, có lẽ bạn cần khởi động bình thường để kết nối mạng và các dịch vụ khác, vì vậy ví dụ trong phiên bản này (được giải thích bên dưới) chỉ chuẩn bị cho một tập lệnh thích hợp để chạy khi Pi khởi động lại.

3. Đặt bất kỳ tệp nào khác mà tập lệnh của bạn cần vào phân vùng khởi động

...chắc chắn.

Thí dụ

Cùng với tập lệnh của tôi, tôi đặt một tải trọng thư mục / trên phân vùng khởi động, chứa các tệp tôi muốn chuyển sang phân vùng Linux. Trong kịch bản không giám sát ở trên,

  • dòng A di chuyển các tập tin vào thư mục pi-user. Ví dụ: payload / home / pi / .bashrc được chuyển vào hệ thống tập tin gốc dưới dạng /home/pi/.bashrc ;
  • dòng B di chuyển các tệp thuộc sở hữu gốc vào phân vùng Linux, bao gồm payload / usr / local / bin / one-time-script.sh trở thành /usr/local/bin/one-time-script.sh và tương tự cho tải trọng / lib / systemd / system / one-time-script.service ;
  • dòng C sau đó tạo một liên kết tượng trưng đến tệp cuối cùng đó, vì vậy tập lệnh cấu hình của tôi one-time-script.sh được chạy ở lần khởi động tiếp theo.

Kịch bản đó thực hiện nhiều tùy chỉnh khác nhau mà tôi thích: nó tạo và định dạng một phân vùng FAT32 khác và thêm nó vào / etc / fstab để người dùng pi có thể ghi vào nó (cho nhật ký ứng dụng, v.v.); thay đổi kích thước phân vùng & hệ thống tập tin ext4 thành phần còn lại của thẻ SD; thay đổi miền địa phương, múi giờ, tên máy chủ (dựa trên số sê-ri CPU), quốc gia WiFi; đặt mạng WiFi và cụm mật khẩu; bật SSH; khắc phục sự cố cài đặt ngôn ngữ cho các phiên SSH; cấu hình khởi động vào bàn điều khiển mà không cần đăng nhập tự động; ghi một số dữ liệu về hệ thống vào một tệp trên phân vùng khởi động; và tất nhiên nó sẽ loại bỏ liên kết tượng trưng đó để nó không chạy lại khi khởi động.

Hầu hết người dùng sẽ thấy điều này không cần thiết và thích sử dụng PiBakery , pi-init2 hoặc hình ảnh ext4 tùy chỉnh, là những giải pháp tuyệt vời. Tôi thích điều này bởi vì tôi hoàn toàn có thể hiểu nó và tôi không phải chạy phần mềm khác. Và nó cũng hoạt động: với tệp .img tôi đã đặt tập lệnh của mình vào, tất cả việc flash thẻ SD + đặt nó vào Pi + để cho nó chạy để tự cấu hình mất 6 phút.

Nguồn Tôi tìm thấy ý tưởng của một tập lệnh làm init=đối số kernel và các mountlệnh cần thiết để làm cho nó hoạt động, trong tập lệnh init_resize.sh chạy theo mặc định để thay đổi kích thước phân vùng Linux.


1

Tôi không khuyên bạn nên chạm vào bất cứ thứ gì trong khu vực khởi động ( config.txttrừ khi) trừ khi bạn có hiểu biết chi tiết về những gì công cụ đó đang làm. cmdline.txtkhông được thiết kế để chạy mọi thứ khi RPi bắt đầu. Nó được sử dụng để truyền tham số cho kernel Linux khi khởi động.

Tôi sẽ đề nghị làm tất cả điều này thông qua SSH. Một tập lệnh trên máy tính để bàn của bạn có thể đẩy một bash / python / java / c / bất cứ chương trình nào lên RPi, thực thi nó và sau đó xóa nó khi nó kết thúc. Thêm luồng vào tập lệnh trên máy tính để bàn của bạn và bạn có thể gửi nó ra nhiều thiết bị như bạn muốn cùng một lúc.


1
Đó là cách chúng tôi làm bây giờ nhưng tôi đang tìm kiếm một giải pháp dễ dàng hơn.
EDP

1
Đọc: chạy thiết lập do khách hàng khởi tạo thay vì khởi tạo máy chủ
EDP

@EDP: không có cách nào để có được thứ bạn muốn chỉ bằng cách chỉnh sửa vị trí khởi động. Bạn có thể viết một tập lệnh kéo tệp từ máy chủ trong lần khởi động đầu tiên của RPi và sau đó yêu cầu chương trình đó xóa tập lệnh khởi động. Điều đó sẽ yêu cầu bạn sử dụng một hình ảnh tùy chỉnh.
Jacobm001

1
"Một tập lệnh trên máy tính để bàn của bạn" - Tập lệnh nào trên máy tính để bàn của tôi? Ở lần khởi động đầu tiên, không có tập lệnh nào trên Desktop. "Thực hiện tất cả thông qua SSH" - ở lần khởi động đầu tiên, Pi có thể không có cài đặt Ethernet hoặc WLAN chính xác.
Thomas Weller

Bạn thậm chí không cần luồng kiểm tra dự án vải. Phần mềm tái lập duy nhất của nó là SSH
Steve Robillard

1

Có thể cho rằng, nếu bạn ổn với việc sửa đổi hình ảnh để tự động chạy tập lệnh ở lần khởi động đầu tiên, bạn có thể chỉ cần sửa đổi hình ảnh theo cách tập lệnh của bạn, sau đó lưu thẻ SD đó vào tệp hình ảnh và sử dụng nó để flash Thẻ SD bạn sẽ sử dụng với RPis mới. Ví dụ: nếu bạn muốn tất cả RPis của mình có một mục nhất định /etc/fstab, bạn có thể chỉ cần sửa đổi /etc/fstabchính nó thay vì viết một tập lệnh thực hiện sửa đổi.

Nếu bạn thực sự cần các hành động theo kịch bản (ví dụ: nếu mỗi hình ảnh nên được sửa đổi theo một cách khác nhau), bạn có thể di chuyển /etc/rc.localđến /etc/rc.bakvà đặt một tập lệnh /etc/rc.localthay thế chính nó /etc/rc.baktrong lệnh cuối cùng. Tập lệnh đó có thể tự thực hiện các hành động khởi động đầu tiên hoặc nó có thể gọi một tập lệnh cụ thể từ /bootphân vùng nếu bạn thích.

Bạn có thể tự động chạy bằng cách chỉ chạm vào /bootphân vùng, bằng cách cung cấp hình ảnh ramdisk khởi động đặc biệt cho kernel như được mô tả ở đây . Hình ảnh đó sẽ chứa các tập lệnh để sửa đổi phân vùng gốc và sau đó tự xóa từ đó config.txt. Tôi không chắc chắn nếu nó có giá trị rắc rối mặc dù.


-2

Bạn có thể muốn xem Nard dự án của tôi có giải pháp cho vấn đề của bạn:

1) Mỗi ​​thẻ SD có thể được chỉ định một ID duy nhất với PC Windows thông thường như được mô tả tại đây:
http://www.arbetsmyra.dyndns.org/nard/#devsinstallid

2) Bật nguồn cho tất cả Pis của bạn

3) Vô hiệu hóa tường lửa PC nếu có thể

4) Mở cửa sổ nhắc DOS và ping địa chỉ quảng bá mạng con

5) Liệt kê bảng ARP bằng lệnh Windows "arp -a". Trong danh sách, bạn sẽ tìm thấy địa chỉ MAC và IP của tất cả Raspberry Pi gần đó.

6) Kết nối với từng thiết bị bằng telnet (thường có sẵn trong Windows). Cụm từ chào mừng sẽ hiển thị ID được chỉ định trong bước 1.


Có lẽ mô tả ban đầu của tôi không đủ rõ ràng. Tôi không đặc biệt tìm cách xác định Pi. Tôi đã có điều đó được bảo hiểm. Những gì tôi đang tìm kiếm là chạy một hoặc nhiều lệnh bash bằng cách thay đổi tệp /boot/cmdline.txt. Tất cả điều này mà không cần đăng nhập qua ssh - thậm chí một lần.
EDP

Bạn có thể sẽ không thể 'ping địa chỉ quảng bá mạng con', các cuộc tấn công Smurf thường bị ngăn chặn.
CrackerJack9
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.