Chính xác thì init làm gì?


43

Tôi đang tạo một bản phân phối linux và bây giờ tôi cần một chương trình init. Tôi có thể viết mã trong c rất tốt và tôi biết khá nhiều về linux (không nhiều nhưng tôi đã sử dụng arch linux để phát triển được 4 năm), vì vậy tôi nghĩ tôi nên thử viết script init cơ bản của riêng mình trong C. Tôi đã chỉ tự hỏi, init làm những nhiệm vụ gì để thiết lập hệ thống cho một shell đơn giản? (Khi tôi hỏi "init làm gì?", Tôi biết init là gì và để làm gì. Tôi chỉ không biết nó làm nhiệm vụ gì.)

Tôi không cần mã và tôi có thể thậm chí không cần lệnh cơ bản nhưng tôi làm cần theo thứ tự mà họ đang chạy trong.


1
Bạn có thể sử dụng bất kỳ trình thông dịch nào bạn thích cho các tập lệnh init kiểu SysV, bao gồm Perl, awk, bash, (t) csh, nhị phân riêng, ... Bash thường được sử dụng vì nó hầu như được đảm bảo có sẵn trên hệ thống nơi các tập lệnh như vậy được triển khai tại điểm có liên quan trong quá trình khởi động, không phải vì có một số khớp nối giữa SysVinit và bash. SysVinit định nghĩa hợp đồng và mỗi tập lệnh được tự do thực hiện hợp đồng đó theo bất kỳ cách nào mà nhà phát triển của nó thấy phù hợp.
một CVn

Câu trả lời:


53

Hệ thống 5 initsẽ chỉ cho bạn biết một phần nhỏ của câu chuyện.

Có một loại cận thị ảnh hưởng đến thế giới Linux. Mọi người nghĩ rằng họ sử dụng một thứ gọi là "Hệ thống 5 init", và đó là cả những gì truyền thống và là nơi tốt nhất để bắt đầu. Thực tế cũng không phải vậy.

Thực tế, truyền thống không phải là những gì những người như vậy nói, đối với người mới bắt đầu. Hệ thống 5 initvà Hệ thống 5 có rcniên đại với Hệ thống UNIX 5 của AT & T, gần như là UNIX đầu tiên như chúng ta bây giờ (nói) sau phiên bản đầu tiên của Linux-Mandrake.

Phiên bản 1 UNIX chỉ có init. Nó không có rc. Ngôn ngữ lắp ráp Phiên bản 1 init( có mã được khôi phục và cung cấp bởi Warren Toomey và cộng sự ) đã trực tiếp sinh ra và gettyxử lý 12 quy trình, gắn 3 hệ thống tệp cứng từ bảng tích hợp và trực tiếp chạy chương trình từ thư mục chính của tên người dùng mel. Các gettybảng cũng đã trực tiếp theo hình ảnh chương trình.

Đó là một thập kỷ nữa sau UNIX System 5, cái gọi là hệ thống khởi động Linux "truyền thống" đã xuất hiện. Năm 1992, Miquel van Smoorenburg (lại) đã viết một Linux init+ rcvà các công cụ liên quan của họ, mà bây giờ mọi người gọi là "Hệ thống 5 init", mặc dù nó không thực sự là phần mềm từ UNIX System 5 (và không chỉ là init).

Hệ thống 5 init/ rckhông phải là nơi tốt nhất để bắt đầu và ngay cả khi người ta bổ sung kiến ​​thức về systemd không bao gồm một nửa những gì cần biết. Có rất nhiều công việc trong lĩnh vực thiết kế hệ thống init (cho Linux và BSD) đã xảy ra chỉ trong hai thập kỷ qua. Tất cả các loại quyết định kỹ thuật đã được thảo luận, thực hiện, thiết kế, thực hiện và thực hành. Các Unices thương mại đã làm rất nhiều, quá.

Các hệ thống hiện có để nghiên cứu và học hỏi từ

Dưới đây là danh sách không đầy đủ của một số hệ thống init chính ngoài hai hệ thống đó và một hoặc hai trong số (một số) điểm nổi bật của chúng:

  • Joachim Nilsson của finit đã đi con đường của việc sử dụng một tập tin cấu hình do con người dễ đọc hơn.
  • Felix von Leitner minit đi cho một hệ thống cấu hình hệ thống tập tin-là-the-cơ sở dữ liệu, dấu chân bộ nhớ nhỏ, và bắt đầu / dừng phụ thuộc giữa những thứ mà initbắt đầu.
  • Gerrit Pape của runit đi cho những gì tôi đã mô tả trước đây như bốn kịch bản shell chỉ spawn tiếp cận.
  • Ban đầu nhằm mục đích có các phụ thuộc, các mục tiêu được đặt tên, nhiều tệp cấu hình và cú pháp cấu hình linh hoạt hơn với toàn bộ cài đặt nhiều hơn cho các quy trình con.
  • mới bắt đầu thiết kế lại hoàn toàn, mô hình hóa hệ thống không phải là dịch vụ và sự phụ thuộc lẫn nhau, mà là các sự kiện và công việc được kích hoạt bởi chúng.
  • Thiết kế của nosh bao gồm đẩy tất cả quản lý dịch vụ ra ngoài (bao gồm cả gettysinh sản và gặt hái zombie) vào một trình quản lý dịch vụ riêng biệt và chỉ xử lý các thiết bị / liên kết / thư mục "API" dành riêng cho hệ điều hành và các sự kiện hệ thống.
  • sinit là một init rất đơn giản. Nó thực thi /bin/rc.initcông việc của nó là bắt đầu các chương trình, gắn kết hệ thống tập tin, v.v. Đối với điều này, bạn có thể sử dụng một cái gì đó như minirc .

Hơn nữa, khoảng 10 năm trước, đã có cuộc thảo luận giữa những người dùng daemontools và những người khác sử dụng svscannhư quy trình số 1, dẫn đến các dự án như Paul Jarc của Svscan như nghiên cứu quy trình 1 , ý tưởng của Gerrit PapeSvscan của Laurent Bercot như quy trình 1 .

Điều này đưa chúng ta đến quy trình # 1 làm gì.

Chương trình # 1 làm gì

Các khái niệm về quá trình # 1 được "cho là" phải làm là do bản chất của họ chủ quan. Một tiêu chí thiết kế mục tiêu có ý nghĩa là quy trình tối thiểu # 1 phải làm. Hạt nhân áp đặt một số yêu cầu trên nó. Và luôn có một số thứ dành riêng cho hệ điều hành thuộc nhiều loại khác nhau mà nó phải làm. Khi nói đến quá trình # 1 theo truyền thống đã làm, thì chúng ta không ở mức tối thiểu đó và chưa bao giờ thực sự có được.

Có một số điều mà các hệ điều hành khác nhau và các chương trình khác yêu cầu của quy trình # 1 mà đơn giản là không thể thoát được.

Mọi người sẽ nói với bạn rằng fork()ing mọi thứ và đóng vai trò là cha mẹ của các quá trình mồ côi là chức năng chính của quy trình # 1. Trớ trêu thay, điều này là không đúng sự thật. Xử lý các quy trình mồ côi là (với các nhân Linux gần đây, như được giải thích tại https://unix.stackexchange.com/a/177361/5132 ) một phần mà hệ thống mà phần lớn có thể đưa ra khỏi quy trình # 1 vào các quy trình khác, chẳng hạn như một người quản lý dịch vụ tận tâm . Tất cả những người này là những người quản lý dịch vụ, chạy theo quy trình # 1:

Tương tự, như được giải thích tại https://superuser.com/a/888936/38062 , toàn bộ /dev/initctlý tưởng không cần phải ở bất cứ đâu gần quy trình # 1. Trớ trêu thay, đó là hệ thống tập trung cao độ chứng minh rằng nó có thể được chuyển ra khỏi quy trình # 1.

Ngược lại, những điều bắt buộc đối với init, mà mọi người thường quên trong họ off-the-top-of-the-đầu thiết kế, những thứ như xử lý SIGINT, SIGPWR, SIGWINCH, và vân vân gửi từ hạt nhân và ban hành các yêu cầu thay đổi trạng thái hệ thống khác nhau gửi từ các chương trình "biết" rằng các tín hiệu nhất định để xử lý # 1 có nghĩa là một số điều nhất định. (Ví dụ: Như được giải thích tại https://unix.stackexchange.com/a/196471/5132 , bộ công cụ BSD "biết" SIGUSR1có ý nghĩa cụ thể.)

Ngoài ra còn có các tác vụ khởi tạo và hoàn thiện một lần mà người ta không thể thoát hoặc sẽ phải chịu đựng rất nhiều khi không thực hiện, chẳng hạn như gắn hệ thống tệp "API" hoặc xóa bộ đệm của hệ thống tệp.

Các vấn đề cơ bản để xử lý các hệ thống tập tin "API" khác với hoạt động của initrom 1st Edition UNIX: Một người có một danh sách thông tin được đưa vào chương trình, và chỉ đơn giản mount()là tất cả các mục trong danh sách. Bạn sẽ tìm thấy cơ chế này trong các hệ thống đa dạng như BSD (sic!) init, Thông qua nosh system-manager, đến systemd.

"thiết lập hệ thống cho một vỏ đơn giản"

Như bạn đã quan sát, init=/bin/shkhông có hệ thống tệp "API" được gắn kết, gặp sự cố một cách vô duyên khi không có bộ đệm ẩn khi một loại exit( https://unix.stackexchange.com/a/195978/5132 ) và nói chung rời khỏi nó để người dùng (siêu) thực hiện thủ công các hành động giúp hệ thống có thể sử dụng tối thiểu.

Để xem những gì người ta thực sự không có lựa chọn nào khác ngoài việc thực hiện các chương trình số 1, và do đó đặt cho bạn một khóa học tốt cho mục tiêu thiết kế đã nêu của bạn, lựa chọn tốt nhất của bạn là xem xét sự chồng chéo trong hoạt động của runit Gerrit Pape, Felix von Leitner's minit, và system-managerchương trình từ gói nosh. Hai người trước cho thấy hai nỗ lực để được tối giản, nhưng vẫn xử lý những thứ không thể tránh khỏi.

Cái sau hữu ích, tôi đề nghị, cho mục nhập thủ công mở rộng cho system-managerchương trình, trong đó nêu chi tiết chính xác hệ thống tập tin "API" nào được gắn, nhiệm vụ khởi tạo nào được chạy và tín hiệu nào được xử lý; trong một hệ thống mà theo thiết kế , người quản lý hệ thống chỉ sinh ra ba thứ khác (trình quản lý dịch vụ, bộ ghi nhật ký đi kèm và chương trình để chạy các thay đổi trạng thái) và chỉ làm điều không thể tránh khỏi trong quy trình # 1.


3
Câu trả lời tuyệt vời và rất nhiều thông tin. Nhưng tôi đang tự hỏi mình ở đâu trong bức tranh lớn này là OSX launchd. Đôi khi mọi người quên hoàn toàn rằng OSX là một thành viên (tuyệt vời) của một gia đình lớn * nix.
DavAlPi

4

Khởi động hệ thống V trên Debian (có các biến thể và biến thể khác) thực hiện như sau:

  • Khi nhập runlevel, nó gọi các script theo /etc/rcX.d/S*thứ tự chữ và số, trong đó Xrunlevel. Các kịch bản này nên thiết lập runlevel. Thiết lập điển hình đang bắt đầu trình nền và thực hiện các tác vụ thiết lập cho mức chạy đó. Đây là một việc được thực hiện một lần khi vào runlevel.
  • Trong khi ở cấp độ chạy, nó bắt đầu các trình tiện ích được liệt kê trong /etc/inittabkhi cần phải hoạt động trong cấp độ chạy đó. Nếu những daemon đó ngừng chạy, nó sẽ khởi động lại chúng. Mặc dù bạn có thể có bất kỳ trình nền nào bạn muốn quản lý init, tối thiểu bạn muốn một vài gettycái để bạn có thể đăng nhập. gettyThoát khi đăng nhập hoàn tất, sau đó initkhởi động lại, cung cấp lời nhắc đăng nhập mới.
    • Nếu daemon khởi động lại quá nhiều lần trong một thời gian quá ngắn, nó sẽ ngừng cố gắng khởi động lại nó trong một thời gian.
    • Chỉ vì một cái gì đó đã được bắt đầu bởi các kịch bản khởi động khi vào cấp độ chạy không inittự động cố gắng giữ cho nó chạy. Bạn cần chỉ định riêng biệt trong /etc/inittab.
  • Khi thoát một runlevel, nó gọi các script theo /etc/rcX.d/K*thứ tự chữ và số, trong đó Xrunlevel. Một cách để thực hiện tắt máy hoặc khởi động lại là xác định runlevel cho các sự kiện đó và thực hiện tác vụ cuối cùng thực hiện lệnh halthoặc reboot.
  • Nó sẽ gọi các tệp thực thi để đáp ứng với các sự kiện nhất định, chẳng hạn như các sự kiện sức mạnh hoặc Ctrl-Alt-Del.
  • Nó lắng nghe trên một ổ cắm, nếu nhận được một số tin nhắn nhất định, nó sẽ thay đổi runlevel.

Vì vậy, bạn có thể sử dụng initlàm người quản lý dịch vụ thô sơ nếu muốn, nhưng nhiệm vụ chính của những ngày này là luôn gettysẵn sàng để người dùng có thể đăng nhập và khởi động chuyển đổi runlevel.

Tôi chỉ tự hỏi, init làm những nhiệm vụ gì để thiết lập hệ thống cho một shell đơn giản?

Bất cứ điều gì bạn muốn. Trên Debian, trong mỗi /etc/rcX.dthư mục là một liên kết tượng trưng đến một tập lệnh /etc/init.dvà bạn hoàn toàn có thể tùy chỉnh hoặc xóa các tập lệnh đó. Trình tự được thiết lập bằng cách đặt trước mỗi kịch bản với một 00, 01vv

Bạn cũng có thể chỉ định một -btùy chọn init(tức là thông qua dòng lệnh kernel) nếu bạn chỉ muốn initsinh ra một shell. Khi bạn thoát khỏi vỏ, initchết và khi initchết, hạt nhân sẽ hoảng loạn.


2

Mức tối thiểu tuyệt đối mà init phải làm là chạy ít nhất một chương trình khác và không bao giờ thoát. Nếu init thoát khỏi hệ thống gặp sự cố. Tôi cho rằng ngay cả việc chạy một chương trình khác là không thực sự cần thiết, nhưng nếu bạn không làm điều đó thì init sẽ phải chịu trách nhiệm thực hiện mọi việc mà hệ thống dự kiến ​​sẽ làm, hoặc nó sẽ không hữu ích lắm.


1
Tôi đã gặp lỗi các hệ thống Linux khi PID 1 bị lỗi nhưng về cơ bản hệ thống vẫn tiếp tục chạy. Làm thế nào xấu sự cố PID 1 có thể phụ thuộc vào phiên bản kernel.
Gilles 'SO- ngừng trở nên xấu xa'

1

init có thể làm bất cứ điều gì bạn muốn

init là một tệp thực thi tùy ý được gọi bởi nhân Linux ở cuối quá trình khởi động (và chỉ có một tệp thực thi như vậy).

Nó thường được triển khai dưới dạng thực thi ELF, nhưng thậm chí nó có thể là tập lệnh shell với chmod +x: Ban đầu là tập lệnh shell

Các triển khai điển hình như sysemd sẽ đọc các tệp cấu hình, ofen /etc/initrcvà sau đó chia một loạt các quy trình người dùng dựa trên các cấu hình đó, để thực hiện các khía cạnh khác nhau của hệ thống.

Tuy nhiên, đây là cách thực hiện hoàn toàn cụ thể và do đó, câu hỏi của bạn không thể được trả lời mà không chỉ định thực hiện cụ thể. Ví dụ, tôi đã chơi với một initquá trình chỉ đơn giản là làm một reboottòa nhà cho mục đích giáo dục.

Hạt nhân Linux chỉ đơn giản là tìm kiếm tệp thực thi tại đường dẫn /inittheo mặc định, nhưng điều này có thể bị ghi đè bởi init=tham số dòng lệnh của hạt nhân Linux.

Một cách tuyệt vời để chơi xung quanh initlà sử dụng QEMU, vì bạn có thể chuyển các tham số dòng lệnh kernel cho QEMU từ dòng lệnh QEMU với -appendtùy chọn và không sợ bị brick máy tính để bàn của bạn.

Dưới đây là thiết lập Buildroot + QEMU hoàn toàn tự động tối thiểu của tôi , giúp bạn dễ dàng chơi xung quanh với các phần riêng của mình để làm sáng tỏ vấn đề.


0

Nếu bạn cam kết với nguyên tắc "làm một việc và làm tốt" theo mô-đun, thì một initchương trình sẽ bắt đầu các quy trình.

Bắt đầu quá trình

Nó nên được thực thi khi kernel đã được giải nén thành công, xử lý tất cả các tác vụ thô sơ liên quan đến việc khởi tạo tất cả các quy trình ban đầu mà hệ thống yêu cầu để vận hành (như gắn ổ đĩa được tìm thấy trong / etc / fstab, đưa lên giao diện mạng và Sớm).

Do quá trình khởi động và tắt máy về cơ bản là nghịch đảo với nhau, nên thông thường một chương trình init cũng đảm bảo rằng các quy trình được dừng lại khi có lệnh tắt máy.

Dừng quá trình

Điều này có nghĩa là nó phải dừng các quy trình theo trang man của quy trình đó (nói cách khác, không chỉ là trắng trợn kill -9, nó sẽ đưa quy trình xuống theo cách mà nó muốn kết thúc), ngắt kết nối các ổ đĩa và cuối cùng đưa ra lệnh tắt nguồn cuối cùng .

Người giới thiệu

Một tài liệu tham khảo tốt về cách thực hiện điều này bởi những người khác là xem xét các tập lệnh /etc/rc.d của Slackware , và cũng tại một hệ thống init đơn giản đã tồn tại, như ninit (kế thừa để khai thác). Nó có sự giám sát quá trình (có nghĩa là nếu một quá trình chết đi, nó được khởi chạy lại), được cho là không phải là công việc của init, nhưng nó vẫn khá cơ bản và dễ hiểu, đặc biệt là thông qua các kịch bản mẫu của tác giả.

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.