http://en.wikipedia.org/wiki/Init
init


In Unix-based computer operating systems, init (short for initialization) is the first process started during booting of the computer system. Init is a daemon process that continues running until the system is shut down. It is the direct or indirectancestor of all other processes and automatically adopts all orphaned processes. Init is started by the kernel using a hard-coded filename, and if the kernel is unable to start it, a kernel panic will result. Init is typically assigned process identifier 1.
The design of init has diverged in Unix systems such as System III and System V, from the functionality provided by the init in Research Unix and its BSD derivatives. The usage on most Linux distributions is somewhat compatible with System V, but some distributions, such as Slackware, use a BSD-style and others, such as Gentoo, have their own customized version.
Several replacement init implementations have been written with attempt to address design limitations in the standard versions. These include systemd and Upstart, the latter being used by Ubuntu[1][2] and some other Linux distributions.[3][4]
Contents
[hide]
SysV-style[edit]
System V init examines the /etc/inittab
file for an :initdefault:
entry, which defines any default runlevel. If there is no default runlevel, then init
dumps the user to a system console for manual entry of a runlevel.
Runlevels[edit]
The runlevels in System V describe certain states of a machine, characterized by the processes run. There are generally eight runlevels, three of which are "standard":
- 0. Halt
- 1. Single user mode (aka. S or s)
- 6. Reboot
Aside from these, every Unix and Unix-like system treats runlevels a little differently. The common denominator, the /etc/inittab
file, defines what each runlevel does (if they do anything at all) in a given system.
Default runlevels[edit]
Operating System | Default runlevel |
---|---|
AIX | 2 |
CentOS | 3 (console/server) or 5 (graphical/desktop)[5] |
Debian | 2[6] |
Gentoo Linux | 3[7] |
HP-UX | 3 (console/server/multiuser) or 4 (graphical) |
Mac OS X | 3 |
Mandriva Linux | 3 (console/server) or 5 (graphical/desktop) |
Red Hat Enterprise Linux / Fedora | 3 (console/server) or 5 (graphical/desktop)[8] |
Slackware Linux | 3 |
Solaris | 3[9] |
SUSE Linux Enterprise/openSUSE Linux | 3 (console/server) or 5 (graphical/desktop)[10] |
Ubuntu (Server and Desktop) | 2[6] |
On the Linux distributions defaulting to runlevel 5 in the table above, runlevel 5 invokes a multiuser graphical environment running the X Window System, usually with a display manager like GDM or KDM. However, the Solaris operating system typically reserves runlevel 5 to shut down and automatically power off the machine.
On most systems users can check the current runlevel with either of the following commands:
-
$ runlevel
(need to be root or sudo) -
$ who -r
The root typically changes the current runlevel by running the telinit
or init
commands. The /etc/inittab
file sets the default runlevel with the :initdefault:
entry.
On Unix systems, changing the runlevel is achieved by starting only the missing services (as each level defines only those that are started / stopped).[citation needed] For example, changing a system from runlevel 3 to 4 might only start the local X server. Going back to runlevel 3, it would be stopped again.
BSD-style[edit]
BSD init runs the initialization shell script located in /etc/rc
, then launches getty on text-based terminals or a windowing system such as X on graphical terminals under the control of /etc/ttys
. There are no runlevels; the /etc/rc
file determines what programs are run by init. The advantage of this system is that it is simple and easy to edit manually. However, new software added to the system may require changes to existing files that risk producing an unbootable system. To mitigate this, BSD variants have long supported a site-specific /etc/rc.local
file that is run in a sub-shell near the end of the boot sequence.
A fully modular system was introduced with NetBSD 1.5 and ported to FreeBSD 5.0 and successors. This system executes scripts in the /etc/rc.d
directory. Unlike System V's script ordering, which is derived from the filename of each script, this system uses explicit dependency tags placed within each script.[11] The order in which scripts are executed is determined by the rcorder script based on the requirements stated in these tags.
Replacements for init[edit]
Traditionally, one of the major drawbacks of init is that it starts tasks serially, waiting for each to finish loading before moving on to the next. When startup processes end up I/O blocked, this can result in long delays during boot.
Various efforts have been made to replace the traditional init daemons to address this and other design problems, including:
- BootScripts in GoboLinux
- busybox-init, suited embedded operating systems, employed by OpenWrt before it was replaced with procd
- DEMONS, a modification of the init start process by KahelOS, where daemons are started only when the DE (desktop environment) started.
- eINIT, a full replacement of init designed to start processes asynchronously, but with the potential of doing it without shell scripts
- Initng, a full replacement of init designed to start processes asynchronously
- launchd, a replacement for init introduced in Mac OS X v10.4 (it launches SystemStarter to run old-style 'rc.local' and SystemStarter processes)
- Mudur, an init replacement written in Python and designed to start process asynchronously in use by the Pardus Linux distribution.[12]
- runit, a cross-platform full replacement for init with parallel starting of services
- s6, another cross-platform full replacement for init, similar to runit.
- Service Management Facility, a complete full replacement/redesign of init from the ground up in Solaris starting with Solaris 10
- systemd, a full replacement for init with parallel starting of services and other features, used by many distributions.
- SystemStarter, a process spawner started by the BSD-style init in Mac OS X prior to Mac OS X v10.4
- Upstart, a full replacement of init designed to start processes asynchronously initiated by Ubuntu.
http://zh.wikipedia.org/wiki/Init
init[編輯]
init(為英語:initialization的簡寫)是 Unix 和 類Unix 系統中用來產生其它所有進程的程序。它以守護進程的方式存在,其進程號為1。
Unix 系列中(如 System III 和 System V)init的作用,和研究中的 Unix 和 BSD 派生版本相比,發生了一些變化。大多數Linux發行版是和 System V 相兼容的,但是一些發行版如Arch 和 Slackware 采用的是BSD風格,其它的如 Gentoo 是自己定制的。Ubuntu[1][2] 和其它一些發行版現在開始采用 Upstart[3] 來代替[4] 傳統的 init 進程。
BSD風格[編輯]
BSD init 運行存放於'/etc/rc'的初始化 shell 腳本,然后啟動基於文本模式的終端(getty)或者基於圖形界面的終端(窗口系統,如 X)。 這里沒有運行模式的問題,因為文件 'rc' 決定了 init 如何執行。
優點: 簡單且易於手動編輯。
缺點: 如果第三方軟件需要在啟動過程執行它自身的初始化腳本,它必須修改已經存在的啟動腳本,一旦這種過程中有一個小錯誤,都將導致系統無法正常啟動。
值得注意的是,現代的 BSD 派生系統一直支持使用 'rc.local' 文件的方式,它將在正常啟動過程接近最后的時間以子腳本的方式來執行。這樣做減少了整個系統無法啟動的風險。然后,第三方軟件包可以將它們獨立的 start/stop 腳本安裝到一個本地的 'rc.d' 目錄中(通常這是由 ports collection/pkgsrc 完成的)。 FreeBSD 和 NetBSD 現在默認使用rc.d ,該目錄中所有的用戶啟動腳本,都被分成更小的子腳本,和 SysV 類似。rcorder 通常根據在 rc.d目錄中腳本之間的依賴關系來決定腳本的執行順序。
SysV風格[編輯]
System V init 檢查 '/etc/inittab' 文件中是否含有 'initdefault' 項。 這告訴 init 系統是否有一個默認運行模式。如果沒有默認的運行模式,那么用戶將進入系統控制台,手動決定進入何種運行模式。
優點: 靈活性強
缺陷: 比較復雜
運行模式[編輯]
System V中運行模式描述了系統各種可能的狀態。通常會有 8 種運行模式,即運行模式 0 到 6 和 S 或者 s。其中運行模式 3 為"保留的"運行模式:
- 0. 關機
- 1. 單用戶模式
- 6. 重啟
除了模式 0, 1,6外, 每種 Unix 和 Unix-like 系統對運行模式的定義不太一樣。通常在 /etc/inittab 文件中定義了各種運行模式的工作范圍。
默認的運行模式[編輯]
操作系統 | 默認的運行模式 |
---|---|
AIX | 2 |
Arch Linux | 3 |
CentOS | 3 |
Debian GNU/Linux | 2 [5] |
Gentoo Linux | 3 |
Mandriva Linux | 5 |
Mac OS X | 3 |
Red Hat Linux / Fedora Core | 3 or 5 |
Slackware Linux | 3 |
Solaris | 3 [6] |
SUSE Linux | 5 [7] |
Ubuntu (Server and Desktop) | 2 [8] |
上面的表中有兩種Linux發行版默認的運行模式為 5,模式 5 是多用戶圖形環境(X Window System),通常還包括X顯示管理器。然而在Solaris操作系統中,模式 5 被保留用來執行關機和自動切斷電源。
大多數操作系統的用戶可以用下面的命令來判斷當前的運行模式是什么:
$ runlevel $ who -r
在 root 權限下,運行 telinit 或者 init 命令可以改變當前的運行模式。 /etc/inittab 文件中設置的默認的運行模式在 :initdefault: 項中。
跳過 init[編輯]
Linux系統中,現代的bootloader(如 LILO 或者 GRUB),用戶可以在初始化過程中最后啟動的進程來取代默認的 /sbin/init
。 通常是在 bootloader 環境中通過執行 init=/foo/bar
命令。例如,如果執行 init=/bin/bash
,啟動單用戶 root 的 shell 環境,無需用戶密碼。
BSD的變種,大多數平台, bootstrap 程序是可以被打斷的,然后執行 boot -s
命令進入單用戶模式。
單用戶模式並不沒有跳過 init,它仍然可以執行 /sbin/init
,但是它將使 init 詢問 exec()
將要執行的命令 (默認為 /bin/sh
) 的路徑,而不是采用正常的多用戶啟動順序。 如果內核啟動時在 /etc/ttys
文件中被標注為 "不安全" (在某些系統中,當前的"安全模式" 可能會有些變化), 在允許這種情況(或者回退到單用戶模式,如果用戶執行 CTRL+D
),init 將首先詢問 root 用戶的密碼。 如果該程序退出,內核將在多用戶模式下重新執行 init。 如果系統從多用戶模式切換到單用戶模式,還將碰到上述的情況。
如果內核加載后, init 不能被正常啟動, 這將導致 panic 錯誤,此時系統將不可使用。想要通過 init 自身來改變 init 的路徑,不同的版本情況不太一樣(NetBSD中可執行 boot -a
; FreeBSD中利用 init_path
命令裝載變量)。
其他風格[編輯]
很多人一直努力地從某些方面改進傳統的 init 守護進程,使它變得更完善。下面列出的是一些改進,沒有特別的順序:
- SystemStarter, 用來替代 launchd — Apple Mac OS X開啟進程
- Initng, 完全代替 init ,可以異步開啟進程
- Upstart, 完全代替 init ,可以異步開啟進程 由Ubuntu使用
- Service Management Facility, 完全代替/重新設計 Solaris 啟動 Solaris 10
- runit, 跨平台的完全代替 init 可以並行啟動服務
- BootScripts, GoboLinux
- Mudur, 用 Python 寫成的 init 替代品, 可以異步開啟進程,Pardus Linux 發行版
- systemd, 完全替代init,可並行啟動服務,並能減少在shell上的系統開銷,為Fedora所使用
下面列出的項目還沒有大范圍的使用:
- eINIT, 完全代替 init ,可以異步開啟進程,但是完成這個過程可以不使用 shell 腳本
- svscan 來自 daemontools 被用作 1 號進程 - 似乎將被 runit 替代
- cinit
- twsinit, 部分用 x86 匯編寫成, 只是用來證明一種概念
- minit
- OpenRC
http://en.wikipedia.org/wiki/Upstart
Upstart
![]() |
|
Original author(s) | Scott James Remnant |
---|---|
Developer(s) | Canonical Ltd. |
Initial release | August 24, 2006 |
Stable release | 1.12.1[1] / March 11, 2014 |
Written in | C |
Operating system | Linux |
Type | Init daemon |
License | GPLv2 |
Website | upstart.ubuntu.com
|
Upstart is an event-based replacement for the traditional init daemon – the method by which several Unix-likecomputer operating systems perform tasks when the computer is started. It was written by Scott James Remnant, a former employee of Canonical Ltd.
Rationale[edit]
The traditional init process was originally only responsible for bringing the computer into a normal running state after power-on, or gracefully shutting down services prior to shutdown. As a result, the design is strictlysynchronous, blocking future tasks until the current one has completed. Its tasks must also be defined in advance, as they are limited to this prep or cleanup function. This leaves it unable to handle various non-startup-tasks on a modern desktop computer elegantly, including:
- The addition or removal of USB pen drives and other portable storage / network devices while the machine is running
- The discovery and scanning of new storage devices, without locking the system, especially when a disk may not even power on until it is scanned
- The loading of firmware for a device, which may need to occur after it is detected but before it is usable
Upstart's event-driven model allows it to respond to events asynchronously as they are generated.[2]
Design[edit]
Upstart operates asynchronously; it handles starting of the tasks and services during boot and stopping them during shutdown, and also supervises the tasks and services while the system is running.
Easy transition and perfect backwards compatibility with sysvinit were the explicit design goals;[3] accordingly, Upstart can run unmodified sysvinit scripts. In this way it differs from most other init replacements (beside systemd and OpenRC), which usually assume and require complete transition to run properly, and do not support a mixed environment of traditional and new startup methods.[4]
Upstart allows for extensions to its event model through the use of initctl to input custom, single events, or event bridges to integrate many or more-complicated events.[5] By default, Upstart includes bridges for socket, dbus, udev, file, and dconf events; additionally, more bridges (for example, a Mach ports bridge, or a devd (found on FreeBSD systems) bridge) are possible.[6]
Adoption[edit]
Linux distributions and other operating systems based on the Linux kernel which use Upstart as the default init system:
- Upstart was first included in Ubuntu in the 6.10 (Edgy Eft) release in late 2006, replacing sysvinit. Ubuntu 9.10 (Karmic Koala) introduced native Upstart bootup as of Alpha 6.[7] In turn, after the Debian project decided to adopt systemd on a future release in 2014, Mark Shuttleworth announced that Ubuntu would begin plans to migrate to systemd itself to maintain consistency with upstream.[8]
- Upstart is used in Google's Chrome OS.[9]
Linux distributions that support or have supported Upstart to some extent, but moved away since or no longer use it as their default init system:
- Debian decided that systemd will be the default init system beginning with the jessie release,[10] after considering switching to Upstart.[11]
- In Fedora 9, Upstart replaced sysvinit, however, systemd replaced Upstart in the Fedora 15 release.[12][13]
- Red Hat includes Upstart in their Red Hat Enterprise Linux 6 release.[14] As a result, it is also used by RHEL 6 variants such as CentOS, Scientific Linux, and Oracle Linux. For RHEL 7, systemd will be used.[15][16]
- openSUSE included Upstart in version 11.3 Milestone 4, but not as default.[17] systemd replaced Upstart, as the default init system in openSUSE 12.1.[18]
- Upstart is used in HP's webOS for the Palm Pre, Palm Pixi (both before Palm was bought out by HP), HP Veer, and HP Pre 3 smart phones, along with the HP TouchPad tablet.[19]
- Upstart replaced the sysvinit in Maemo 5 for Nokia Internet tablets[20] and was retained for MeeGo on the N9 and N950 handsets despite MeeGo's transition to systemd after merging with Moblin.[citation needed]
http://upstart.ubuntu.com/cookbook/
http://en.wikipedia.org/wiki/Systemd
systemd
Original author(s) | Lennart Poettering,Kay Sievers |
---|---|
Developer(s) | Lennart Poettering, Kay Sievers and others[1] |
Initial release | 30 March 2010 |
Stable release | 213[2] / 28 May 2014 |
Written in | C[3] |
Operating system | Linux |
Type | Init daemon |
License | first GPLv2+, currently GNU LGPL2.1+ [4] |
Website | freedesktop.org/…/systemd/
|
systemd is a system management daemon designed exclusively for the Linux kernel API. For systems using it, it is the first process which is executed in user space during the Linux startup process. Therefore, systemd serves as the root of the user space's process tree. The name systemd adheres to the Unix convention of making daemons easier to distinguish by having letter d as the last one in their actual filenames.[5]
Contents
[hide]
Overview[edit]
Systemd was developed for Linux to replace the init system inherited from UNIX System V and Berkeley Software Distribution (BSD) operating systems. Like init, systemd is a daemon that manages other daemons. All daemons, including systemd, are background processes. Systemd is the first daemon to start (during booting) and the last daemon to terminate (during shutdown).
Lennart Poettering and Kay Sievers, the software engineers who initially developed systemd,[1] sought to surpass the efficiency of the init daemon in several ways. They wanted to improve the software framework for expressing dependencies; to allow more processing to be done concurrently or in parallel during systembooting; and to reduce the computational overhead of the shell.
Systemd is published as free and open-source software under the terms of the GNU Lesser General Public License version 2.1 or later.[4]
Software architecture[edit]

Systemd's initialization instructions for each daemon are recorded in a declarative configuration file rather than a shell script. For inter-process communication, systemd makes Unix domain sockets and D-Bus available to the running daemons. Because systemd tracks processes using Linux cgroups instead of process identifiers(PIDs), daemons cannot "escape" systemd; not even by double-forking. Systemd is also capable of aggressive parallelization.
Among systemd's auxiliary features are a cron-like job scheduler called systemd Calendar Timers, and an eventlogging subsystem called journal.[6] The system administrator may choose whether to log system events with systemd or syslog. Systemd's logfile is a binary file. The state of systemd itself can be preserved in asnapshot for future recall.
In April 2012, the source tree for udev (a device manager for the Linux kernel, which handles the /devdirectory and all user space actions when adding/removing devices, including firmware loading) was merged into systemd.[7]
Systemd provides a replacement for sysvinit, pm-utils, inetd, acpid, syslog, watchdog, cron and atd. Also, it has an integrated login manager called systemd-logind, which offers multiseat improvements and replaces ConsoleKit, which is no longer maintained.[8][9]
All available userspace utility programs for systemd and their man pages are currently documented at the project's official page.[10]
In version 209, networkd was integrated, which provides abilities for systemd to perform various network configurations; as of this version, support is limited to statically assigned addresses and basic support forbridging configuration.[11][12][13][14][15]
Since version 205, systemd offers ControlGroupInterface, an API to the Linux kernel cgroups.[16] The Linux kernel cgroups are adapted to support kernfs,[17] and are being modified to support a unified hierarchy.[18]
GNOME integration[edit]
In the interest of enhancing the interoperability between systemd and GNOME desktop environment, systemd coauthor Lennart Poettering asked the GNOME Project to consider making systemd an external dependency of GNOME 3.2, so those two projects become better integrated, with GNOME using operations offered by systemd for various tasks.[19]
In November 2012, the GNOME Project concluded that basic GNOME functionality should not rely on systemd.[20] However, in contradiction of this statement, GNOME 3.8 introduced a de facto dependency on systemd by introducing session management behaviors which depend on how systemd operates. While the developers of Gentooattempted to adapt these changes in OpenRC, the implementation contained too many bugs, causing the distribution to mark systemd as a dependency of GNOME.[21][22]
At the same time, GNOME is pushing further integration of systemd.[23] For Mutter version 3.13.2, mutter-launch was replaced with logind integration.[24]
Controversy[edit]
Adoption of systemd has been controversial at times. Articles run in Linux Advocates have characterized systemd as "the new PulseAudio," and as "an accident waiting to happen."[25][26] One Fuduntu contributor is quoted as stating that systemd has limited software choice:[25]
Systemd, whether by design, or circumstance, is largely becoming non-optional. Inclusion of core technologies such as dbus and udev are reducing choice for linux users and developers, rather than expanding them—which is the very antithesis of the idea of Free/Open Source software.
In a 2012 interview, Slackware's founder Patrick Volkerding also expressed reservations about the systemd architecture:[27]
Concerning systemd, I do like the idea of a faster boot time (obviously), but I also like controlling the startup of the system with shell scriptsthat are readable, and I'm guessing that's what most Slackware users prefer too. I don't spend all day rebooting my machine, and having looked at systemd config files it seems to me a very foreign way of controlling a system to me, and attempting to control services, sockets, devices, mounts, etc., all within one daemon flies in the face of the UNIX concept of doing one thing and doing it well.
Eric S. Raymond declined to comment on systemd at first, but stated, "I'm aware there’s a controversy."[28] Then in a March 2014 interview on Slashdot, he expressed some concerns about the goals and architecture of systemd:[29]
I want to study it carefully because I'm a bit troubled by what I hear about the feature set and the goals. From that, I fear it may be one of those projects that is teetering right at the edge of manageable complexity – OK as long as an architect with a strong sense of design discipline is running things, but very prone to mission creep and bloat and likely to turn into a nasty hairball over the longer term.
Adoption[edit]
In May 2011, Fedora became the first major Linux distribution to enable systemd by default.[30] As of October 2013, Slackware does not support or use systemd, but Slackware's lead Patrick Volkerding has not ruled out the possibility for switching to it.[31]
Linux distribution | Date added to software repository[note 1] | Enabled by default? |
---|---|---|
Ångström | N/A | Yes |
Arch Linux | October 2012[32] | Yes |
CoreOS | July 2013 | Yes[33] |
Debian GNU/Linux[34] | April 2012 | Chosen for next release[note 2] |
Fedora | May 2011 (v15)[37] | Yes |
Frugalware Linux | August 2011 (v1.5)[38] | Yes |
Gentoo Linux | 2011[39][40][41] | No |
Mageia | May 2012 (v2.0)[42] | Yes |
openSUSE | March 2011 (v11.4)[43] | Yes |
Red Hat Enterprise Linux | Pending for RHEL 7 | Pending for RHEL 7[44][45] |
Sabayon Linux | August 2013 (v13.08)[46] | Yes |
Slackware | N/A | No |
Ubuntu[note 3] | April 2013 (v13.04)[48] | Planned[36] |
- Jump up^ Dates are for the general availability release.
- Jump up^ The Debian Technical Committee voted to make systemd the default system management daemon for Linux in the "jessie" release.[35] As a result, Ubuntu founder Mark Shuttleworth announced that Ubuntu would migrate towards it from its self-developed competitor Upstart for a future release, in order to maintain consistency with the distribution that Ubuntu is based upon.[36]
- Jump up^ Ubuntu's development documentation offers instructions on how to use systemd as an experimental option.[47]
http://blog.csdn.net/zhoudaxia/article/details/6666872
1、init程序剖析
init進程是內核引導過程完成時創建的第一個進程。Linux使用了init進程來對組成Linux的服務和應用程序進行初始化。
當 init 進程啟動時(使用傳統的sysvinit版本),它會打開一個名為 /etc/inittab 的文件。這個文件是 init 的配置文件,定義了如何對系統進行初始化。這個文件還包含了有關出現電源故障時執行的操作(如果系統支持)、以及在檢測到 Ctrl-Alt-Delete 鍵序列時應該如何反應的信息。請參看 清單 1 中該文件的簡短片段,了解它所提供的內容。
inittab 配置文件使用通用格式定義了幾項內容:id:runlevels:action:process。其中 id 是惟一標識該項的字符序列。runlevels 定義了操作所使用的運行級別。action 指定了要執行的特定操作。最后,process 定義了要執行的進程。
清單 1. inittab 文件摘錄
- # The default runlevel
- id:2:initdefault
- # Boot-time system configuration/initialization script
- si::sysinit:/etc/init.d/rcS
- # Runlevels
- l0:0:wait:/etc/init.d/rc 0
- l1:1:wait:/etc/init.d/rc 1
- l2:2:wait:/etc/init.d/rc 2
- l3:3:wait:/etc/init.d/rc 3
- l4:4:wait:/etc/init.d/rc 4
- l5:5:wait:/etc/init.d/rc 5
- l6:6:wait:/etc/init.d/rc 6
- z6:6:respawn:/sbin/sulogin
- # How to react to ctrl-alt-del
- ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now
在 init 加載 /etc/inittab 之后,就會將系統切換到 initdefault 操作所定義的運行級別。如 清單 1 所示,即運行級別 2。我們可以將運行級別看作是系統的狀態。例如,運行級別 0 定義了系統掛起狀態,運行級別 1 是單用戶模式。運行級別 2 到 5 是多用戶狀態,運行級別 6 表示重啟。(注意有些發行版對於運行級別的表示是不同的)。還可以以另一種方式考慮運行級別,即它是一種定義可以執行哪些進程(定義系統狀態的進程)的方法。
我們可以使用 telinit 工具(這是一個指向 init 工具的鏈接)與 init 進程進行通信。例如,如果目前在多用戶模式下(runlevel 2),希望切換到單用戶模式(runlevel 1),使用命令 telinit 1 即可(使用超級用戶模式)。要查看系統的當前運行級別,請使用命令 runlevel。
正如 清單 1 定義的一樣, initdefault 指定默認的 init 級別是 2 (多用戶模式)。在定義初始的運行級別之后,則調用 rc 腳本以及參數 2(運行級別)來啟動系統。這個腳本然后會調用各種服務和應用程序腳本來啟動或停止特定的元素。在本例中,文件都是在 /etc/rc2.d/ 中定義的。例如,如果要啟動 MySQL 應用程序(例如系統啟動),可以這樣調用:/etc/rc2.d/S20mysql start。在關閉系統時,則使用 stop 參數調用相同的腳本集。
最后,串行執行大量的腳本以啟動各種需要的服務(通常可以在 Linux 的引導屏幕中看到)。即使這些服務彼此無關時,依然會順次啟動它們。其結果是引導過程非常耗時(尤其在具有很多服務的大型系統上更是如此)。
關於這個問題的一個很明顯的解決方案是去掉 init 命令的串行特性,將其替換成並行化操作。在很多多處理系統中都可以看到這種用法。例如,socket striping,或者使用兩個或多個 socket 並行地移動數據,就是一個基於這個主題的解決方案。獨立磁盤冗余陣列(RAID)系統也是通過將磁盤分成條狀(通常是並行的)來提高 I/O 性能。
修改初始化進程非常的簡單。在引導時(使用 LILO 或 GRUB),指定一個新進程來開始處理系統初始化。指定 init=/sbin/mynewinit 作為內核引導行的一部分從而調用這個進程,而不是默認的 init 進程。在 /init/main.c:kernel_init()-->init_post()的內核源代碼中您可以看到這種用法。如果在內核引導行中提供了一個 init 命令,引導時就會使用它。否則,內核就會嘗試啟動 4 個備選方法之一(第一個是 /sbin/init,接着是/etc/init, /bin/init, /bin/sh)。
init進程是由內核啟動的第一個也是惟一的一個用戶進程,它是后續所有進程的發起者,比如init進程啟動/bin/sh程序后,才能夠在控制台上輸入各種命令。
init執行的基本流程如下:
(1)解析/etc/inittab:執行sysinit命令指定的進程,以前通常是/etc/init.d/rcS,在新版本的init程序中則通常是/etc/rc.d/rc.sysinit腳本。
(2)執行/etc/rc.d/rc.sysinit:這是由init執行的第一個腳本,此步進行的工作包括配置網絡、配置內核參數、掛載root文件系統、檢查文件系統、設置系統時鍾、配置機器、開啟交換空間等。
(3)執行/etc/rc.d/rcX.d/[K...][S...]:根據定義的initdefault運行級別,執行對應wait命令指定的程序,這會運行對應目錄下的各個程序,並等待它們運行完。在rcX.d目錄下,首先終止K開頭的服務(用來關閉一個服務),然后啟動S開頭的服務(用來啟動一個服務)。對每一個運行級別來說,在/etc/rc.d子目錄中都有一個對應的下級目錄。這些運行級別的下級子目錄的命名方法為rcX.d, 其中X就是代表運行級別的數字。在各個運行級別的子目錄中,都建立有到/etc/rc.d/init.d子目錄中命令腳本程序的符號鏈接,鏈接的名稱在K與S后有一個數字,表示執行順序,數字小的先執行,例如K01tog-pegasus、S00microcode_ctl。對以K開頭的腳本執行時系統會傳遞stop參數,而S開頭的腳本系統會傳遞start參數。
(4)執行/etc/rc.d/rc.local:Redhat中運行模式2,3,5都把/etc/rc.d/rc.local作為初始化腳本中的最后一個文件,所以用戶可以自己在這個文件中添加一些需要在其他初始化工作之后,登陸之前執行的命令。
(5)執行getty程序:為每個聯機終端使用fork()創建一個子進程,並在子進程中運行getty程序,init進程則調用wait(),進入等待子進程結束狀態。getty程序設置終端類型、屬性、速度和線路規程等。對於字符界面的運行級別(如級別2和3),它會打開並初始化一個tty端口,顯示提示信息。通常,若/etc/issue文本文件存在,則getty會首先顯示其中的文本信息,然后顯示登錄提示信息(例如“plinux login:” ),出現字符登錄界面,並等待用戶鍵入用戶名和口令。可以在inittab文件中配置使用哪一種getty程序(在“id:runlevels:action:process”的process部分指定,並可以傳遞相應的getty參數),如agetty, getty, mgetty, uugetty, mingetty,fbgetty等。getty程序只能由超級用戶執行。
注意如果第1步中的inittab文件指定的默認運行級別是圖形用戶界面形式(如級別5),則init程序會轉向去執行/etc/X11/prefdm腳本,它會執行/usr/sbin/gdm,啟動圖形登錄界面。GDM管理的不只是X的啟動,還有登錄,注銷,掛起等一系列操作。
啟動登錄界面(圖形或字符界面),並輸入完用戶名后,getty會調用login程序。
(6)執行login程序:getty調用exec()執行login程序,以核對輸入的用戶名和口令。由於調用了exec(而不是fork),login的執行環境會覆蓋getty的執行環境。login進程會讀取/etc/passwd,以用戶名和口令。login根據用戶輸入的用戶名,從口令文件passwd中取得對應用戶的登錄項,然后調用getpass()以顯示”password:”提示信息,讀取用戶鍵入的密碼,然后使用加密算法對鍵入的密碼進行加密處理,並與口令文件中該用戶項中pw_passwd字段作比較。如果用戶幾次鍵入的密碼均無效,則login程序會以出錯碼1退出執行,表示此次登錄過程失敗。此時父進程(進程init)的wait()會返回該退出進程的pid,因此會根據記錄下來的信息再次創建一個子進程,並在該子進程中針對該終端設備再次執行getty程序,重復上述過程。
如果用戶鍵入的密碼正確,則login就會把當前工作目錄(Currend Work Directory)修改成口令文件中指定的起始工作目錄。並把對該終端設備的訪問權限修改成用戶讀/寫和組寫,設置進程的組ID。然后利用所得到的信息初始化環境變量信息,例如起始目錄(HOME=)、使用的shell程序(SHELL=)、用戶名(USER=和LOGNAME=)和系統執行程序的默認路徑序列(PATH=)。接着顯示/etc/motd文件(message-of-the-day)中的文本信息,並檢查並顯示該用戶是否有郵件的信息。最后login程序改變成登錄用戶的用戶ID,並執行口令文件中該用戶項中指定的shell程序,如/bin/bash或/bin/csh等。有關login程序的一些執行選項和特殊訪問限制的說明,可參見Linux系統中的在線手冊頁(man -8 login)。
(7)執行shell程序或x-windows:如果用戶名和口令正確,login調用exec執行shell命令行解釋程序(當然,也可以執行X-windows的圖形界面,如果用戶設置了的話)。登錄shell會首先從/etc/profile文件以及$HOME/.bash_profile文件(或.bashrc文件,若存在的話)讀取命令並執行。因此用戶可以把每次登錄時都要執行的命令放在.bash_profile文件中。如果在進入shell時設置了ENV環境變量(或者在.bash_profile文件中設置了該變量),則shell還會從$ENV指定的文件中讀去命令並執行。因此我們也可以把每次運行shell都要執行的命令放在ENV變量指定的文件中。設置ENV環境變量的方法是把下列語句放在你起始目錄的.bash_profile文件中: ENV=$HOME/.anyfilename; export ENV。
運行shell時,原來的getty進程最終被替換成了bash進程,對應的getty,login,bash這三個程序也就具有相同的進程ID。在成功登錄到Linux系統后,你會發現(使用”top”或”ps –ax”命令)自己終端原來的getty進程已經找不到了。因為getty進程執行了login程序,被替換成了login進程,並且最后被替換成你的登錄shell進程。對於圖形用戶界面,login程序最后會被替換成圖形界面進程(如gnome-session程序)。
(8)Linux運行時:init進程會負責收取孤兒進程。如果某個進程創建子進程之后,在子進程終止之前終止,則子進程成為孤兒進程。在Linux中所有的進程必須屬於單棵進程樹,所以孤立進程必須被收取。一旦進程成為孤兒,它會立即成為init進程的子進程。這是為了保持進程樹的完整性。
(9)用戶注銷:當某個終端或虛擬控制台上的用戶注銷之后,該終端上的所有進程都會被終止(killed),包括bash。然后,init進程就會調用fork為該終端或虛擬控制台重新創建一個getty進程,以便能夠讓其他用戶登錄。這是為什么呢?你應該發現,當用戶登錄時,“getty”用的是“exec”而不是“fork”系統調用來執行“login”,這樣,“login”在執行的時候會覆蓋“getty”的執行環境(同理,用戶注冊成功后,“login”的執行環境也會被shell占用)。所以,如果想再次使用同一終端,必須再啟動一個“getty”。對於圖形界面,用戶注銷后會回到圖形登錄界面。
(10)系統關閉:init負責殺死所有其它的進程,卸載所有的文件系統並停止處理器的工作,以及任何其它被配置成要做的工作。
以Fedora 14桌面系統中為例(它使用新的upstart init程序,不過它兼容sysvinit),/etc/inittab文件內容如下:
- # inittab is only used by upstart for the default runlevel.
- #
- # ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
- #
- # System initialization is started by /etc/init/rcS.conf
- #
- # Individual runlevels are started by /etc/init/rc.conf
- #
- # Ctrl-Alt-Delete is handled by /etc/init/control-alt-delete.conf
- #
- # Terminal gettys are handled by /etc/init/tty.conf and /etc/init/serial.conf,
- # with configuration in /etc/sysconfig/init.
- #
- # For information on how to write upstart event handlers, or how
- # upstart works, see init(5), init(8), and initctl(8).
- #
- # Default runlevel. The runlevels used are:
- # 0 - halt (Do NOT set initdefault to this)
- # 1 - Single user mode
- # 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
- # 3 - Full multiuser mode
- # 4 - unused
- # 5 - X11
- # 6 - reboot (Do NOT set initdefault to this)
- #
- id:5:initdefault:
Fedora的默認運行級別為5,是多用戶的x-windows圖形界面。與傳統的sysvinit有所不同,在upstart中,只會為默認運行級別使用inittab文件,要添加其他的運行級別,應該放到/etc/init/rc.conf中,而不是inittab中。upstart系統現在首先運行的是/etc/init/rcS.conf,其內容如下(Fedora 14中):
- start on startup
- stop on runlevel
- task
- # Note: there can be no previous runlevel here, if we have one it's bad
- # information (we enter rc1 not rcS for maintenance). Run /etc/rc.d/rc
- # without information so that it defaults to previous=N runlevel=S.
- console output
- exec /etc/rc.d/rc.sysinit
- post-stop script
- if [ "$UPSTART_EVENTS" = "startup" ]; then
- [ -f /etc/inittab ] && runlevel=$(/bin/awk -F ':' '$3 == "initdefault" && $1 !~ "^#" { print $2 }' /etc/inittab)
- [ -z "$runlevel" ] && runlevel="3"
- for t in $(cat /proc/cmdline); do
- case $t in
- -s|single|S|s) runlevel="S" ;;
- [1-9]) runlevel="$t" ;;
- esac
- done
- exec telinit $runlevel
- fi
- end script
upstart首先在系統引導時首先運行rc.sysinit腳本,然后搜索inittab的initdefault,用telinit切換到initdefault的級別來運行。upstart把原來/etc/inittab的功能被分散到/etc/init下的各個conf文件中。
注意不同的Linux發行版會對upstart做一些不同的定制。在ubuntu中,甚至默認不再有/etc/inittab文件了。當然他仍然會處理這個文件(如果有的話),如果你有需要,可以創建這個文件,添加需要的內容。Ubuntu 10.04中的/etc/init/rcS.conf內容如下:
- # rcS - System V single-user mode compatibility
- #
- # This task handles the old System V-style single-user mode, this is
- # distinct from the other runlevels since running the rc script would
- # be bad.
- description "System V single-user mode compatibility"
- author "Scott James Remnant <scott@netsplit.com>"
- start on runlevel S
- stop on runlevel [!S]
- console owner
- script
- if [ -x /usr/share/recovery-mode/recovery-menu ]; then
- exec /usr/share/recovery-mode/recovery-menu
- else
- exec /sbin/sulogin
- fi
- end script
- post-stop script
- # Don't switch runlevels if we were stopped by an event, since that
- # means we're already switching runlevels
- if [ -n "${UPSTART_STOP_EVENTS}" ]
- then
- exit 0
- fi
- # Switch, passing a magic flag
- start --no-wait rc-sysinit FROM_SINGLE_USER_MODE=y
- end script
這里先做一些前期檢查,與Fedora不同的是,第一個執行的腳本換成了/etc/init/rc-sysinit.conf,其內容如下:
- # rc-sysinit - System V initialisation compatibility
- #
- # This task runs the old System V-style system initialisation scripts,
- # and enters the default runlevel when finished.
- description "System V initialisation compatibility"
- author "Scott James Remnant <scott@netsplit.com>"
- start on filesystem and net-device-up IFACE=lo
- stop on runlevel
- # Default runlevel, this may be overriden on the kernel command-line
- # or by faking an old /etc/inittab entry
- env DEFAULT_RUNLEVEL=2
- # There can be no previous runlevel here, but there might be old
- # information in /var/run/utmp that we pick up, and we don't want
- # that.
- #
- # These override that
- env RUNLEVEL=
- env PREVLEVEL=
- console output
- env INIT_VERBOSE
- task
- script
- # Check for default runlevel in /etc/inittab
- if [ -r /etc/inittab ]
- then
- eval "$(sed -nre 's/^[^#][^:]*:([0-6sS]):initdefault:.*/DEFAULT_RUNLEVEL="\1";/p' /etc/inittab || true)"
- fi
- # Check kernel command-line for typical arguments
- for ARG in $(cat /proc/cmdline)
- do
- case "${ARG}" in
- -b|emergency)
- # Emergency shell
- [ -n "${FROM_SINGLE_USER_MODE}" ] || sulogin
- ;;
- [0123456sS])
- # Override runlevel
- DEFAULT_RUNLEVEL="${ARG}"
- ;;
- -s|single)
- # Single user mode
- [ -n "${FROM_SINGLE_USER_MODE}" ] || DEFAULT_RUNLEVEL=S
- ;;
- esac
- done
- # Run the system initialisation scripts
- [ -n "${FROM_SINGLE_USER_MODE}" ] || /etc/init.d/rcS
- # Switch into the default runlevel
- telinit "${DEFAULT_RUNLEVEL}"
- end script
可見Ubuntu是在rc-sysinit.conf中才處理inittab並切換到initdefault級別來運行。
init的完整初始化過程如下(包括啟動字符界面和圖形界面):
- /sbin/init
- --->/etc/init/rcS.conf
- --->exec /etc/rc.d/rc.sysinit 執行第一個腳本(Ubuntu中為/etc/init/rc-sysinit.conf)
- --->/bin/hostname 獲取主機名(設置$HOSTNAME)
- --->/etc/sysconfig/network 配置網絡基本參數
- --->/proc/mounts 檢測並掛載procfs,sysfs到/proc,/sys
- --->/etc/init.d/functions 包含一些通用函數,會被/etc/init.d(是到rc.d/init.d的鏈接)下的腳本用到
- --->/etc/sysconfig/i18n 設置終端字符集
- --->/etc/sysconfig/init 設置終端和圖形界面的一些參數
- --->deamon(),killproc(),pidofproc() 一些通用函數
- --->status(),echo_success(),
- --->update_boot_stage(),strstr()
- --->/selinux/enforce 檢查SELinux的狀態
- --->/etc/system-release 打印熟悉的發行版信息 “Welcome to Fedora ..."
- --->/proc/cmdline 獲取內核啟動的命令行參數
- --->/proc/sys/kernel/modprobe 獲取modprobe的位置(為/sbin/modprobe)
- --->/sbin/sysctl 初始化硬件(通過sysctl設置運行時內核參數)
- --->kill $nashpid 殺死所有的nash進程(我們在initrd中使用的shell)
- --->/sbin/start_udev 啟動udev((動態設備管理進程)
- --->/bin/taskset 設置進程的默認CPU親合值(即優先使用哪個CPU,用在多處理器環境中)
- --->/etc/sysconfig/modules/*.modules 加載其他用戶自定義的模塊
- --->sysctl -e -p /etc/sysctl.conf 配置內核參數
- --->/proc/devices 獲取設備號及相應設備名,以便進行設備初始化
- --->/sbin/dmraid 激活software raid
- --->/sbin/kpartx “/dev/mapper/..." 為software raid上的每塊硬盤創建設備映射
- --->/.autofsck 是否自動執行文件系統檢查
- --->sulogin 若為單用戶模式,執行單用戶登錄程序
- --->plymouth --show-splash 顯示啟動時的背景畫面
- --->/etc/sysconfig/readonly-root 設置root文件系統掛載方式
- --->從/etc/fstab掛載暫存設備
- --->/etc/rwtab, /etc/rwtab.d/* 掛載其他有卷標的分區
- --->ip addr show 獲取並設置網上ip地址
- --->從/etc/fstab掛載持久數據的存儲設備
- --->/etc/statetab, /etc/statetab.d/* 持載其他持久數據的存儲設備
- --->/sbin/fsck 檢查文件系統
- --->umount -a & reboot -f 如果檢查失敗,卸載文件系統並重啟
- --->以讀寫方式重新掛載root文件系統 如果文件系統檢查沒有失敗
- --->掛載所有其他的文件系統
- --->cat /var/lib/random-seed > /dev/urandom 初始化偽隨機數生成器
- --->/usr/sbin/system-config-keyboard,passwd,... 配置機器相關參數(如果有需要的話)
- --->/etc/sysconfig/network 重新讀取網絡配置數據,並重設hostname
- --->清除相關的/, /var,/tmp數據
- --->/sbin/swapon 開啟各個交換區分(根據/proc/swaps)
- --->/usr/sbin/system-config-network-cmd 執行引導時的網絡配置(傳遞內核啟動的netprofile參數)
- --->dmesg -s 131072 > /var/log/dmesg 轉儲內核啟動的消息信息
- --->/etc/inittab
- --->id:5:initdefault: 查找initdefault定義的運行級別(為5,圖形用戶界面)
- --->telinit $runlevel 切換到對應級別運行
- --->/etc/init/rc.conf
- --->exec /etc/rc.d/rc $RUNLEVEL
- --->/etc/profile.d/lang.sh 設置語言環境
- --->/etc/rc.d/rc5.d/KNxxxx 先關閉相關服務(在關閉系統時也會執行)
- --->/etc/rc.d/init.d/xxxx
- --->/etc/rc.d/rc5.d/SNxxxx 再開啟相關服務
- --->etc/rc.d/rc5.d/xxxx
- --->/etc/rc.d/rc.local 在所有init腳本運行完之后運行,可在些添加自己的初始化命令(Ubuntu中為/etc/rc.local)
- --->/etc/init/start-ttys.conf 啟動tty1-tty6設備
- --->/etc/sysconfig/init 指定tty設備,通常為/dev/tty1-/dev/tty6
- --->/etc/init/tty.conf
- --->exec /sbin/mingetty $TTY 在每個tty設備上啟動mingetty
- --->成功后就可以通過Ctrl+Alt+F1..F6在各個不同的tty之間切換
- ################################################# 字符界面 ################################################
- --->fork()--->/sbin/mingetty 運行mingetty程序,出現字符登錄界面
- --->/etc/issue 在登錄界面上顯示發行版信息
- --->exec("/bin/login",...) 運行/bin/login程序,驗證用戶名和口令
- --->/etc/passwd 讀取passwd文件核對用戶名和口令
- --->jackzhou:x:500:500:jackzhou:/home/jackzhou:/bin/bash
- --->切換到工作目錄/home/jackzhou
- --->初始化環境變量$HOME,$PATH等
- --->/etc/motd 顯示當天的消息
- --->檢查新郵件
- --->exec("/bin/bash",...) 運行bash程序
- --->/etc/profile 執行這些腳本中的命令
- --->.bash_profile或.bashrc
- --->ENV=$HOME/.anyfilename; export ENV 運行$ENV指向的腳本(如果設置了的話)
- --->bash運行中 mingetty,login最后替換成了bash,登錄成功
- ################################################## 圖形界面 #############################################
- --->/etc/init/prefdm.conf
- --->exec /etc/X11/prefdm -nodaemon 准備啟動指定的X圖形界面(X Display Manager)
- --->/etc/sysconfig/i18n 設置語言環境
- --->/etc/sysconfig/desktop 讀取指定的DM配置(如果有的話)
- --->exec /usr/sbin/gdm 啟動指定的DM(gdm, kdm, wdm或xdm,默認為/usr/sbin/gdm)
- --->啟動X server窗口
- --->/etc/gdm/custom.conf 根據配置在X窗口中顯示登錄界面
- --->用戶選擇語言、鍵盤布局、會話等
- --->/usr/share/xsessions/gnome.desktop 讀取會話要顯示的名稱
- --->Exec=gnome-session 指定默認的會話程序
- --->用戶輸入用戶名和密碼
- --->用/bin/login驗證用戶名和密碼
- --->/etc/gdm/PreSession/* 執行會話前的一些任務(比如更改X窗口的默認背景)
- --->/etc/gdm/PostLogin/* 執行一些登錄后立即需要運行的命令
- --->/etc/gdm/Xsession gnome-session--->/etc/X11/xinit/Xsession 啟動GNOME會話
- --->/etc/X11/xinit/xinitrc-common 導入Xsession與xinitrc共用的代碼
- --->/etc/profile.d/lang.sh 設置i18n環境
- --->/etc/X11/Xresources 讀取用戶登錄時需要載入的全局資源
- --->/etc/X11/Xmodmap 讀取的全局的鍵盤配置(用於xdm和xinit,用startx啟動圖形界面時要用到)
- --->/etc/X11/xinit/xinitrc.d/* 運行所有的xinitrc腳本
- --->exec -l $SHELL -c gnome-session 執行特定的環境設置(以前是執行./Xclients.d/Xclients.gnome-session.sh)
- --->/etc/X11/xinit/Xclients 運行各個X客戶端的腳本(或者$HOME/.xsession,或者$HOME/.Xclients)
- --->/etc/sysconfig/desktop 讀取指定的會話程序配置(如果有的話)
- --->exec "$(type -p gnome-session)" 默認運行gnome-session,進入GNOME桌面
- --->GNOME桌面運行中 mingetty,login最后替換成了gnome程序,登錄成功
- --->/etc/gdm/PostSession/* GNOME會話結束時運行的腳本
- #################################### 在字符界面下通過startx啟動圖形界面 ##############################################
- --->/bin/bash 在字符界面的Shell下
- --->/usr/bin/startx
- --->記錄$HOME目錄和/etc/X11/xinit下的.xinitrc和.xserverrc文件 以$HOME目錄下的為優先
- --->解析用戶指定的client、server、display參數及其選項
- --->沒有指定參數時就設為前面記錄的.xinitrc和.xserverrc文件
- --->XAUTHORITY=$HOME/.Xauthority 設置XAUTHORITY環境變量
- --->設置X server的權限信息
- --->xinit $client $clientargs -- $server $display $serverargs 啟動X server和第一個X client
- --->/etc/X11/xinit/xinitrc 用來運行各個X client(上面沒有指定第一個client時)
- --->/etc/X11/xinit/xinitrc-common 導入Xsession與xinitrc共用的代碼
- --->/etc/profile.d/lang.sh 設置i18n環境
- --->/etc/X11/Xresources 讀取用戶登錄時需要載入的全局資源
- --->/etc/X11/Xmodmap 讀取全局的鍵盤配置
- --->/etc/X11/xinit/xinitrc.d/* 運行所有的xinitrc腳本
- --->/etc/X11/xinit/Xclients 運行各個X client的腳本(或者$HOME/.Xclients)
- --->/etc/sysconfig/desktop 讀取指定的會話程序配置(如果有的話)
- --->exec "$(type -p gnome-session)" 默認運行gnome-session,進入GNOME桌面
- --->GNOME桌面運行中 mingetty,login最后替換成了gnome程序,登錄成功
- --->/etc/gdm/PostSession/* GNOME會話結束時運行的腳本
注意在rc.sysinit加載完/etc/sysconfig/modules/中(如果你希望額外加載一些比如遙控器之類的模塊,你可以在這里增加腳本)的用戶自定義的模塊后,就會由update_boot_stage通知圖形化的啟動界面,准備進入啟動畫面,內核啟動的命令行參數(在grub中可以看到)中會指定rhgb程序。rhgb程序的作用是在啟動的時候建立一個臨時的僅使用loopback網絡的X窗口服務器,然后在這個窗口上顯示啟動進度,init程序的其他部分可以通過rhgb-client程序向這個進度窗口發送消息。在“配置機器相關參數”這一步中,如果存在/.unconfigured文件,會先調用rhgb-client向進度窗口發送消息,然后調用/usr/bin/system-config-keyboard配置鍵盤,調用 /usr/bin/passwd root配置超級用戶密碼,調用/usr/sbin/system-config-network-tui配置網絡,調用/usr/sbin/timeconfig配置時區,調用 /usr/sbin/authconfig-tui --nostart配置網絡登錄,調用/usr/sbin/ntsysv配置默認的運行級別。然后清空包括/var/lock/,/var/run/, /tmp等在內的臨時目錄,並開啟交換空間。運行完rc.sysinit后,rcS.conf就會查找inittab中的默認運行級別並切換到這個級別。
轉到rc.conf,它調用/etc/rc.d/rc腳本,運行指定級別目錄下的各個啟動腳本。首先按照名稱順序運行那些K打頭的腳本,然后按照名稱順序運行那些S打頭的腳本。啟動腳本(是符號鏈接)中的數字是怎么來的呢,它是由你指定的,如果你要增加自己的啟動腳本到相應的啟動級別中去,這個數字當然應該由你指定,因為只有你才知道這個腳本應該以什么樣的優先級啟動。但是對於那些已經存在的啟動腳本,它們的優先級是在腳本中最前面的注釋行中的chkconfig這一行指定的,在這一行中,你可以看到類似# chkconfig: 35 99 95的字樣,它的含義是:這個腳本應該增加到運行級別3和運行級別5中,啟動的優先級是99,關閉的優先級是95,當然,這些數字是由那些Fedora的開發者測試過沒有問題,所以才寫在這里的。二進制的程序/sbin/chkconfig將會讀取這一行,並且在將服務增加到啟動級別中去的時候自動生成文件名。文件名中的第一個字符S和K代表了什么含義呢?它代表了你在services控制面板中選擇了打開這個服務還是關閉這個服務,如果你在那里打開了這個服務,則以S作為前導符,否則為K。結合我們前面介紹的啟動過程,你就可以知道,在啟動的時候,Fedora會首先保證那些K打頭的腳本是關閉的(通過以stop參數調用這個腳本),然后才會逐個啟動那些S打頭的腳本(通過以start參數調用這個腳本)。對於每個啟動腳本文件,如果想知道啟動了時候都做了些什么,可以查看相應腳本中的start()函數,比如對於avahi-dnsconfd這個腳本,我們可以看到,它只是運行了/usr/sbin/avahi-dnsconfd -D這個命令。
最后執行的初始化腳本是rc.local,你可以在這個腳本中添加自定義的需要啟動的服務或需要執行的命令。在所有需要啟動的服務都啟動完畢以后,rc腳本通過rhgb-client程序通知rhgb圖形界面退出,rhgb的使命就完成了。
init程序在運行完rc.local后,執行/etc/init/start-ttys.conf的配置,它查找init配置文件中的$ACTIVE_CONSOLES指定的每個tty設備(為tty1-tty6),並調用tty.conf啟動這些tty設備。tty.conf會在/dev/tty1-/dev/tty6設備上啟動/sbin/mingetty。從現在開始,你可以通過Ctrl+Alt+F1..F6在各個不同的tty之間進行切換了。
上面“fork()--->/sbin/mingetty”這一部分是指傳統字符界面的啟動及登錄過程,這個過程在前面已經介紹比較清楚了。現在的Linux桌面系統都是登錄到圖形用戶界面,登錄屏幕是圖形界面的形式。下面“/etc/init/start-ttys.conf”這一部分是指圖形界面的啟動和登錄過程。
1)直接啟動圖形界面
在啟動mingetty后,如果運行級別為5,init程序會執行prefdm.conf的配置,它調用/etc/X11/prefdm腳本,准備啟動圖形界面登錄管理器。prefdm將會讀取位於/etc/sysconfig/desktop中的配置文件,如果沒有指定任何配置文件,prefdm運行的順序依次為gdm,kdm,wdm和xdm,從而出現圖形登錄界面。后面的啟動部分就屬於GNOME,KDE或者其它相應的窗口管理器了。
注意,對於Ubuntu,默認運行級別為2,在/etc/rc2.d目錄中包含了啟動登錄管理器gdm的腳本。
無論是gdm,xdm還是kdm,所做的事情都是類似的,即啟動一個X server窗口,基於這個X窗口提供一個圖形化的用戶登錄界面,以便在實際進入X窗口系統之前,對用戶進行驗證,並且提供用戶選擇自己希望的語言,窗口管理器等的機會。除此之外,dm程序一般還支持別的一些操作,比如提供直接關機的選項以及根據配置決定是否打開XDMCP服務的端口等。gdm的配置定義在/etc/gdm/custom.conf中。
XDMCP服務是X窗口顯示管理器控制協議的縮寫,它允許用戶在遠程電腦上運行X窗口服務,然后通過XDMCP協議使用本地的XDM登錄,登錄以后的后續操作將使用遠程的X窗口作為顯示系統。一個很簡單的例子,首先使用gdmsetup程序(系統管理菜單中的登錄窗口)打開XDMCP的支持(遠程選項卡更改為與本地相同),然后打開一個終端窗口,運行Xnest :1 -query 127.0.0.1命令(Xnest並不是默認安裝的命令),你將在一個新開的窗口中看到和你的登錄屏幕一模一樣的登錄屏幕,你可以登錄其它用戶,進行所有和本地用戶一樣的操作。顯然如果你是在另外一台電腦上,只需要把相應的ip地址改掉就可以了。並不一定非要使用Xnest程序,你甚至可以在遠程的Win32系統上進行基於XDMCP的遠程登錄,這首先需要你在你的windows系統上運行一個X 窗口系統,有很多種類似的實現,包括X-win32和cygwin在內的各種免費和收費版本都是一個不錯的選擇,事實上,一台強勁的服務器通過這種方法可以將N台落魄的486PC轉變成可以運行高級科學運算的X終端。除了這些方法,你還可以使用內置於gnome之中的vino程序,這個程序可以基於本地的X窗口打開一個兼容於vnc的服務,你可以使用各種類型的vncviewer來連接這個服務並進行遠程操作(參見首選項菜單中的遠程桌面),這種實現方式下,遠程顯示的屏幕和本地屏幕是完全相同的。或者你也可以使用單獨的vncserver,這種使用方式和XDMCP的使用方法類似,只是登錄的用戶和使用的窗口管理器都是由vncserver指定好的。
在登錄界面上,用戶可以選擇語言、鍵盤布局、會話等。系統內建的幾個會話包括安全模式終端,安全模式gnome以及上一次的成功登錄等,其它的會話則是從配置文件中讀取的,gdm將會在多個目錄中尋找設定的會話,包括/etc/X11/sessions/,/usr/share/gdm/BuiltInSessions/,/usr/share/xsessions/等,路徑可以通過daemon/SessionDesktopDir配置項進行更改,gdm在這些目錄中尋找擴展名為desktop的文件,比如默認會話對應的文件是 /usr/share/gdm/BuiltInSessions/default.desktop,而gnome會話對應的文件為/usr/share/xsessions/gnome.desktop。這些配置文件定義了在不同的語言中這個會話要顯示的名稱。
當用戶選擇了一個X會話,輸入了正確的用戶名和密碼以后,gdm執行命令的順序依次是,首先它將執行位於daemon/PreSessionScriptDir配置項路徑下(默認為/etc/gdm/PreSession/)的所有腳本文件,來執行啟動會話前的一些任務,比如更改X窗口的默認背景之類,然后它將調用位於daemon/PostLoginScriptDir配置的目錄中(默認為/etc/gdm/PostLogin)的腳本,執行一些在剛剛登錄以后需要運行的命令,然后它將以前面提到的desktop文件中定義的exec參數的值作為參數,調用daemon/BaseXsession配置項指定的腳本(默認為/etc/gdm/Xsession),比如如果你選擇的是默認會話,那么執行的命令將會是/etc/gdm/Xsession default,如果你查看這個文件你將發現,在這種情況下,它將首先檢查是否存在主目錄的.xsession文件,如果存在就執行它,否則檢查是否存在主目錄下的.Xclients文件,如果存在則執行它,否則就將執行/etc/X11/xinit/Xclients文件,這個文件根據 /etc/sysconfig/desktop配置文件中的設置運行各個X client,第一個X client默認為執行gnome-session。
運行完gnome-session,我們就進入了GNOME桌面環境。而配置在daemon/PostSessionScriptDir配置項(默認值為/etc/gdm/PostSession/)所設定的目錄中的腳本將在GNOME會話結束以后運行,這意味着無論出於什么原因,gnome程序已經完全退出了,也許是你選擇了注銷命令,也許是X窗口崩潰了,如果你有這方面的需要,可以將相應的腳本放在對應的目錄中。
2)通過startx啟動圖形界面
還有一種啟動圖形界面的方式,就是在登錄到字符界面后,通過運行startx腳本來啟動X圖形界面。startx並不使用gdm來啟動X窗口,而是用xinit程序啟動X。/usr/bin/xinit是一個二進制文件,並非是一個腳本。它的主要功能是啟動一個X服務器,同時啟動第一個基於X的客戶端應用程序。當第一個Client退出時,xinit將殺死X server進程,然后自己終止運行。
參考xinit的man文檔,可知其用法為:xinit [[client] options ] [-- [server] [display] options]。其中client用於指定第一個X客戶端應用程序,client后面的options是傳給這個應用程序的參數,server是用於指定啟動哪個X服務器,一般為/usr/bin/X或/usr/bin/Xorg,display用於指定display number,一般為0,表示第一個display,option為傳給server的參數。
如果不指定client,xinit會查找HOME(環境變量)目錄下的.xinitrc文件,如果存在這個文件,xinit直接調用execvp函數執行該文件,以啟動指定的X客戶端程序。如果這個文件不存在,那么client及其options默認為: xterm -geometry +1+1 -n login -display :0 。
如果不指定server,xinit會查找HOME(環境變量)目錄下的.xserverrc 文件,如果存在這個文件,xinit直接調用execvp函數執行該文件,以啟動指定的X服務器。如果這個文件不存在,那么server及其display為: X :0 。如果系統目錄中不存在X命令,那么我們需要在系統目錄下建立一個名為X的鏈接,使其指向真正的X server命令(Ubuntu下為Xorg)。
下面是幾個關於xinit應用的例子:
(1)xinit /usr/bin/xclock -- /usr/bin/X :0
該例子將啟動X server, 同時將會啟動xclock。請注意指定client或server時,需要用絕對路徑,否則xinit將因無法區別是傳給xterm或server的參數還是指定的client或server而直接當成是參數處理。
(2)在HOME下新建.xinitrc文件,並加入以下幾行:
- xsetroot -solid gray &
- xclock -g 50x50-0+0 -bw 0 &
- xterm -g 80x24+0+0 &
- xterm -g 80x24+0-0 &
- twm
當xinit啟動時,它會先啟動X server,然后啟動一個clock,兩個xterm,最后啟動窗口管理器twm。請注意最后一個命令不能后台運行,否則所有命令都后台運行的話xinit就會返回退出,同樣的,除最后一個命令外都必須后台運行,否則后面的命令將只有在該命令退出后才能運行。
看到這里,眼尖的人或許早以看出xinit的功能完全可以由腳本來實現,例如要啟動X Server和一個xterm,就像xinit默認啟動的那樣,只需要在新建一個腳本或在rc.local中加入:
- X&
- export DISPLAY=:0.0
- xterm
這個實現完全正確,然而卻並沒有完全實現xinit所具有的功能,xinit的功能就是當最后一個啟動的client(如上面第二個例子中的twm窗口管理器)退出后,X服務器也會退出。而我們的腳本實現中當我們退出xterm后並不會退出X server。
startx可以看作是xinit的前端,用法和xinit的基本一樣:startx [[client] options ] [-- [server] [display] options]。為什么呢?這是因為startx其實就是一個腳本,它啟動X server就是通過調用xinit命令實現的,startx的參數將全部傳給xinit。因此,這些參數的意義和xinit的參數是一樣的。
下面是兩個關於startx命令的簡單例子:
(1)startx -- -depth 16:以16位色啟動X 服務器。
(2)startx -- -dpi 100:以100的dpi啟動X 服務器。
startx會先記錄$HOME下的.xinitrc和.xserverrc文件(如果有的話),系統目錄/etc/X11/xinit/下的xinitrc和.xserverrc文件。然后解析用戶的參數,如果該用戶指定了該參數,那么startx就會以該參數來啟動xinit,否則就會解析$HOME目錄下的.xinitrc和.xserverrc文件,如果該文件不存在,就會解析系統目錄下(/etc/X11/xinit/)的xinitrc和xserverrc文件,如果這個文件也不存在,那 startx就將以默認的client(xterm)和server(/usr/bin/X)為參數來啟動xinit。
在Fedora 14中,只有/etc/X11/xinit/xinitrc文件,由它來運行Xclients腳本,這個腳本用於運行各個指定的X client,其中的第一個X client即為gnome-session,這就是GNOME桌面環境。從代碼可知,xinitrc的功能與Xsession幾乎一樣,只有一些細微的差別(在Ubuntu中xinitrc是直接調用Xsession的)。
完整的Linux init程序啟動過程如下圖:
圖1 Linux init程序啟動過程
2、initng介紹
由於傳統的init進程(sysvinit)是一個串行化的進程,因此可對這部分系統進行充分優化。實際上,您可以使用任何方法來對init進程進行優化。其中最簡單方法是禁用不必要的服務。例如,如果您運行的是一個桌面系統(而不是一個服務器),就可以禁用諸如 apache、sendmail 和 mysql 之類的服務,這樣可以縮短init序列。
其他的一些init程序版本解決了這個問題。一種是基於依賴關系的(即使用依賴關系來提供並行化,如新版的initng),一種是一個基於事件的系統(即進程依賴於事件來表示自己何時啟動或停止,如upstart)。
initng(下一代 init)可以完全取代異步啟動進程的init,它能更加快速地完成init進程。initng 背后的基本思想是只要滿足了服務的依賴關系就可啟動。這樣系統就可以在 CPU 和 I/O 之間實現較好的平衡。當從磁盤上加載一個腳本或等待硬件設備啟動的同時,可以運行另一個腳本來啟動另外一個服務。
作為一個基於依賴關系的解決方案,initng 使用自己的初始化腳本集,它們對服務和守護進程的依賴性進行了編碼。清單 2 展示了一個示例。這個腳本指定了需要為給定的運行級別啟動的服務。該服務具有兩個依賴關系,使用 need 關鍵字定義,分別是 system/initial 和 net/all。在 system/my_service 可以啟動之前,這些服務必須是可用的。當這些服務可用時,exec 關鍵字就開始起作用了。exec 關鍵字(以及 start 選項)定義了如何使用任何可用的選項啟動服務。要停止這個服務,就會使用 exec 關鍵字以及 stop 選項。
清單 2. 為 initng 定義服務
- service system/my_service {
- need = system/initial net/all;
- exec start = /sbin/my_service --start --option;
- exec stop = /sbin/my_service --stop --option;
- }
您可以使用服務定義對整個系統進行編碼,如清單 2 所示。那些沒有依賴關系的服務可以立即(並行地)啟動,而具有依賴關系的服務則必須等待以安全啟動。您可以將 initng 看作一個基於目標的系統。其目標就是要啟動的服務。沒有進行顯式的規划;相反,依賴關系簡單地定義了服務初始化的流程,這個過程中隱含着並行化的操作。
initng 的典型安裝需要 initng 發行版(源代碼或二進制文件)和 ifiles 發行版。您可以使用 ./configure、make 和 make install 編譯自己的 initng 發行版。您必須使用 cmake 來編譯 ifiles 文件(這是腳本文件)。根據系統需求的不同,您可能需要創建新的服務/守護進程定義(不過很可能 initng 社區中已經有人這樣做了)。然后您還必須修改 LILO 或 GRUB 的配置以指向新的 /sbin/initng。要控制 initng,需要使用 ngc(對應telinit 與傳統的 init)。它們的語法有些不同,不過功能是相同的。