虚拟机分配的内存较小,需要关闭图形界面。通过分析发现,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 grim 15 * reaper of innocent orphaned children. 16 * 17 * We don‘t want people to have to make incorrect 18 * assumptions about where in the task array this 19 * 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 all 37 * the work 38 */ 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, and 50 * we‘re essentially up and running. Get rid of the 51 * 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 are 30 * 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直接拿来主义了。它最大的优点:支持事件和热插拔。参考这里:http://upstart.ubuntu.com/cookbook/
/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: 即可每次重启到控制台界面。