linux Init分析(原创)
1.uboot的目标就是启动内核kernel;
2.kernel的目的就是启动应用程序,而第一个应用程序即是Init,构建根文件系统。
从uboot初始化配置后,引导内核的启动,启动函数为:start_kernel(void)
其他可以先不管,我们需要的是看看rest_init()函数;
代码如下:
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern struct kernel_param __start___param[], __stop___param[]; smp_setup_processor_id(); /*
* Need to run as early as possible, to initialize the
* lockdep hash:
*/
lockdep_init();
debug_objects_early_init(); /*
* Set up the the initial canary ASAP:
*/
boot_init_stack_canary(); cgroup_init_early(); local_irq_disable();
early_boot_irqs_off();
early_init_irq_lock_class(); /*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
lock_kernel();
tick_init();
boot_cpu_init();
page_address_init();
printk(KERN_NOTICE "%s", linux_banner);
setup_arch(&command_line);
mm_init_owner(&init_mm, &init_task);
setup_command_line(command_line);
setup_nr_cpu_ids();
setup_per_cpu_areas();
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */ build_all_zonelists(NULL);
page_alloc_init(); printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
parse_early_param();
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);
/*
* These use large bootmem allocations and must precede
* kmem_cache_init()
*/
pidhash_init();
vfs_caches_init_early();
sort_main_extable();
trap_init();
mm_init();
/*
* Set up the scheduler prior starting any interrupts (such as the
* timer interrupt). Full topology setup happens at smp_init()
* time - but meanwhile we still have a functioning scheduler.
*/
sched_init();
/*
* Disable preemption - early bootup scheduling is extremely
* fragile until we cpu_idle() for the first time.
*/
preempt_disable();
if (!irqs_disabled()) {
printk(KERN_WARNING "start_kernel(): bug: interrupts were "
"enabled *very* early, fixing it\n");
local_irq_disable();
}
rcu_init();
radix_tree_init();
/* init some links before init_ISA_irqs() */
early_irq_init();
init_IRQ();
prio_tree_init();
init_timers();
hrtimers_init();
softirq_init();
timekeeping_init();
time_init();
profile_init();
if (!irqs_disabled())
printk(KERN_CRIT "start_kernel(): bug: interrupts were "
"enabled early\n");
early_boot_irqs_on();
local_irq_enable(); /* Interrupts are enabled now so all GFP allocations are safe. */
gfp_allowed_mask = __GFP_BITS_MASK; kmem_cache_init_late(); /*
* HACK ALERT! This is early. We're enabling the console before
* we've done PCI setups etc, and console_init() must be aware of
* this. But we do want output early, in case something goes wrong.
*/
console_init();
if (panic_later)
panic(panic_later, panic_param); lockdep_info(); /*
* Need to run this when irqs are enabled, because it wants
* to self-test [hard/soft]-irqs on/off lock inversion bugs
* too:
*/
locking_selftest(); #ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start && !initrd_below_start_ok &&
page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
"disabling it.\n",
page_to_pfn(virt_to_page((void *)initrd_start)),
min_low_pfn);
initrd_start = ;
}
#endif
page_cgroup_init();
enable_debug_pagealloc();
kmemtrace_init();
kmemleak_init();
debug_objects_mem_init();
idr_init_cache();
setup_per_cpu_pageset();
numa_policy_init();
if (late_time_init)
late_time_init();
sched_clock_init();
calibrate_delay();
pidmap_init();
anon_vma_init();
#ifdef CONFIG_X86
if (efi_enabled)
efi_enter_virtual_mode();
#endif
thread_info_cache_init();
cred_init();
fork_init(totalram_pages);
proc_caches_init();
buffer_init();
key_init();
security_init();
dbg_late_init();
vfs_caches_init(totalram_pages);
signals_init();
/* rootfs populating might need page-writeback */
page_writeback_init();
#ifdef CONFIG_PROC_FS
proc_root_init();
#endif
cgroup_init();
cpuset_init();
taskstats_init_early();
delayacct_init(); check_bugs(); acpi_early_init(); /* before LAPIC and SMP init */
sfi_init_late(); ftrace_init(); /* Do the rest non-__init'ed, we're now alive */
rest_init();
}
rest_init()函数,如下:
static noinline void __init_refok rest_init(void)
__releases(kernel_lock)
{
int pid; rcu_scheduler_starting();
/*
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
numa_default_policy();
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
rcu_read_lock();
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
complete(&kthreadd_done);
unlock_kernel(); /*
* The boot idle thread must execute schedule()
* at least once to get things moving:
*/
init_idle_bootup_task(current);
preempt_enable_no_resched();
schedule();
preempt_disable(); /* Call into cpu_idle with preempt disabled */
cpu_idle();
}
我们可以看到内核有一个内核的初始化线程:
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
进入看看到底是实现什么东西:
static int __init kernel_init(void * unused)
{
/*
* Wait until kthreadd is all set-up.
*/
wait_for_completion(&kthreadd_done);
lock_kernel(); /*
* init can allocate pages on any node
*/
set_mems_allowed(node_states[N_HIGH_MEMORY]);
/*
* init can run on any cpu.
*/
set_cpus_allowed_ptr(current, cpu_all_mask);
/*
* Tell the world that we're going to be the grim
* reaper of innocent orphaned children.
*
* We don't want people to have to make incorrect
* assumptions about where in the task array this
* can be found.
*/
init_pid_ns.child_reaper = current; cad_pid = task_pid(current); smp_prepare_cpus(setup_max_cpus); do_pre_smp_initcalls();
start_boot_trace(); smp_init();
sched_init_smp(); do_basic_setup(); /* Open the /dev/console on the rootfs, this should never fail */
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n"); (void) sys_dup(0);
(void) sys_dup(0);
/*
* check if there is an early userspace init. If yes, let it do all
* the work
*/ if (!ramdisk_execute_command)
ramdisk_execute_command = "/init"; if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
ramdisk_execute_command = NULL;
prepare_namespace();
} /*
* Ok, we have completed the initial bootup, and
* we're essentially up and running. Get rid of the
* initmem segments and start the user-mode stuff..
*/ init_post();
return 0;
}
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n"); (void) sys_dup(0);
(void) sys_dup(0);
上面代码实现的是控制台的输入,输出,还有error,好,现在,目前为止还没有看到真正的好东西,接着往下看
init_post();
static noinline int init_post(void)
__releases(kernel_lock)
{
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy(); current->signal->flags |= SIGNAL_UNKILLABLE; if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command);
} /*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
run_init_process(execute_command);
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults...\n", execute_command);
}
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh"); panic("No init found. Try passing init= option to kernel. "
"See Linux Documentation/init.txt for guidance.");
}
好东西终于出现了:
if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command);
}
这个是干啥用的呢,搜索一下发现、
static int __init init_setup(char *str)
{
unsigned int i;
execute_command = str;
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
__setup("init=", init_setup);//设置命令行参数时候如:init=/linuxrc
查看一下:
# ls /linuxrc -l
lrwxrwxrwx 1 root root 11 Oct 25 2013 /linuxrc -> bin/busybox
那么linux就先启动/linuxrc
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
从函数名字来看run_init_process(“”)函数是用来初始化init进程的。在众多的书籍中,都介绍着,我们的linux系统最先启动的是init进程,我们可以直观的ps命令知道,init的pid = 1 因此我们有理由相信至此,我们找到好东西了。
首先 我们在linux的shell下
# ls /sbin/init -l
lrwxrwxrwx 1 root root 14 Oct 25 2013 /sbin/init -> ../bin/busybox
/sbin/init 指向/bin/busybox ;
至此我们发现所启动的程序都是指向busybox本身。因此我们需要分析busybox本身才能知道到底发生了什么.
解压busybox-1.16.1 建立工程。我们找到init.c的文件。当然里面也有cp.c ls.c等文件,linux是借助busybox来实现这些命令的,如果需要在应用程序里面实现某些类似功能可以参考busybox的源码。
我们先看init.c里面的main函数:
看看都做了什么东西:
int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int init_main(int argc UNUSED_PARAM, char **argv)
{
die_sleep = * **; /* if xmalloc would ever die... */ if (argv[] && strcmp(argv[], "-q") == ) {
return kill(, SIGHUP);
} if (!DEBUG_INIT) {
/* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
if (getpid() !=
&& (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc"))
) {
bb_show_usage();
}
/* Turn off rebooting via CTL-ALT-DEL - we get a
* SIGINT on CAD so we can shut things down gracefully... */
reboot(RB_DISABLE_CAD); /* misnomer */
} /* Figure out where the default console should be */
console_init();
set_sane_term();
xchdir("/");
setsid(); /* Make sure environs is set to something sane */
putenv((char *) "HOME=/");
putenv((char *) bb_PATH_root_path);
putenv((char *) "SHELL=/bin/sh");
putenv((char *) "USER=root"); /* needed? why? */ if (argv[])
xsetenv("RUNLEVEL", argv[]); #if !ENABLE_FEATURE_EXTRA_QUIET
/* Hello world */
message(L_CONSOLE | L_LOG, "init started: %s", bb_banner);
#endif /* Make sure there is enough memory to do something useful. */
if (ENABLE_SWAPONOFF) {
struct sysinfo info; if (sysinfo(&info) ==
&& (info.mem_unit ? info.mem_unit : ) * (long long)info.totalram < *
) {
message(L_CONSOLE, "Low memory, forcing swapon");
/* swapon -a requires /proc typically */
new_init_action(SYSINIT, "mount -t proc proc /proc", "");
/* Try to turn on swap */
new_init_action(SYSINIT, "swapon -a", "");
run_actions(SYSINIT); /* wait and removing */
}
} /* Check if we are supposed to be in single user mode */
if (argv[]
&& (strcmp(argv[], "single") == || strcmp(argv[], "-s") == || LONE_CHAR(argv[], ''))
) {
/* ??? shouldn't we set RUNLEVEL="b" here? */
/* Start a shell on console */
new_init_action(RESPAWN, bb_default_login_shell, "");
} else {
/* Not in single user mode - see what inittab says */ /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
* then parse_inittab() simply adds in some default
* actions(i.e., INIT_SCRIPT and a pair
* of "askfirst" shells */
parse_inittab();
}
#if ENABLE_SELINUX
if (getenv("SELINUX_INIT") == NULL) {
int enforce = ; putenv((char*)"SELINUX_INIT=YES");
if (selinux_init_load_policy(&enforce) == ) {
BB_EXECVP(argv[], argv);
} else if (enforce > ) {
/* SELinux in enforcing mode but load_policy failed */
message(L_CONSOLE, "can't load SELinux Policy. "
"Machine is in enforcing mode. Halting now.");
exit(EXIT_FAILURE);
}
}
#endif /* Make the command line just say "init" - thats all, nothing else */
strncpy(argv[], "init", strlen(argv[]));
/* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
while (*++argv)
memset(*argv, , strlen(*argv)); /* Set up signal handlers */
if (!DEBUG_INIT) {
struct sigaction sa; bb_signals(
+ ( << SIGUSR1) /* halt */
+ ( << SIGTERM) /* reboot */
+ ( << SIGUSR2) /* poweroff */
, halt_reboot_pwoff);
signal(SIGQUIT, restart_handler); /* re-exec another init */ /* Stop handler must allow only SIGCONT inside itself */
memset(&sa, , sizeof(sa));
sigfillset(&sa.sa_mask);
sigdelset(&sa.sa_mask, SIGCONT);
sa.sa_handler = stop_handler;
/* NB: sa_flags doesn't have SA_RESTART.
* It must be able to interrupt wait().
*/
sigaction_set(SIGTSTP, &sa); /* pause */
/* Does not work as intended, at least in 2.6.20.
* SIGSTOP is simply ignored by init:
*/
sigaction_set(SIGSTOP, &sa); /* pause */ /* SIGINT (Ctrl-Alt-Del) must interrupt wait(),
* setting handler without SA_RESTART flag.
*/
bb_signals_recursive_norestart(( << SIGINT), record_signo);
} /* Set up "reread /etc/inittab" handler.
* Handler is set up without SA_RESTART, it will interrupt syscalls.
*/
if (!DEBUG_INIT && ENABLE_FEATURE_USE_INITTAB)
bb_signals_recursive_norestart(( << SIGHUP), record_signo); /* Now run everything that needs to be run */
/* First run the sysinit command */
run_actions(SYSINIT);
check_delayed_sigs();
/* Next run anything that wants to block */
run_actions(WAIT);
check_delayed_sigs();
/* Next run anything to be run only once */
run_actions(ONCE); /* Now run the looping stuff for the rest of forever.
*/
while () {
int maybe_WNOHANG; maybe_WNOHANG = check_delayed_sigs(); /* (Re)run the respawn/askfirst stuff */
run_actions(RESPAWN | ASKFIRST);
maybe_WNOHANG |= check_delayed_sigs(); /* Don't consume all CPU time - sleep a bit */
sleep();
maybe_WNOHANG |= check_delayed_sigs(); /* Wait for any child process(es) to exit.
*
* If check_delayed_sigs above reported that a signal
* was caught, wait will be nonblocking. This ensures
* that if SIGHUP has reloaded inittab, respawn and askfirst
* actions will not be delayed until next child death.
*/
if (maybe_WNOHANG)
maybe_WNOHANG = WNOHANG;
while () {
pid_t wpid;
struct init_action *a; /* If signals happen _in_ the wait, they interrupt it,
* bb_signals_recursive_norestart set them up that way
*/
wpid = waitpid(-, NULL, maybe_WNOHANG);
if (wpid <= )
break; a = mark_terminated(wpid);
if (a) {
message(L_LOG, "process '%s' (pid %d) exited. "
"Scheduling for restart.",
a->command, wpid);
}
/* See if anyone else is waiting to be reaped */
maybe_WNOHANG = WNOHANG;
}
} /* while (1) */
}
首先看一下
if (argv[1]
60 && (strcmp(argv[1], "single") == 0 || strcmp(argv[1], "-s") == 0 || LONE_CHAR(argv[1], '1'))
61 ) {
62 /* ??? shouldn't we set RUNLEVEL="b" here? */
63 /* Start a shell on console */
64 new_init_action(RESPAWN, bb_default_login_shell, "");
65 } else {
66 /* Not in single user mode - see what inittab says */
67
68 /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
69 * then parse_inittab() simply adds in some default
70 * actions(i.e., INIT_SCRIPT and a pair
71 * of "askfirst" shells */
72 parse_inittab();
73 }
argv[1]参数是空的,实际上我们之前启动的内核init进程也是没有参数的,因此linux走的是另外的分支即是:
parse_inittab();
static void parse_inittab(void)
{
#if ENABLE_FEATURE_USE_INITTAB
char *token[];
parser_t *parser = config_open2("/etc/inittab", fopen_for_read); if (parser == NULL)
#endif
{
/* No inittab file - set up some default behavior */
/* Reboot on Ctrl-Alt-Del */
new_init_action(CTRLALTDEL, "reboot", "");
/* Umount all filesystems on halt/reboot */
new_init_action(SHUTDOWN, "umount -a -r", "");
/* Swapoff on halt/reboot */
if (ENABLE_SWAPONOFF)
new_init_action(SHUTDOWN, "swapoff -a", "");
/* Prepare to restart init when a QUIT is received */
new_init_action(RESTART, "init", "");
/* Askfirst shell on tty1-4 */
new_init_action(ASKFIRST, bb_default_login_shell, "");
//TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
/* sysinit */
new_init_action(SYSINIT, INIT_SCRIPT, "");
return;
} #if ENABLE_FEATURE_USE_INITTAB
/* optional_tty:ignored_runlevel:action:command
* Delims are not to be collapsed and need exactly 4 tokens
*/
while (config_read(parser, token, , , "#:",
PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
/* order must correspond to SYSINIT..RESTART constants */
static const char actions[] ALIGN1 =
"sysinit\0""wait\0""once\0""respawn\0""askfirst\0"
"ctrlaltdel\0""shutdown\0""restart\0";
int action;
char *tty = token[]; if (!token[]) /* less than 4 tokens */
goto bad_entry;
action = index_in_strings(actions, token[]);
if (action < || !token[][]) /* token[3]: command */
goto bad_entry;
/* turn .*TTY -> /dev/TTY */
if (tty[]) {
if (strncmp(tty, "/dev/", ) == )
tty += ;
tty = concat_path_file("/dev/", tty);
}
new_init_action( << action, token[], tty);
if (tty[])
free(tty);
continue;
bad_entry:
message(L_LOG | L_CONSOLE, "Bad inittab entry at line %d",
parser->lineno);
}
config_close(parser);
#endif
}
parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
我们看名字可以得知此语句是去读取配置文件/etc/inittab。如果没有/etc/inittab文件(if (parser == NULL)),我们就给它配置一个默认的inittab文件
海思开发板下看一下:
# cat /etc/inittab
# /etc/inittab init() configuration for BusyBox
#
# Copyright (C) - by Erik Andersen <andersen@codepoet.org>
#
#
# Note, BusyBox init doesn't support runlevels. The runlevels field is
# completely ignored by BusyBox init. If you want runlevels, use sysvinit.
#
#
# Format for each entry: <id>:<runlevels>:<action>:<process>
#
# <id>: WARNING: This field has a non-traditional meaning for BusyBox init!
#
# The id field is used by BusyBox init to specify the controlling tty for
# the specified process to run on. The contents of this field are
# appended to "/dev/" and used as-is. There is no need for this field to
# be unique, although if it isn't you may have strange results. If this
# field is left blank, it is completely ignored. Also note that if
# BusyBox detects that a serial console is in use, then all entries
# containing non-empty id fields will _not_ be run. BusyBox init does
# nothing with utmp. We don't need no stinkin' utmp.
#
# <runlevels>: The runlevels field is completely ignored.
#
# <action>: Valid actions include: sysinit, respawn, askfirst, wait, once,
# restart, ctrlaltdel, and shutdown.
#
# Note: askfirst acts just like respawn, but before running the specified
# process it displays the line "Please press Enter to activate this
# console." and then waits for the user to press enter before starting
# the specified process.
#
# Note: unrecognised actions (like initdefault) will cause init to emit
# an error message, and then go along with its business.
#
# <process>: Specifies the process to be executed and it's command line.
#
# Note: BusyBox init works just fine without an inittab. If no inittab is
# found, it has the following default behavior:
# ::sysinit:/etc/init.d/rcS
# ::askfirst:/bin/sh
# ::ctrlaltdel:/sbin/reboot
# ::shutdown:/sbin/swapoff -a
# ::shutdown:/bin/umount -a -r
# ::restart:/sbin/init
#
# if it detects that /dev/console is _not_ a serial console, it will
# also run:
# tty2::askfirst:/bin/sh
# tty3::askfirst:/bin/sh
# tty4::askfirst:/bin/sh
#
# Boot-time system configuration/initialization script.
# This is run first except when booting in single-user mode.
#
::sysinit:/etc/init.d/rcS # /bin/sh invocations on selected ttys
#
# Note below that we prefix the shell commands with a "-" to indicate to the
# shell that it is supposed to be a login shell. Normally this is handled by
# login, but since we are bypassing login in this case, BusyBox lets you do
# this yourself...
#
# Start an "askfirst" shell on the console (whatever that may be)
#::askfirst:-/bin/sh
# Start an "askfirst" shell on /dev/tty2-
# tty2::askfirst:-/bin/sh
# tty3::askfirst:-/bin/sh
# tty4::askfirst:-/bin/sh # /sbin/getty invocations for selected ttys
# tty4::respawn:/sbin/getty tty5
# tty5::respawn:/sbin/getty tty6 # Example of how to put a getty on a serial line (for a terminal)
::respawn:/sbin/getty -L ttyS000 vt100 -n root -I "Auto login as root ..."
#::respawn:/sbin/getty -L ttyS1 vt100
#
# Example how to put a getty on a modem line.
#::respawn:/sbin/getty ttyS2 # Stuff to do when restarting the init process
::restart:/sbin/init # Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
前面两个冒号空的不用管,ctrlaltdel shutdown 是一下组合键或者操作的动作的信号发生后才运行的。
我们找到这句:new_init_action(1 << action, token[3], tty);
仔细读源码,我们可以知道它是将/etc/inittab配置文件的每一项执行完后就将其他从链表中删除。
我们在配置文件/etc/inittab发现一个脚本:
::sysinit:/etc/init.d/rcS
看看它想干嘛的:
#! /bin/sh /bin/mount -a echo "
_ _ _ _ _ _ _ _ _ _ _ _
\ _ _ _ _ _ ___
/ /__/ \ |_/
/ __ / - _ ___
/ / / / / /
_ _ _ _/ / / \_/ \_ ______
___________\___\__________________
"
for initscript in /etc/init.d/S[-][-]*
do
if [ -x $initscript ] ;
then
echo "[RCS]: $initscript"
$initscript
fi
done
我们发现一个很重要的一项:
/bin/mount -a 它的意思是将会执行/etc/fstab脚本。我们在海思平台上看一下:
# cat /etc/fstab
proc /proc proc defaults
sysfs /sys sysfs defaults
tmpfs /dev tmpfs defaults
这里涉及一个udev机制,详细请查看文章mdev解析,这里意思是将linux虚拟的文件系统proc sysfs tmpfs 挂载到对应的目录这样,我们就不必要手动去创建了。
for initscript in /etc/init.d/S[-][-]*
do
if [ -x $initscript ] ;
then
echo "[RCS]: $initscript"
$initscript
fi
done
上面的for循环是干嘛用的呢,我们可以大胆猜测下,应该是if(满足某种条件如具备可执行条件)就循环执行一个目录下的脚本。
我们去看看/etc/init.d/目录下都有哪些脚本:
# cd /etc/init.d/
# ls
S00devs S01udev S80network S90modules rcS
# cat S90modules
#!/bin/sh telnetd&
cd /kmod
./load
cd -
我们挑一些来看看,如S90modules,发现它的作用就是启动/kmod/load脚本,我们再看看具体都做了哪些东西:
# cat /kmod/load
rmmod ufsd
rmmod ohci-hcd
rmmod ehci-hcd
rmmod png
rmmod jpge
rmmod jpeg
rmmod hi_wdg
rmmod hi_keyled
rmmod hi_e2prom
rmmod hi_cipher
rmmod hi_ir
rmmod hi_sci
rmmod hifb
rmmod hi_tuner
rmmod hi_svdec.ko
rmmod hi_mpi
rmmod hi_ndpt
rmmod hi_otp
rmmod tde
#rmmod hi_usbprotected
rmmod hi_i2c
rmmod hi_gpioi2c
rmmod hi_gpio
rmmod hi_dmac
rmmod hi_common
rmmod hi_mmz
rmmod hi_c51
rmmod hi_media
insmod hi_c51.ko
insmod hi_mmz.ko
insmod hi_common.ko
insmod hi_dmac.ko
insmod hi_gpio.ko
insmod hi_gpioi2c.ko gpioidclock= clockbit= gpioiddata= databit= i2cmode=
insmod hi_i2c.ko
#insmod hi_usbprotected.ko Usb0PwrEn= Usb0Ovrcur= Usb0IntType=
insmod tde.ko
insmod hi_otp.ko
insmod hi_ndpt.ko
insmod hi_mpi.ko
insmod hi_svdec.ko
insmod hi_tuner.ko
insmod hifb.ko video="hifb:vram0_size:2430, vram2_size:7200"
insmod hi_sci.ko
insmod hi_ir.ko
insmod hi_cipher.ko
insmod hi_e2prom.ko
insmod hi_keyled.ko
insmod hi_wdg.ko
insmod jpeg.ko
insmod jpge.ko
insmod png.ko
insmod /kmod/usb/ehci-hcd.ko
insmod /kmod/usb/ohci-hcd.ko
echo > /proc/sys/vm/dirty_ratio
insmod ufsd.ko
mount -t squashfs /dev/romblock11 /home
mount -t yaffs2 /dev/mtdblock12 /reserved
mount -t yaffs2 /dev/mtdblock13 /mnt
mount -t tmpfs nodev /tmp
echo > /proc/sys/vm/overcommit_memory
echo > /proc/sys/vm/min_free_kbytes
我们不难知道,load脚本主要是执行一些驱动模块的卸载,加载,还有将/dev下的一些分区用正确的格式挂载到对应的目录下。
至此,我们的分析基本完毕,另外还有app的启动也是用脚本,在进入linux时候启动起来的。
# pwd
/etc
# cat profile
# /etc/profile: system-wide .profile file for the Bourne shells
#
# set_path_before()
{
[ -d $ ] && PATH="$1:$PATH"
} PATH="/usr/bin:/usr/sbin:/bin:/sbin"
set_path_before /usr/local/sbin
set_path_before /usr/local/bin LD_LIBRARY_PATH="/usr/local/lib:/usr/lib" export PATH
export LD_LIBRARY_PATH # ANSI COLORS
"
NORMAL=""
RED=""
GREEN=""
YELLOW=""
BLUE=""
MAGENTA=""
CYAN=""
WHITE="" umask if [ -e /tmp/run_flag ]; then
echo "app is running already! "
exit
else
touch /tmp/run_flag
fi
#ifconfig eth1 192.168.5.177
#route add DEFAULT 192.168.5.177
#ifconfig lo 127.0.0.1
#/usr/sbin/udhcpd -S /etc/udhcpd.conf
#echo "" >/proc/sys/net/ipv4/ip_forward
#cd /etc
#./iptables.sh himm 0x600d1310 0x5F1
ifconfig eth0 up
ifconfig eth1 up echo "${GREEN}Welcome to HiLinux.${NORMAL}"
cd /home
while true
do
./appmain
killall - udhcpc
usleep
./appmain
done
/etc/profile 文件是登陆linux时候就运行的,app此时启动了。
# cat /etc/fstab proc /proc proc defaults 0 0sysfs /sys sysfs defaults 0 0tmpfs /dev tmpfs defaults 0 0
linux Init分析(原创)的更多相关文章
- Linux内核分析-使用gdb跟踪调试内核从start_kernel到init进程启动
姓名:江军 ID:fuchen1994 实验日期:2016.3.13 实验指导 使用实验楼的虚拟机打开shell cd LinuxKernel/ qemu -kernel linux-3.18.6/a ...
- 【原创】一文掌握 Linux 性能分析之 I/O 篇
本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 一文掌握 Li ...
- linux内核分析作业3:跟踪分析Linux内核的启动过程
内核源码目录 1. arch:录下x86重点关注 2. init:目录下main.c中的start_kernel是启动内核的起点 3. ipc:进程间通信的目录 实验 使用实验楼的虚拟机打开shell ...
- 《Linux内核分析》期末总结
Linux内核设计期中总结 版权声明:本文为博主原创文章,未经博主允许不得转载. 前八周博客汇总及总结 Linux内核设计第一周——从汇编语言出发理解计算机工作原理 我们学习了汇编语言的基础知识,这一 ...
- 《Linux及安全》期中总结&《Linux内核分析》期终总结
[5216 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK NINE ...
- 《Linux内核分析》期中总结
两个月Linux内核的学习,让我理解了Linux内核的基本工作原理,包括进程管理.内存管理.设备驱动.文件系统,从分析内核到了解整个系统是如何工作的.如何控制管理资源分配.进程切换并执行.各种策略和结 ...
- Linux内核分析之可执行程序的装载和启动
一.内容分析 1.可执行文件的创建 (1)预处理阶段 预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行相应的转换,预处理过程还会删除程序中的注释和多余的空白字符.其中预处理指令主 ...
- 《Linux内核分析》第三周 构建一个简单的Linux系统MenuOS
[刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK THREE ...
- 《Linux内核分析》第五周 扒开系统调用的三层皮(下)
[刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK FIVE( ...
随机推荐
- goweb-访问数据库
访问数据库 对许多Web应用程序而言,数据库都是其核心所在.数据库几乎可以用来存储你想查询和修改的任何信息,比如用户信息.产品目录或者新闻列表等. Go没有内置的驱动支持任何的数据库,但是Go定义了d ...
- 一种循环buffer结构
最新数据循环在buffer[H] -> buffer[L] 放置,记录最新放置Index,对外接口获取数据时,进行两次数据拷贝,Index-H ,index-L 拷贝到数组里
- Python——Pandas 时间序列数据处理
介绍 Pandas 是非常著名的开源数据处理库,我们可以通过它完成对数据集进行快速读取.转换.过滤.分析等一系列操作.同样,Pandas 已经被证明为是非常强大的用于处理时间序列数据的工具.本节将介绍 ...
- sbt 设置
修改 sbtopts for shell # zkk -sbt-dir D:/DATA/.sbt -sbt-boot D:/DATA/.sbt/boot -ivy D:/DATA/.ivy2 修改 s ...
- 获取cell上按钮事件
原由:点击cell上的按钮,无法获取button对应的cell位置 //获取按钮上层控件,也就是cell本身 AccountCell *cell= (AccountCell *)[按钮名称 super ...
- 《VSTO开发中级教程》刘永富 著 清华大学出版社 在线购买
现在可以和作者 刘永富 通过“二手书直卖”这个APP直接买书. 二手书直卖 的下载方法: 方法一:加QQ群61840693,群共享中搜索“二手书直卖”,下载后打开即可. 方法二:从本帖下载:二手书直卖 ...
- Hibernate一级缓存Session和对象的状态
建议看原文:https://blog.csdn.net/qq_42402854/article/details/81461496 一.session简介 首先,SessionFactor ...
- 进程异常行为-反弹Shell攻击,KILL多个进程
进程异常行为-反弹Shell攻击 父进程名称:bash 进程名称:bash 进程名称:/usr/bin/bash 进程id:23,077 命令行参数:sh -c /bin/bash -i >&a ...
- android形状属性、锁屏密码、动态模糊、kotlin项目、抖音动画、记账app、视频播放器等源码
Android精选源码 直观了解Android的"形状"属性如何影响Drawable的外观. 一个灵活的视频播放器, 可替换播放器内核. android锁屏输入密码功能源码 背景动 ...
- 吴裕雄--天生自然 JAVASCRIPT开发学习:对象 实例(3)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...