1 คะแนน โดย GN⁺ 2 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • 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/busybox
    docker 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_main
    int 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 ความคิดเห็น

 
GN⁺ 2 시간 전
ความคิดเห็นจาก Lobste.rs
  • คำตอบของคำถามที่อ้างอิงมานั้นใกล้เคียงกับคำว่า การนำมาเขียนใหม่ มากกว่า
    คำแนะนำเกี่ยวกับ BusyBox อยู่ที่ https://busybox.net/about.html และซอร์สอยู่ที่ https://github.com/vda-linux/busybox_mirror

  • ค่อนข้างน่าหงุดหงิดที่โปรแกรมแกล้งทำเป็นว่าตัวเองมีชื่ออย่างหนึ่งทั้งที่จริงไม่ใช่
    กรณีแย่ที่สุดคือบน macOS ที่รัน gcc แล้วจริง ๆ กลับได้ clang ออกมา และ PowerShell ก็ทำงานคล้าย ๆ กัน น่าจะใช้ชื่ออื่นไปเลยจะดีกว่า

    • ปัญหานี้ส่วนหนึ่งก็เกิดจากการที่เริ่มต้นขึ้นในยุคที่นักพัฒนาจำนวนมากไม่รู้จัก clang, ไม่มี Mac สำหรับทดสอบ หรือไม่มีทางเลือกที่ใช้งานได้จริง
      Nixpkgs ต้องใส่แพตช์จำนวนมากอย่างเช่น https://github.com/NixOS/nixpkgs/… และแม้แต่โปรเจ็กต์ดังอย่าง sqlite ก็ไม่ใช่ข้อยกเว้น ขณะที่ macOS เหมือนเลือกเส้นทางแบบ หลอกกันไปก่อน
    • คนที่เขียน makefile ของซอฟต์แวร์จำนวนมากมีไม่น้อยที่ไม่รู้จัก cc
    • เข้าใจความอัดอั้นนั้น แต่ถ้ามัน เข้ากันได้มากพอ ที่จะรันสคริปต์ build ส่วนใหญ่ได้ ก็มีความเป็นไปได้สูงว่านี่คือเหตุผลที่มันแพร่หลาย เพราะทำให้เอาสคริปต์เดียวกันมาใช้ซ้ำได้ในระดับหนึ่งทั้งบน Linux และ Unix หลายตระกูล
    • บางครั้งมันก็เป็นไปไม่ได้ในทางปฏิบัติ
      น่าจะมี 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 เดิมถูกสร้างขึ้นมาเป็น ทางเลือกภายใต้ไลเซนส์ BSD ของ BusyBox ที่ใช้ GPL
      เพิ่มเติมคือ 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 นั้นย้อนกลับมาทำร้ายตัวเองได้อย่างไร
      ยิ่งคิดถึงเรื่องที่ Google ขู่จะปิดกั้น Termux มานานหลายปี ก็ยิ่งใช่เลย
  • มีพอร์ตสำหรับ Windows ด้วย: https://github.com/rmyorston/busybox-w32
    ขนาดที่เล็กของ BusyBox ทำให้การพอร์ตแบบนี้เป็นเรื่องที่เป็นไปได้มากกว่า เพียงแต่ตอนนี้ดูเหมือนความเกี่ยวข้องจะลดลงไปบ้างแล้ว เพราะบน Windows สามารถรัน Linux ได้ตรง ๆ อยู่แล้ว