กระบวนการ init สามารถเป็นเชลล์สคริปต์ใน Linux ได้หรือไม่


14

ฉันกำลังผ่านการสอนเกี่ยวกับการตั้งค่า initramfsที่กำหนดเองซึ่งระบุว่า:

สิ่งเดียวที่ขาดหายไปคือ / init ไฟล์เรียกทำงานในรูทของ initramfs ที่ถูกเรียกใช้โดยเคอร์เนลเมื่อโหลดแล้ว เนื่องจาก sys-apps / busybox มีเชลล์ที่ใช้งานได้อย่างสมบูรณ์ซึ่งหมายความว่าคุณสามารถเขียนไบนารี / init ของคุณเป็นเชลล์สคริปต์แบบง่าย ๆ (แทนที่จะทำให้มันเป็นแอพพลิเคชั่นที่ซับซ้อนที่เขียนใน Assembler หรือ C ที่คุณต้องรวบรวม)

และให้ตัวอย่างของ init เป็นเชลล์สคริปต์ที่ขึ้นต้นด้วย #!/bin/busybox sh

จนถึงตอนนี้ฉันอยู่ภายใต้การแสดงผลที่ init เป็นกระบวนการหลักที่เปิดตัวและกระบวนการพื้นที่ผู้ใช้อื่น ๆ ทั้งหมดเป็นลูกของ init ในที่สุด อย่างไรก็ตามในตัวอย่างที่กำหนดกระบวนการแรกนั้นจริง ๆ แล้วbin/busybox/ shซึ่ง init นั้นจะเกิดขึ้นในภายหลัง

นี่เป็นการรบกวนที่ถูกต้องหรือไม่? ตัวอย่างเช่นถ้าฉันมีล่ามที่มีอยู่ ณ ตอนนั้นฉันสามารถเขียน init เป็นสคริปต์ Python ได้หรือไม่?

คำตอบ:


12

init ไม่ใช่ "spawned" (เป็นกระบวนการลูก) แต่ควรเป็นexecเช่นนี้:

# Boot the real thing.
exec switch_root /mnt/root /sbin/init

execแทนที่กระบวนการทั้งหมดในสถานที่ การเริ่มต้นขั้นสุดท้ายยังคงเป็นกระบวนการแรก (pid 1) แม้ว่าจะนำหน้าด้วยการเริ่มต้นใน Initramfs

Initramfs /initซึ่งเป็นเชลล์สคริปต์ Busybox ที่มี pid 1, execไปที่ Busybox switch_root(ดังนั้นตอนนี้switch_rootคือ pid 1); โปรแกรมนี้มีการเปลี่ยนแปลงจุดติดของคุณเพื่อจะเป็นใหม่/mnt/root/

switch_rootแล้วอีกครั้งexecเพื่อ/sbin/initของระบบแฟ้มรากที่แท้จริงของคุณ ด้วยเหตุนี้มันทำให้ระบบเริ่มต้นที่แท้จริงของคุณเป็นกระบวนการแรกที่มี pid 1 ซึ่งจะส่งผลให้เกิดกระบวนการลูกจำนวนเท่าใดก็ได้

แน่นอนว่ามันสามารถทำได้ด้วยสคริปต์ Python ถ้าคุณสามารถอบ Python ลงใน Initramfs ของคุณได้ แม้ว่าคุณจะไม่ได้วางแผนที่จะรวม busybox ไว้ แต่คุณจะต้องพยายามปรับปรุงฟังก์ชั่นของมันใหม่ (เช่นswitch_rootและทุกอย่างที่คุณมักจะทำด้วยคำสั่งง่ายๆ)

อย่างไรก็ตามมันใช้ไม่ได้กับเมล็ดที่ไม่อนุญาตให้ใช้ไบนารีสคริปต์ ( CONFIG_BINFMT_SCRIPT=y) หรือในกรณีเช่นนี้คุณต้องเริ่มใช้ล่ามโดยตรงและทำให้โหลดสคริปต์ของคุณอย่างใด


/ไม่ได้หายไปในอากาศบาง - มันคือการติดตั้งมากกว่า( แต่มักจะเนื้อหาของมันจะถูกลบออกทั้งหมดก่อนก็คือการบันทึกความทรงจำ) มันเป็นยังคงมี switch_rootsyscall ทำอะไรswitchroot- ซึ่งเป็นสิ่งที่เคอร์เนล devs จัดไว้ให้เมื่อพวกเขาเปลี่ยนกระบวนการบูตในเคอร์เนล 2.6 บางสิ่งบางอย่างเพื่อต้องการ initramfs มันเป็นเคอร์เนลที่ทำเวทมนต์
mikeserv

1
switchrootsyscall แน่นอนจะเป็นข่าวกับผม คุณมีแหล่งที่มาสำหรับสิ่งนั้นหรือไม่? หากคุณดูซอร์สโค้ด switch_root.c ดูเหมือนว่าเป็นกระบวนการแบบแมนนวลและเหมือนกับที่อธิบายไว้ในเอกสาร / filesystems / ramfs-rootfs-initramfs.txt นอกจากนี้หากคุณลบทุกอย่างแล้วติดตั้งมันก็หายไปมากในตอนนี้คุณไม่คิดเหรอ?
frostschutz

pivot_rootในทางตรงกันข้ามเป็นตึกระฟ้า มันไม่ได้ใช้สำหรับswitch_rootและไม่สามารถใช้งานได้โดยไม่ต้องกระโดดข้ามห่วงและไม่ว่าจะด้วยวิธีใดมันก็ไม่มีความสำคัญสำหรับคำตอบนี้ดังนั้นฉันจึงลบมันออกไปโดยสิ้นเชิง น่าเสียดายที่ฉันคิดว่าเวทมนตร์และหายตัวไปในอากาศบาง ๆ ทำงานได้ดีจริงๆ ... :-P
frostschutz

บางทีฉันอาจมีความคิดที่ผิดเกี่ยวกับswitch_root- ซึ่งฉันขอโทษและฉันขอขอบคุณที่แสดงให้ฉัน - แต่มันก็ไม่หายอะไรเลย initramfs root ยังคงอยู่และมีอยู่เสมอสำหรับทุกคน - มันเป็น root
mikeserv

1
ในฐานะที่เป็นเอกสารที่คุณเชื่อมโยงเพื่อพูดว่า : แต่ initramfs เป็น rootfs: คุณไม่สามารถ pivot_root rootfs หรือเลิกเมานท์ได้ แทนที่จะลบทุกอย่างออกจาก rootfs เพื่อเพิ่มพื้นที่ ( find -xdev / -exec rm '{}' ';'), overmount rootfs ด้วย root ใหม่ ( cd /newmount; mount --move . /; chroot .), แนบ stdin / stdout / stderr ไปที่ใหม่ / dev / console และเรียกใช้ init ใหม่
mikeserv

4

exec syscall ของเคอร์เนลลินุกซ์ช่วยลดค่าได้

เมื่อไฟล์ที่เรียกใช้งานเริ่มต้นด้วยมายากลไบต์#!พวกเขาบอกเคอร์เนลให้ใช้#!/bin/shเป็น:

  • ทำและexecเรียกระบบ
  • ด้วยปฏิบัติการ /bin/sh
  • และด้วยอาร์กิวเมนต์ CLI: พา ธ ไปยังสคริปต์ปัจจุบัน

สิ่งนี้เป็นสิ่งเดียวกันกับที่เกิดขึ้นเมื่อคุณรันเชลล์สคริปต์ userland ปกติด้วย:

./myscript.sh

หากไฟล์เริ่มต้นด้วยเมจิกไบต์.ELFแทน#!เคอร์เนลจะเลือกตัวโหลดเอลฟ์แทนเพื่อเรียกใช้

รายละเอียดเพิ่มเติมที่: ทำไมผู้คนเขียน #! / usr / bin / env python shebang ในบรรทัดแรกของสคริปต์ Python | กองล้นมากเกินไป

เมื่อคุณมีสิ่งนี้อยู่ในใจมันจะง่ายต่อการยอมรับว่า/initสามารถเป็นอะไรก็ได้ที่เคอร์เนลสามารถเรียกใช้งานรวมถึงเชลล์สคริปต์และทำไม/bin/shไฟล์แรกที่สามารถเรียกใช้งานได้ในกรณีนั้น

นี่คือตัวอย่างเล็ก ๆ ที่รันได้สำหรับผู้ที่ต้องการลองใช้: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/cbea7cc02c868711109ae1a261d01fd0473eea0b#custom-init

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