BusyBox คืออะไร?
(specular.fi)- BusyBox คือ มัลติคอลไบนารี ที่รวมหลายคำสั่งไว้ในไฟล์รันไฟล์เดียว โดย
wgetเริ่มต้นของ Alpine ก็ทำงานผ่าน BusyBox เช่นกัน /usr/bin/wgetในคอนเทนเนอร์ Alpine ไม่ใช่ไบนารีจริง แต่เป็น ลิงก์เชิงสัญลักษณ์ ที่ชี้ไปยัง/bin/busybox- เมื่อ BusyBox ทำงาน มันจะอ่านชื่อที่ถูกเรียกจาก
argv[0]และเลือก แอปเพล็ต ที่จะรันจากชื่อสุดท้ายของพาธ - แต่ละแอปเพล็ตจะถูกค้นหาด้วยชื่อและเข้าสู่ฟังก์ชัน
mainที่เกี่ยวข้อง โดยwgetถูกอิมพลีเมนต์ไว้ในwget.cและสุดท้ายจะรันwget_main - สามารถดูคำสั่งที่ถูกคอมไพล์รวมไว้ได้ด้วย
busybox --listและในตัวอย่างของ Alpine แสดง 304 รายการ โดยยูทิลิตีแต่ละตัวดูเหมือนเป็นเวอร์ชันที่ย่อขนาดลง
วิธีการทำงานของ BusyBox
- BusyBox ใช้โครงสร้าง มัลติคอลไบนารี (multicall binary) ที่ให้หลายคำสั่งทำงานผ่านไฟล์รันไฟล์เดียว
- ในคอนเทนเนอร์ Alpine นั้น
/usr/bin/wgetไม่ใช่ไฟล์รันจริง แต่เป็น ลิงก์เชิงสัญลักษณ์ ที่ชี้ไปยัง/bin/busyboxdocker run --rm -it alpine sh / # which wget /usr/bin/wget / # ls -lah /usr/bin/wget lrwxrwxrwx 1 root root 12 Apr 15 04:51 /usr/bin/wget -> /bin/busybox - ใน
/usr/binจะเห็นไฟล์รันมากกว่า 130 รายการที่ดูเหมือนออกมาจากไบนารีตัวเดียว ซึ่งเชื่อมโยงกับโครงสร้างมัลติคอลไบนารีของ BusyBox - เมื่อเริ่มทำงาน BusyBox จะดึงชื่อที่ถูกเรียกจาก
argv[0]แล้วตัดเอาเฉพาะชื่อท้ายสุดของพาธเพื่อใช้ตัดสินใจว่าจะรัน แอปเพล็ต (applet) ใดapplet_name = argv[0]; if (applet_name[0] == '-') applet_name++; applet_name = bb_basename(applet_name); - มันยังทำงานได้เมื่อส่งชื่อแอปเพล็ตมาแบบชัดเจน เช่น
busybox ls -1และถ้าส่งชื่อที่ไม่มีอยู่ จะขึ้นข้อความapplet not found/ # busybox ls -1 bin dev etc home / # busybox meheh meheh: applet not found
โครงสร้างแอปเพล็ตและวิธีติดตั้ง
- BusyBox จะค้นหาแอปเพล็ตตามชื่อก่อน แล้วจึงเรียกใช้ฟังก์ชัน
mainของแอปเพล็ตนั้นint applet = find_applet_by_name(name); // ... run_applet_no_and_exit(applet, name, argv); // ... xfunc_error_retval = applet_main[applet_no](argc, argv); - แอปเพล็ตแต่ละตัวมีไฟล์ C แยกของตัวเอง และ
wgetถูกอิมพลีเมนต์อยู่ในwget.c - การตั้งค่าของแต่ละแอปเพล็ตถูกกำหนดไว้ในรูปคอมเมนต์ของโค้ด โดยการตั้งค่า
WGETมีข้อมูลwget (41 kb), เปิดใช้งานเป็นค่าเริ่มต้น, คำอธิบายว่าเป็นยูทิลิตีสำหรับดาวน์โหลดไฟล์แบบไม่โต้ตอบจากเซิร์ฟเวอร์ HTTP และ FTP และมีเป้าหมายการบิลด์เป็นwget.o//config:config WGET //config: bool "wget (41 kb)" //config: default y //config: help //config: wget is a utility for non-interactive download of files from HTTP //config: and FTP servers. //applet:IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_WGET) += wget.o - ในท้ายที่สุด แอปเพล็ต
wgetจะเข้าสู่wget_mainint wget_main(int argc UNUSED_PARAM, char **argv) - BusyBox รองรับฮาร์ดลิงก์ด้วย และใน
busybox --install -sนั้น-sหมายถึงการสร้าง ลิงก์เชิงสัญลักษณ์busybox --install -s - สามารถดูรายการคำสั่งที่รวมอยู่ในการคอมไพล์ได้ด้วย
busybox --listและในสภาพแวดล้อมตัวอย่างของ Alpine แสดง 304 รายการ/ # busybox --list | wc -l 304 - คำสั่งหลายตัวของ Alpine ทำงานเสมือนเป็นอินเทอร์เฟซไปยังไบนารีที่อิงกับ BusyBox และยูทิลิตีแต่ละตัวก็ดูเหมือนเป็น เวอร์ชันที่ย่อขนาดลง เมื่อเทียบกับยูทิลิตีต้นฉบับแบบเต็ม
1 ความคิดเห็น
ความคิดเห็นจาก Lobste.rs
คำตอบของคำถามที่อ้างอิงมานั้นใกล้เคียงกับคำว่า การนำมาเขียนใหม่ มากกว่า
คำแนะนำเกี่ยวกับ BusyBox อยู่ที่ https://busybox.net/about.html และซอร์สอยู่ที่ https://github.com/vda-linux/busybox_mirror
ค่อนข้างน่าหงุดหงิดที่โปรแกรมแกล้งทำเป็นว่าตัวเองมีชื่ออย่างหนึ่งทั้งที่จริงไม่ใช่
กรณีแย่ที่สุดคือบน macOS ที่รัน
gccแล้วจริง ๆ กลับได้ clang ออกมา และ PowerShell ก็ทำงานคล้าย ๆ กัน น่าจะใช้ชื่ออื่นไปเลยจะดีกว่าNixpkgs ต้องใส่แพตช์จำนวนมากอย่างเช่น https://github.com/NixOS/nixpkgs/… และแม้แต่โปรเจ็กต์ดังอย่าง sqlite ก็ไม่ใช่ข้อยกเว้น ขณะที่ macOS เหมือนเลือกเส้นทางแบบ หลอกกันไปก่อน
ccน่าจะมี makefile จำนวนมากที่ฮาร์ดโค้ด
gccไว้ และในบริบทอื่นก็คล้ายกัน เช่น โปรแกรมเก่าจำนวนมากตรวจxterm-*ของตัวแปรแวดล้อมTERMแทนที่จะใช้ฐานข้อมูลterminfoซึ่งเป็นวิธีที่ถูกต้อง ดังนั้น การเลือกชื่ออื่นจึงใช้ไม่ได้ผลเวลาวินิจฉัยปัญหาแปลก ๆ ในคอนเทนเนอร์ มักจะใช้
podman cp /usr/bin/busybox-static somecontainer:/binบ่อย ๆtoybox ก็มีโครงสร้างคล้ายกัน
เครื่องมือบางส่วนดูเหมือนจะนำมาจากที่อื่นหรือพอร์ตมาจากโครงการอื่น แต่จำนวนมากก็ถูกเขียนขึ้นใหม่สำหรับ BusyBox โดยมีเป้าหมายให้เล็ก และใช้ฟังก์ชันของ libc เท่าที่จำเป็นเพื่อให้คอมไพล์แบบ static link แล้วมีขนาดเล็ก อีกข้อดีหนึ่งคือสามารถใช้เครื่องมือเหล่านี้จากเชลล์สคริปต์ราวกับเป็นคำสั่ง built-in ได้ บางตัวรันแบบ fork+jump แทน fork+exec และบางตัวก็รันได้ด้วยการเรียกฟังก์ชันปกติโดยไม่ต้อง fork เลย
เพิ่มเติมคือ Toybox on Wikipedia ระบุว่า “Toybox เริ่มต้นในช่วงต้นปี 2006 หลังจากที่ Rob Landley ถอนตัวจากบทบาทผู้ดูแล BusyBox เพราะข้อพิพาทกับ Bruce Perens ผู้สร้าง BusyBox ดั้งเดิม”
ในทางปฏิบัติมันคือ การนำมาเขียนใหม่ นั่นแหละ แม้ว่าถ้าไลเซนส์อนุญาต ก็ไม่น่าแปลกใจถ้าจะยืมโค้ดบางส่วนมาจากอิมพลีเมนเตชันขนาดใหญ่ดั้งเดิม
From the 'pedia: ตามนั้น BusyBox ถูกเขียนขึ้นครั้งแรกโดย Bruce Perens ในปี 1995 และถูกประกาศว่าเสร็จสมบูรณ์สำหรับวัตถุประสงค์ที่ตั้งใจไว้ในปี 1996 เป้าหมายแรกเริ่มคือสร้างระบบที่บูตได้สมบูรณ์ซึ่งทำหน้าที่เป็นทั้งดิสก์กู้คืนและตัวติดตั้งของดิสทริบิวชัน Debian ให้ยัดลงในฟลอปปีดิสก์แผ่นเดียวได้ หลังจากนั้นมันก็ขยายตัวจนกลายเป็นชุดเครื่องมือ user space หลักโดยพฤตินัยสำหรับอุปกรณ์ Linux แบบฝังตัวและตัวติดตั้งดิสทริบิวชัน Linux เนื่องจากไฟล์รันแต่ละตัวบน Linux ต้องมีโอเวอร์เฮดหลาย KB การรวมโปรแกรมมากกว่า 200 ตัวเข้าไว้ในไฟล์เดียวจึงช่วยประหยัดทั้งพื้นที่ดิสก์และหน่วยความจำได้มาก
ที่เกี่ยวข้องกัน Toybox ก็มีโครงสร้างและปรัชญาคล้ายกันแต่ใช้ไลเซนส์ BSD จำได้ว่าผู้พัฒนาหลัก Rob Landley มองว่า ถ้าใช้ไลเซนส์ที่ภาคธุรกิจยอมรับได้ง่าย ก็มีโอกาสถูกใส่เข้าไปในอุปกรณ์ Android และถ้าเป็นเช่นนั้น โทรศัพท์และแท็บเล็ต Android ทุกเครื่องก็อาจเปลี่ยนเป็นสภาพแวดล้อมพัฒนาแบบคล้าย Unix ได้ทั้งหมด ดูเหมือนว่า Toybox จะยังเป็นส่วนหนึ่งของ Android อยู่ แต่ถ้าไม่มีเครื่องมือชั้นบนอย่าง Termux มาช่วย Android ก็ยังไม่ง่ายที่จะใช้งานแบบ Unix
ยิ่งคิดถึงเรื่องที่ Google ขู่จะปิดกั้น Termux มานานหลายปี ก็ยิ่งใช่เลย
มีพอร์ตสำหรับ Windows ด้วย: https://github.com/rmyorston/busybox-w32
ขนาดที่เล็กของ BusyBox ทำให้การพอร์ตแบบนี้เป็นเรื่องที่เป็นไปได้มากกว่า เพียงแต่ตอนนี้ดูเหมือนความเกี่ยวข้องจะลดลงไปบ้างแล้ว เพราะบน Windows สามารถรัน Linux ได้ตรง ๆ อยู่แล้ว