虚拟机分配的内存较小,需要关闭图形界面。通过分析发现,kernel启动时,执行kernel_init()函数(init/main.c):先新建一个initrd(init Ram Disk,内存中的文件系统,挂载到/),然后执行init_post()。
1 static int __init kernel_init(void * unused) 2 { 3 lock_kernel(); 4 5 /* 6 * init can allocate pages on any node 7 */ 8 set_mems_allowed(node_possible_map); 9 /*10 * init can run on any cpu.11 */12 set_cpus_allowed_ptr(current, cpu_all_mask);13 /*14 * Tell the world that we're going to be the grim15 * reaper of innocent orphaned children.16 *17 * We don't want people to have to make incorrect18 * assumptions about where in the task array this19 * can be found.20 */21 init_pid_ns.child_reaper = current;22 23 cad_pid = task_pid(current);24 25 smp_prepare_cpus(setup_max_cpus);26 27 do_pre_smp_initcalls();28 start_boot_trace();29 30 smp_init();31 sched_init_smp();32 33 do_basic_setup();34 35 /*36 * check if there is an early userspace init. If yes, let it do all37 * the work38 */39 40 if (!ramdisk_execute_command)41 ramdisk_execute_command = "/init";42 43 if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {44 ramdisk_execute_command = NULL;45 prepare_namespace();46 }47 48 /*49 * Ok, we have completed the initial bootup, and50 * we're essentially up and running. Get rid of the51 * initmem segments and start the user-mode stuff..52 */53 54 init_post();55 return 0;56 }
而在init_post()中,试图从多个位置查找init可执行文件,最后运行shell兜底(37~40行):
1 static noinline int init_post(void) 2 __releases(kernel_lock) 3 { 4 /* need to finish all async __init code before freeing the memory */ 5 async_synchronize_full(); 6 free_initmem(); 7 unlock_kernel(); 8 mark_rodata_ro(); 9 system_state = SYSTEM_RUNNING;10 numa_default_policy();11 12 if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)13 printk(KERN_WARNING "Warning: unable to open an initial console.\n");14 15 (void) sys_dup(0);16 (void) sys_dup(0);17 18 current->signal->flags |= SIGNAL_UNKILLABLE;19 20 if (ramdisk_execute_command) {21 run_init_process(ramdisk_execute_command);22 printk(KERN_WARNING "Failed to execute %s\n",23 ramdisk_execute_command);24 }25 26 /*27 * We try each of these until one succeeds.28 *29 * The Bourne shell can be used instead of init if we are30 * trying to recover a really broken machine.31 */32 if (execute_command) {33 run_init_process(execute_command);34 printk(KERN_WARNING "Failed to execute %s. Attempting "35 "defaults...\n", execute_command);36 }37 run_init_process("/sbin/init");38 run_init_process("/etc/init");39 run_init_process("/bin/init");40 run_init_process("/bin/sh");41 42 panic("No init found. Try passing init= option to kernel.");43 }
在CentOS6中,/sbin/init属于upstart这个包,它是ubuntu对传统System V init daemon的一项重大改进,CentOS直接拿来主义了。它最大的优点:支持事件和热插拔。参考这里:
/sbin/init|__/etc/init/*.conf 或*.override 系统级|__/etc/dbus-1/system.d/Upstart.conf 用户级
而/etc/init/rc.conf、/etc/init/rcS.conf是/sbin/init执行的2个普通任务,
- /etc/init/rc.conf
|__ /etc/rc.d/rc
它遍历:/etc/rc$runlevel.d/K*后执行initctl starting JOB=.... 来启动各种服务- /etc/init/rcS.conf
|__ /etc/rc.d/rc.sysinit
|__ /etc/inittab: 【这里获取要进入的runlevel,id:5:initdefault:,5表示GUI界面】 |__ exec telinit $runlevel 【注意这里是重点,直接设置当前runlevel】- chkconfig 改变的是/etc/rcXX.d 链接
【注】CentOS7 用 /lib/systemd/system/default.target来取代/etc/inittab。
所以,只需要修改/etc/inittab: id:3:initdefault: 即可每次重启到控制台界面。