zoukankan      html  css  js  c++  java
  • linux Init分析(原创)

    1.uboot的目标就是启动内核kernel;

    2.kernel的目的就是启动应用程序,而第一个应用程序即是Init,构建根文件系统。

    从uboot初始化配置后,引导内核的启动,启动函数为:start_kernel(void)

    其他可以先不管,我们需要的是看看rest_init()函数;

    代码如下:

      1 asmlinkage void __init start_kernel(void)
      2 {
      3     char * command_line;
      4     extern struct kernel_param __start___param[], __stop___param[];
      5 
      6     smp_setup_processor_id();
      7 
      8     /*
      9      * Need to run as early as possible, to initialize the
     10      * lockdep hash:
     11      */
     12     lockdep_init();
     13     debug_objects_early_init();
     14 
     15     /*
     16      * Set up the the initial canary ASAP:
     17      */
     18     boot_init_stack_canary();
     19 
     20     cgroup_init_early();
     21 
     22     local_irq_disable();
     23     early_boot_irqs_off();
     24     early_init_irq_lock_class();
     25 
     26 /*
     27  * Interrupts are still disabled. Do necessary setups, then
     28  * enable them
     29  */
     30     lock_kernel();
     31     tick_init();
     32     boot_cpu_init();
     33     page_address_init();
     34     printk(KERN_NOTICE "%s", linux_banner);
     35     setup_arch(&command_line);
     36     mm_init_owner(&init_mm, &init_task);
     37     setup_command_line(command_line);
     38     setup_nr_cpu_ids();
     39     setup_per_cpu_areas();
     40     smp_prepare_boot_cpu();    /* arch-specific boot-cpu hooks */
     41 
     42     build_all_zonelists(NULL);
     43     page_alloc_init();
     44 
     45     printk(KERN_NOTICE "Kernel command line: %s
    ", boot_command_line);
     46     parse_early_param();
     47     parse_args("Booting kernel", static_command_line, __start___param,
     48            __stop___param - __start___param,
     49            &unknown_bootoption);
     50     /*
     51      * These use large bootmem allocations and must precede
     52      * kmem_cache_init()
     53      */
     54     pidhash_init();
     55     vfs_caches_init_early();
     56     sort_main_extable();
     57     trap_init();
     58     mm_init();
     59     /*
     60      * Set up the scheduler prior starting any interrupts (such as the
     61      * timer interrupt). Full topology setup happens at smp_init()
     62      * time - but meanwhile we still have a functioning scheduler.
     63      */
     64     sched_init();
     65     /*
     66      * Disable preemption - early bootup scheduling is extremely
     67      * fragile until we cpu_idle() for the first time.
     68      */
     69     preempt_disable();
     70     if (!irqs_disabled()) {
     71         printk(KERN_WARNING "start_kernel(): bug: interrupts were "
     72                 "enabled *very* early, fixing it
    ");
     73         local_irq_disable();
     74     }
     75     rcu_init();
     76     radix_tree_init();
     77     /* init some links before init_ISA_irqs() */
     78     early_irq_init();
     79     init_IRQ();
     80     prio_tree_init();
     81     init_timers();
     82     hrtimers_init();
     83     softirq_init();
     84     timekeeping_init();
     85     time_init();
     86     profile_init();
     87     if (!irqs_disabled())
     88         printk(KERN_CRIT "start_kernel(): bug: interrupts were "
     89                  "enabled early
    ");
     90     early_boot_irqs_on();
     91     local_irq_enable();
     92 
     93     /* Interrupts are enabled now so all GFP allocations are safe. */
     94     gfp_allowed_mask = __GFP_BITS_MASK;
     95 
     96     kmem_cache_init_late();
     97 
     98     /*
     99      * HACK ALERT! This is early. We're enabling the console before
    100      * we've done PCI setups etc, and console_init() must be aware of
    101      * this. But we do want output early, in case something goes wrong.
    102      */
    103     console_init();
    104     if (panic_later)
    105         panic(panic_later, panic_param);
    106 
    107     lockdep_info();
    108 
    109     /*
    110      * Need to run this when irqs are enabled, because it wants
    111      * to self-test [hard/soft]-irqs on/off lock inversion bugs
    112      * too:
    113      */
    114     locking_selftest();
    115 
    116 #ifdef CONFIG_BLK_DEV_INITRD
    117     if (initrd_start && !initrd_below_start_ok &&
    118         page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
    119         printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
    120             "disabling it.
    ",
    121             page_to_pfn(virt_to_page((void *)initrd_start)),
    122             min_low_pfn);
    123         initrd_start = 0;
    124     }
    125 #endif
    126     page_cgroup_init();
    127     enable_debug_pagealloc();
    128     kmemtrace_init();
    129     kmemleak_init();
    130     debug_objects_mem_init();
    131     idr_init_cache();
    132     setup_per_cpu_pageset();
    133     numa_policy_init();
    134     if (late_time_init)
    135         late_time_init();
    136     sched_clock_init();
    137     calibrate_delay();
    138     pidmap_init();
    139     anon_vma_init();
    140 #ifdef CONFIG_X86
    141     if (efi_enabled)
    142         efi_enter_virtual_mode();
    143 #endif
    144     thread_info_cache_init();
    145     cred_init();
    146     fork_init(totalram_pages);
    147     proc_caches_init();
    148     buffer_init();
    149     key_init();
    150     security_init();
    151     dbg_late_init();
    152     vfs_caches_init(totalram_pages);
    153     signals_init();
    154     /* rootfs populating might need page-writeback */
    155     page_writeback_init();
    156 #ifdef CONFIG_PROC_FS
    157     proc_root_init();
    158 #endif
    159     cgroup_init();
    160     cpuset_init();
    161     taskstats_init_early();
    162     delayacct_init();
    163 
    164     check_bugs();
    165 
    166     acpi_early_init(); /* before LAPIC and SMP init */
    167     sfi_init_late();
    168 
    169     ftrace_init();
    170 
    171     /* Do the rest non-__init'ed, we're now alive */
    172    rest_init();
    173 }

    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.
    ");
    
    	(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.
    ");
    
    	(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
    ",
                    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...
    ", 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
    ",
                    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函数:

    看看都做了什么东西:

      1 int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
      2 int init_main(int argc UNUSED_PARAM, char **argv)
      3 {
      4     die_sleep = 30 * 24*60*60; /* if xmalloc would ever die... */
      5 
      6     if (argv[1] && strcmp(argv[1], "-q") == 0) {
      7         return kill(1, SIGHUP);
      8     }
      9 
     10     if (!DEBUG_INIT) {
     11         /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
     12         if (getpid() != 1
     13          && (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc"))
     14         ) {
     15             bb_show_usage();
     16         }
     17         /* Turn off rebooting via CTL-ALT-DEL - we get a
     18          * SIGINT on CAD so we can shut things down gracefully... */
     19         reboot(RB_DISABLE_CAD); /* misnomer */
     20     }
     21 
     22     /* Figure out where the default console should be */
     23     console_init();
     24     set_sane_term();
     25     xchdir("/");
     26     setsid();
     27 
     28     /* Make sure environs is set to something sane */
     29     putenv((char *) "HOME=/");
     30     putenv((char *) bb_PATH_root_path);
     31     putenv((char *) "SHELL=/bin/sh");
     32     putenv((char *) "USER=root"); /* needed? why? */
     33 
     34     if (argv[1])
     35         xsetenv("RUNLEVEL", argv[1]);
     36 
     37 #if !ENABLE_FEATURE_EXTRA_QUIET
     38     /* Hello world */
     39     message(L_CONSOLE | L_LOG, "init started: %s", bb_banner);
     40 #endif
     41 
     42     /* Make sure there is enough memory to do something useful. */
     43     if (ENABLE_SWAPONOFF) {
     44         struct sysinfo info;
     45 
     46         if (sysinfo(&info) == 0
     47          && (info.mem_unit ? info.mem_unit : 1) * (long long)info.totalram < 1024*1024
     48         ) {
     49             message(L_CONSOLE, "Low memory, forcing swapon");
     50             /* swapon -a requires /proc typically */
     51             new_init_action(SYSINIT, "mount -t proc proc /proc", "");
     52             /* Try to turn on swap */
     53             new_init_action(SYSINIT, "swapon -a", "");
     54             run_actions(SYSINIT);   /* wait and removing */
     55         }
     56     }
     57 
     58     /* Check if we are supposed to be in single user mode */
     59     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     }
     74 
     75 #if ENABLE_SELINUX
     76     if (getenv("SELINUX_INIT") == NULL) {
     77         int enforce = 0;
     78 
     79         putenv((char*)"SELINUX_INIT=YES");
     80         if (selinux_init_load_policy(&enforce) == 0) {
     81             BB_EXECVP(argv[0], argv);
     82         } else if (enforce > 0) {
     83             /* SELinux in enforcing mode but load_policy failed */
     84             message(L_CONSOLE, "can't load SELinux Policy. "
     85                 "Machine is in enforcing mode. Halting now.");
     86             exit(EXIT_FAILURE);
     87         }
     88     }
     89 #endif
     90 
     91     /* Make the command line just say "init"  - thats all, nothing else */
     92     strncpy(argv[0], "init", strlen(argv[0]));
     93     /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
     94     while (*++argv)
     95         memset(*argv, 0, strlen(*argv));
     96 
     97     /* Set up signal handlers */
     98     if (!DEBUG_INIT) {
     99         struct sigaction sa;
    100 
    101         bb_signals(0
    102             + (1 << SIGUSR1) /* halt */
    103             + (1 << SIGTERM) /* reboot */
    104             + (1 << SIGUSR2) /* poweroff */
    105             , halt_reboot_pwoff);
    106         signal(SIGQUIT, restart_handler); /* re-exec another init */
    107 
    108         /* Stop handler must allow only SIGCONT inside itself */
    109         memset(&sa, 0, sizeof(sa));
    110         sigfillset(&sa.sa_mask);
    111         sigdelset(&sa.sa_mask, SIGCONT);
    112         sa.sa_handler = stop_handler;
    113         /* NB: sa_flags doesn't have SA_RESTART.
    114          * It must be able to interrupt wait().
    115          */
    116         sigaction_set(SIGTSTP, &sa); /* pause */
    117         /* Does not work as intended, at least in 2.6.20.
    118          * SIGSTOP is simply ignored by init:
    119          */
    120         sigaction_set(SIGSTOP, &sa); /* pause */
    121 
    122         /* SIGINT (Ctrl-Alt-Del) must interrupt wait(),
    123          * setting handler without SA_RESTART flag.
    124          */
    125         bb_signals_recursive_norestart((1 << SIGINT), record_signo);
    126     }
    127 
    128     /* Set up "reread /etc/inittab" handler.
    129      * Handler is set up without SA_RESTART, it will interrupt syscalls.
    130      */
    131     if (!DEBUG_INIT && ENABLE_FEATURE_USE_INITTAB)
    132         bb_signals_recursive_norestart((1 << SIGHUP), record_signo);
    133 
    134     /* Now run everything that needs to be run */
    135     /* First run the sysinit command */
    136     run_actions(SYSINIT);
    137     check_delayed_sigs();
    138     /* Next run anything that wants to block */
    139     run_actions(WAIT);
    140     check_delayed_sigs();
    141     /* Next run anything to be run only once */
    142     run_actions(ONCE);
    143 
    144     /* Now run the looping stuff for the rest of forever.
    145      */
    146     while (1) {
    147         int maybe_WNOHANG;
    148 
    149         maybe_WNOHANG = check_delayed_sigs();
    150 
    151         /* (Re)run the respawn/askfirst stuff */
    152         run_actions(RESPAWN | ASKFIRST);
    153         maybe_WNOHANG |= check_delayed_sigs();
    154 
    155         /* Don't consume all CPU time - sleep a bit */
    156         sleep(1);
    157         maybe_WNOHANG |= check_delayed_sigs();
    158 
    159         /* Wait for any child process(es) to exit.
    160          *
    161          * If check_delayed_sigs above reported that a signal
    162          * was caught, wait will be nonblocking. This ensures
    163          * that if SIGHUP has reloaded inittab, respawn and askfirst
    164          * actions will not be delayed until next child death.
    165          */
    166         if (maybe_WNOHANG)
    167             maybe_WNOHANG = WNOHANG;
    168         while (1) {
    169             pid_t wpid;
    170             struct init_action *a;
    171 
    172             /* If signals happen _in_ the wait, they interrupt it,
    173              * bb_signals_recursive_norestart set them up that way
    174              */
    175             wpid = waitpid(-1, NULL, maybe_WNOHANG);
    176             if (wpid <= 0)
    177                 break;
    178 
    179             a = mark_terminated(wpid);
    180             if (a) {
    181                 message(L_LOG, "process '%s' (pid %d) exited. "
    182                         "Scheduling for restart.",
    183                         a->command, wpid);
    184             }
    185             /* See if anyone else is waiting to be reaped */
    186             maybe_WNOHANG = WNOHANG;
    187         }
    188     } /* while (1) */
    189 }

    首先看一下

    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[4];
        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, 4, 0, "#:",
                    PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
            /* order must correspond to SYSINIT..RESTART constants */
            static const char actions[] ALIGN1 =
                "sysinit""wait""once""respawn""askfirst"
                "ctrlaltdel""shutdown""restart";
            int action;
            char *tty = token[0];
    
            if (!token[3]) /* less than 4 tokens */
                goto bad_entry;
            action = index_in_strings(actions, token[2]);
            if (action < 0 || !token[3][0]) /* token[3]: command */
                goto bad_entry;
            /* turn .*TTY -> /dev/TTY */
            if (tty[0]) {
                if (strncmp(tty, "/dev/", 5) == 0)
                    tty += 5;
                tty = concat_path_file("/dev/", tty);
            }
            new_init_action(1 << action, token[3], tty);
            if (tty[0])
                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(8) configuration for BusyBox
    #
    # Copyright (C) 1999-2004 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-4
    # tty2::askfirst:-/bin/sh
    # tty3::askfirst:-/bin/sh
    # tty4::askfirst:-/bin/sh
    
    # /sbin/getty invocations for selected ttys
    # tty4::respawn:/sbin/getty 38400 tty5
    # tty5::respawn:/sbin/getty 38400 tty6
    
    # Example of how to put a getty on a serial line (for a terminal)
    ::respawn:/sbin/getty -L ttyS000 115200 vt100 -n root -I "Auto login as root ..."
    #::respawn:/sbin/getty -L ttyS1 9600 vt100
    #
    # Example how to put a getty on a modem line.
    #::respawn:/sbin/getty 57600 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[0-9][0-9]*
    do
            if [ -x $initscript ] ;
            then
                    echo "[RCS]: $initscript"
                    $initscript
            fi
    done

    我们发现一个很重要的一项:

    /bin/mount -a 它的意思是将会执行/etc/fstab脚本。我们在海思平台上看一下:
    # cat /etc/fstab 
    proc            /proc           proc    defaults        0       0
    sysfs           /sys            sysfs   defaults        0       0
    tmpfs           /dev            tmpfs   defaults        0       0
    
    

    这里涉及一个udev机制,详细请查看文章mdev解析,这里意思是将linux虚拟的文件系统proc sysfs tmpfs 挂载到对应的目录这样,我们就不必要手动去创建了。

    for initscript in /etc/init.d/S[0-9][0-9]*
    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=11 clockbit=3 gpioiddata=12 databit=5 i2cmode=2
    insmod hi_i2c.ko
    #insmod hi_usbprotected.ko Usb0PwrEn=63 Usb0Ovrcur=65 Usb0IntType=1
    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 3 > /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 1 > /proc/sys/vm/overcommit_memory
    echo 8192 > /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 $1 ] && 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 022
    
    if [ -e /tmp/run_flag ]; then
            echo "app is running already! "
            exit 0
    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 "1" >/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 -9 udhcpc
    usleep 300000
    ./appmain 100
    done

    /etc/profile 文件是登陆linux时候就运行的,app此时启动了。

     
     
    
    

    # cat /etc/fstab proc            /proc           proc    defaults        0       0sysfs           /sys            sysfs   defaults        0       0tmpfs           /dev            tmpfs   defaults        0       0

  • 相关阅读:
    二阶段项目所遇问题 加载分页信息并且加入删除摁钮 限制权限可见
    用kryonet时kryo报buffer underflow错误
    《深入理解Java虚拟机》读书笔记七
    《深入理解Java虚拟机》读书笔记六
    《深入理解Java虚拟机》读书笔记五
    《深入理解Java虚拟机》读书笔记四
    《深入理解Java虚拟机》读书笔记三
    《深入理解Java虚拟机》读书笔记二
    《深入理解Java虚拟机》读书笔记一
    《实战Java高并发程序设计》读书笔记六
  • 原文地址:https://www.cnblogs.com/kernel-style/p/3397705.html
Copyright © 2011-2022 走看看