Chinaunix首页 | 论坛 | 博客
  • 博客访问: 61037
  • 博文数量: 35
  • 博客积分: 2000
  • 博客等级: 大尉
  • 技术积分: 390
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-23 13:36
文章分类

全部博文(35)

文章存档

2011年(1)

2010年(1)

2009年(33)

我的朋友
最近访客

分类: LINUX

2009-04-26 22:02:00

Liunx 启动的过程:

1上电

2硬件将bootloader的第一段载入内存,跳到入口

3bootloader的第一段将第二段载入内存,跳到第二段的入口

3bootloader第二段运行,进行一定的初始化,为加载内核做好准备

4加载内核自引导块到内存,加载内核的其他部分到内存,跳到内核的自引导块入口

5自引导块运行,一般是steup()函数

6setup函数运行完后,跳到startup_32入口      linux/arch/arm/boot/compressed/head.S

7starup_32()解压内核,并跳到内核入口

/*

 *  linux/arch/arm/boot/compressed/head.S

#include

#include

 

/*

 * Debugging stuff

 *

 * Note that these macros must not contain any code which is not

 * 100% relocatable.  Any attempt to do so will result in a crash.

 * Please select one of the following when turning on debugging.

 */

#ifdef DEBUG

 

 

#include

 

              .macro    writeb,    ch, rb

              senduart \ch, \rb

              .endm

 

#if defined

…………..

#elif defined(CONFIG_ARCH_S3C2410)

              .macro loadsp, rb

              mov \rb, #0x50000000

              add  \rb, \rb, #0x4000 * CONFIG_S3C2410_LOWLEVEL_UART_PORT

              .endm

#else

              .macro    loadsp,    rb

              addruart \rb

              .endm

#endif

#endif

#endif

 

              .macro    kputc,val

              mov r0, \val

              bl     putc

              .endm

 

              .macro    kphex,val,len

              mov r0, \val

              mov r1, #\len

              bl     phex

              .endm

 

              .macro    debug_reloc_start

#ifdef DEBUG

              kputc      #'\n'

              kphex      r6, 8              /* processor id */

              kputc      #':'

              kphex      r7, 8              /* architecture id */

              kputc      #':'

              mrc p15, 0, r0, c1, c0

              kphex      r0, 8              /* control reg */

              kputc      #'\n'

              kphex      r5, 8              /* decompressed kernel start */

              kputc      #'-'

              kphex      r8, 8              /* decompressed kernel end  */

              kputc      #'>'

              kphex      r4, 8              /* kernel execution address */

              kputc      #'\n'

#endif

              .endm

 

              .macro    debug_reloc_end

#ifdef DEBUG

              kphex      r5, 8              /* end of kernel */

              kputc      #'\n'

              mov r0, r4

              bl     memdump             /* dump 256 bytes at start of kernel */

#endif

              .endm

 

              .section ".start", #alloc, #execinstr

/*

 * sort out different calling conventions

 */

              .align

start:

              .type       start,#function

              .rept 8

              mov r0, r0

              .endr

 

              b     1f

              .word      0x016f2818           @ Magic numbers to help the loader

              .word      start               @ absolute load/run zImage address

              .word      _edata                   @ zImage end address

1:            mov r7, r1                    @ save architecture ID

              mov r8, #0                    @ save r0

…………………………………….

              bl     decompress_kernel

 

              add  r0, r0, #127

              bic   r0, r0, #127           @ align the kernel length

/*

 * r0     = decompressed kernel length

 * r1-r3  = unused

 * r4     = kernel execution address

 * r5     = decompressed kernel start

 * r6     = processor ID

 * r7     = architecture ID

 * r8-r14 = unused

 */

              add  r1, r5, r0        @ end of decompressed kernel

              adr   r2, reloc_start

              ldr   r3, LC1

              add  r3, r2, r3

1:            ldmia       r2!, {r8 - r13}              @ copy relocation code

              stmia       r1!, {r8 - r13}

              ldmia       r2!, {r8 - r13}

              stmia       r1!, {r8 - r13}

              cmp r2, r3

              blo   1b

 

              bl     cache_clean_flush

              add  pc, r5, r0        @ call relocation code

 

/*

 * We're not in danger of overwriting ourselves.  Do this the simple way.

 *

 * r4     = kernel execution address

 * r7     = architecture ID

 */

wont_overwrite:     mov r0, r4

              mov r3, r7

              bl     decompress_kernel

              b     call_kernel

 

* All code following this line is relocatable.  It is relocated by

 * the above code to the end of the decompressed kernel image and

 * executed there.  During this time, we have no stacks.

 *

 * r0     = decompressed kernel length

 * r1-r3  = unused

 * r4     = kernel execution address

 * r5     = decompressed kernel start

 * r6     = processor ID

 * r7     = architecture ID

 * r8-r14 = unused

 */

              .align       5

reloc_start:     add  r8, r5, r0

              debug_reloc_start

              mov r1, r4

1:

              .rept 4

              ldmia       r5!, {r0, r2, r3, r9 - r13}      @ relocate kernel

              stmia       r1!, {r0, r2, r3, r9 - r13}

              .endr

 

              cmp r5, r8

              blo   1b

              debug_reloc_end

 

call_kernel:     bl     cache_clean_flush

              bl     cache_off

              mov r0, #0

              mov r1, r7                    @ restore architecture number

              mov pc, r4                    @ call kernel

……………………………………….

/*

 * Here follow the relocatable cache support functions for the

 * various processors.  This is a generic hook for locating an

 * entry and jumping to an instruction at the specified offset

 * from the start of the block.  Please note this is all position

 * independent code.

 *

 ………………………………

 

reloc_end:

 

              .align

              .section ".stack", "w"

user_stack:     .space     4096

8从内核入口开始执行,被执行的函数名startup_32()

startup_32()为创建第一个内核线程做准备,然后跳到函数start_kernel()的入口

9start_kernel()开始运行源代码如下,这个过程比较复杂,主要是内核的初始化工作

linux/init/main.c

asmlinkage void __init start_kernel(void)

{

       char * command_line;            内核命令行

       extern struct kernel_param __start___param[], __stop___param[];

/*

 * Interrupts are still disabled. Do necessary setups, then

 * enable them

 */关闭中断

       lock_kernel();

       page_address_init();

       printk(KERN_NOTICE);

       printk(linux_banner);

       setup_arch(&command_line);          /解释bootloader传递过来的参数

       setup_per_cpu_areas();

 

       /*

        * Mark the boot cpu "online" so that it can call console drivers in

        * printk() and can access its per-cpu storage.

        */

       smp_prepare_boot_cpu();

 

       /*

        * 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();   关闭preempting ,bootup阶段的进程轮询是很脆弱的,直到cpu_idle进程建立

       build_all_zonelists();

       page_alloc_init();

       printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line);

       parse_early_param();

       parse_args("Booting kernel", command_line, __start___param,

                 __stop___param - __start___param,

                 &unknown_bootoption);

       sort_main_extable();

       trap_init();

       rcu_init();

       init_IRQ();

       pidhash_init();

       init_timers();

       softirq_init();

       time_init();

 

       /*

        * 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);

       profile_init();

       local_irq_enable();

#ifdef CONFIG_BLK_DEV_INITRD

       if (initrd_start && !initrd_below_start_ok &&

                     initrd_start < min_low_pfn << PAGE_SHIFT) {

              printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "

                  "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);

              initrd_start = 0;

       }

#endif

       vfs_caches_init_early();                     vfs_caches_init_early(void)

{

       dcache_init_early();

       inode_init_early();                   * Initialize the waitqueues and inode hash table.

}

       mem_init();

       kmem_cache_init();

       setup_per_cpu_pageset();

       numa_policy_init();

       if (late_time_init)

              late_time_init();

       calibrate_delay();

       pidmap_init();

       pgtable_cache_init();

       prio_tree_init();

       anon_vma_init();

#ifdef CONFIG_X86

       if (efi_enabled)

              efi_enter_virtual_mode();

#endif

       fork_init(num_physpages);

       proc_caches_init();

       buffer_init();

       unnamed_dev_init();

       key_init();

       security_init();

       vfs_caches_init(num_physpages);      vfs_caches 初始化

       radix_tree_init();

       signals_init();

       /* rootfs populating might need page-writeback */

       page_writeback_init();

#ifdef CONFIG_PROC_FS

       proc_root_init();

proc_root_init(void)

{

       int err = proc_init_inodecache();

       if (err)

              return;

       err = register_filesystem(&proc_fs_type);   /注册文件系统

       if (err)

              return;

       proc_mnt = kern_mount(&proc_fs_type);    /挂载文件系统

       err = PTR_ERR(proc_mnt);

       if (IS_ERR(proc_mnt)) {

              unregister_filesystem(&proc_fs_type);

              return;。。。。。。。。。。。。。。。。。。。

 

#endif

       cpuset_init();

 

       check_bugs();

 

       acpi_early_init(); /* before LAPIC and SMP init */

 

       /* Do the rest non-__init'ed, we're now alive */

       rest_init();

}

其中最后一步要执行的是Rest_init()的源代码如下,主要是创建线程1 init,

static void noinline rest_init(void)

       __releases(kernel_lock)

{

       kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);

       numa_default_policy();

       unlock_kernel();   开启时间中断

 

       /*

        * The boot idle thread must execute schedule()

        * at least one to get things moving:

        */

       preempt_enable_no_resched();

       schedule();         进程调度函数开始运行

       preempt_disable();  

 

       /* Call into cpu_idle with preempt disabled */

       cpu_idle();   cpu_idle运行

}

 

Init的源代码:init内核线程主要是挂载根文件系统,设备驱动初始化,启动用户级进程init在目录sbin/init             /etc/init                 /bin/init之一

 

static int init(void * unused)

{

       lock_kernel();          关闭时间中断

       /*

        * init can run on any cpu.

        */

       set_cpus_allowed(current, CPU_MASK_ALL)

       /*

        * 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.

        */

       child_reaper = current;

 

       /* Sets up cpus_possible() */

       smp_prepare_cpus(max_cpus);

 

       do_pre_smp_initcalls();

 

       fixup_cpu_present_map();

       smp_init();

       sched_init_smp();

 

       cpuset_init_smp();

 

       /*

        * Do this before initcalls, because some drivers want to access

        * firmware files.                       有一部分驱动需要从文件系统加载,在初始化驱动以前应该先把文件系统建立起来,虽然只是一个临时的内存文件系统,有了这部分,就能够加载大部分的驱动,进行初始化了

        */

       populate_rootfs();           这个函数用来挂载基于内存的文件系统 initramfs

 

void __init populate_rootfs(void)

{

       char *err = unpack_to_rootfs(__initramfs_start,

                      __initramfs_end - __initramfs_start, 0);   __initramfs_start  __initramfs_end 是全局变量描述了应该将文件系统解压到哪里

       if (err)

              panic(err);

#ifdef CONFIG_BLK_DEV_INITRD    如果配置的时候选定了使用initrd

       if (initrd_start) {    给出了initrd_start

              int fd;

              err = unpack_to_rootfs((char *)initrd_start,     解压 initrd  使用的工具是gzip

                     initrd_end - initrd_start, 1);

              if (!err) {

                     printk(" it is\n");

                     unpack_to_rootfs((char *)initrd_start,

                            initrd_end - initrd_start, 0);

                     free_initrd();   如果错误就释放掉这个内存空间,initrd_start initrd_end

                     return;

              }

              printk("it isn't (%s); looks like an initrd\n", err);

              fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 700);  打开initrd.image

              if (fd >= 0) {                                         打开正确

                     sys_write(fd, (char *)initrd_start,

initrd_end - initrd_start);         initrd_end-initrd_start 这么大的内存内容,从initrd_start指定的地址写到文件fd     

                     sys_close(fd);                        关闭文件

                     free_initrd();                         释放内存

              }

       }

       do_basic_setup();

tatic void __init do_basic_setup(void)

{

文本框: /* These are the core pieces */
	devices_init();
	buses_init();
	classes_init();
	firmware_init();

	/* These are also core pieces, but must come after the
	 * core core pieces.
	 */
	platform_bus_init();
	system_bus_init();
	cpu_dev_init();
	memory_dev_init();
	attribute_container_init();       /* drivers will send hotplug events */

       init_workqueues();

       usermodehelper_init();

       driver_init();                  初始化设备驱动

 

#ifdef CONFIG_SYSCTL

       sysctl_init();

#endif

 

       /* Networking initialization needs a process context */

       sock_init();

 

       do_initcalls();

}

       /*

        * check if there is an early userspace init.  If yes, let it do all

        * the work    看看是否一个用户inti存在,如果存在就让它把所有工作了

        */

 

       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();         挂载rootfs ,其代码如下

mount_devfs();

 

          if (root_delay) {

              printk(KERN_INFO "Waiting %dsec before mounting root device...\n",

                     root_delay);

              ssleep(root_delay);

       }

 

       md_run_setup();

 

       if (saved_root_name[0]) {                  bootloader传过来的参数

              root_device_name = saved_root_name;

              ROOT_DEV = name_to_dev_t(root_device_name);

              if (strncmp(root_device_name, "/dev/", 5) == 0)

                     root_device_name += 5;

       }

 

       is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;

 

       if (initrd_load())

              goto out;

 

       if (is_floppy && rd_doload && rd_load_disk(0))

              ROOT_DEV = Root_RAM0;

 

       mount_root();

out:

       umount_devfs("/dev");

       sys_mount(".", "/", NULL, MS_MOVE, NULL);

       sys_chroot(".");

       security_sb_post_mountroot();

       mount_devfs_fs ();

}

       }

 

       /*

        * 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..         完成了initial bootup

        */

       free_initmem();

       unlock_kernel();          开时间中断

       system_state = SYSTEM_RUNNING;           系统状态运行

       numa_default_policy();

 

       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);

 

       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");     开始调用用户初始化 init 存放目录在 sbin  etc  bin

       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.");

}

10init进程的进程号是1,这个进程主要的作用就是进行系统应用程序的初始化,这个进程是所有用户进程的父进程,这个进程就一直运行到关机。

它会根据inittab中的内容依次执行脚本,inittab的内容如下

#

# inittab       This file describes how the INIT process should set up

#               the system in a certain run-level.

#

# Author:       Miquel van Smoorenburg,

#               Modified for RHS Linux by Marc Ewing and Donnie Barnes

#

 

# Default runlevel. The runlevels used by RHS 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:

 

# System initialization.

si::sysinit:/etc/rc.d/rc.sysinit

 

l0:0:wait:/etc/rc.d/rc 0

l1:1:wait:/etc/rc.d/rc 1

l2:2:wait:/etc/rc.d/rc 2

l3:3:wait:/etc/rc.d/rc 3

l4:4:wait:/etc/rc.d/rc 4

l5:5:wait:/etc/rc.d/rc 5

l6:6:wait:/etc/rc.d/rc 6

 

# Trap CTRL-ALT-DELETE

ca::ctrlaltdel:/sbin/shutdown -t3 -r now

 

# When our UPS tells us power has failed, assume we have a few minutes

# of power left.  Schedule a shutdown for 2 minutes from now.

# This does, of course, assume you have powerd installed and your

# UPS connected and working correctly. 

pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"

 

# If power was restored before the shutdown kicked in, cancel it.

pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"

 

 

# Run gettys in standard runlevels

1:2345:respawn:/sbin/mingetty tty1

2:2345:respawn:/sbin/mingetty tty2

3:2345:respawn:/sbin/mingetty tty3

4:2345:respawn:/sbin/mingetty tty4

5:2345:respawn:/sbin/mingetty tty5

6:2345:respawn:/sbin/mingetty tty6

 

# Run xdm in runlevel 5

x:5:respawn:/etc/X11/prefdm -nodaemon

 

init进程将从上到下的读取/etc/inittab文件,只要状态符合当前运行级就会去执行脚本。

inittab由几行组成,每行被三个冒号分隔成四个部分,每个部分具有不同的含义。格式如下:

行标识符:状态:动作:命令

行标识符是你的运行级脚本的名字,不能使用重复的行标识符。

状态是表示运行级脚本何时应该执行的数字。状态由0,1,2,3,4,5,6S一个或多个数字字母组成。如果状态为空,就是系统启动必须执行的脚本。

下面是slackware的状态定义:

0 = halt

1 = single user mode

2 = unused (but configured the same as runlevel 3)

3 = multiuser mode (default Slackware runlevel)

4 = X11 with KDM/GDM/XDM (session managers)

5 = unused (but configured the same as runlevel 3)

6 = reboot

S同状态1相同。

动作有once, wait, respawn, sysinit, crtlaltdel, initdefault组成,说明了init执行脚本的方式。

onceinit在进入后只执行一次。init不等待命令的结束。

wait:和once不同的是,init等待命令的结束。

respawn:命令结束后会被重起。

sysinitinit最先执行的运行级脚本,状态被忽略。说穿了就是无论何是都优先执行的脚本,应指向系统初始化脚本。

ctrlaltdel:当“三指禅”被按下时,该运行级被启动,一般是指向重启脚本。

initdefault:指定系统启动时的缺省运行级。在sysinit后执行。

对于slackwareinittab

id3initdefault

id指出缺省为多用户字符界面(3),不要把它设置成06!注意没有命令。

siSsysinit/etc/rc.d/rc.S

si指出系统初始化运行级,其中S等同于状态1,它指向/etc/rc.d/rc.S,也就是说init第一个去执行的shell脚本。

rc2345wait/etc/rc.d/rc.M

rc指出多用户启动运行级,当状态为2,3,4,5时被执行,init等待命令的结束,这也是为什么启动时没有shell可用的原因。

c11235respawn/sbin/agetty 38400 tty1 linux

c1指出控制台1,当它被杀死时init将重启它。它打开一个终端tty1供你使用。

x14wait/etc/rc.d/rc.4

x1指出多用户GUI运行级,指向脚本rc.4

rc.S(系统初始化运行级脚本)做的事:

#安装proc文件系统。

#决定是否有需要使用Hotplug自动检测硬件。

#启动devfsd

#安装devfs

#2.6内核启动udev

#打开交换分区,其中要读取/etc/fstab中获取分区信息。

#检查根分区是否为只读,因为只有只读时才能检查硬盘。

#如有需要检查根分区。

#安装sysfs/proc/sys

#设置硬件时钟。

#配置isa设备。

#执行/etc/rc.d/rc.modules (这个文件将剩下的内核模块装入内核,稍后再讲)。

#初始化lvm卷,不要问我为什么。

#检查非根分区。

#安装本地硬盘分区。

#删除临时文件。

#initrd被安装在/initrd中,它用来在内核启动第一时间载入一些内核模块和必需程序(如fsck)等。现在卸载它。

#创建utmp

#如果你是用的zipslack(一个工作在vfat上的linux套件),配置umsdos

#Linux 2.4.27写入你的mtod文件

#执行rc.sysvinit。(不像rhslackware是一个“叛徒”。它的init脚本结构不像大多数linux套件(基于SVR4),而像BSD,所以只是一个假文件。)

#执行rc.serical。(串口)

#安装随机数种子

rc.modules

#决定内核版本,到目录”/lib/modules/你的内核版本号/“去寻找模块

#更新内核模块依赖关系。

#装入APM高级管理,它被注释掉了,建议你启用它以正常关机。

#一大堆被注释掉了的硬件模块,如果hotplug找不到你的硬件就到这里来。

rc.S执行完成后,slackware将执行缺省的运行级(3),也就是先执行rc.M(多用户进程级)。

#设置黑屏时间。

#设置主机名,主机名存储在/etc/HOSTNAME里,缺省为darkstar.example.net

#设置dmesg缓冲区的大小。越多越好。

#执行rc.syslog,打开syslogklogd

#执行rc.pcmcia,初始化PCMCIA卡,我不懂。

#执行rc.inet1,设置网络。重点。

#执行rc.hotplug,即插即用。

#执行rc.inet2,网络守护进程。重点。

#把所有的锁文件删掉。

#把黑洞设备和临时目录设成777

#运行ldconfig,更新共享库,我喜欢关掉。

#更新X字体缓存,关掉吧。不过安了新字体后自己要手动运行一次”fc-cache"而已。

#执行rc.CUPSUNIX打印守护进程。

#打开appletalk。关了吧。

#打开用户限额。请看/usr/doc/Linux-HowTOs/Quota

#执行rc.acpid。高级能源管理。

#执行rc.alsaalsa声音系统。

#执行rc.font。用户自己的字体。

#执行rc.keymap。用户自己的keymap

#把你的一大堆网络standalone进程打开。

#执行rc.gpm。字符界面上用鼠标。

#又执行rc.sysinit一次。这不是Bug,这是sysinit的特点:sysinit脚本应被放在/etc/rc.d/rcX.d中。

#执行rc.local。最后,执行用户你的自己的配置文件。(用户如果想开机就自动运行程序的话可以在里面添加)

rc.inet1

#读入另一个脚本文件rc.inet1.conf的变量,里面有网络的基本配置。

#打开lo环回接口。

#打开eth0 eth1 eth3 eth4, 请看eth_up函数,很长。

#如有需要使用无线网卡。

#如有需要使用DHCP

rc.inet2

#启动rc.portmap,准备安装NFS文件系统

#安装所有smb文件系统

#执行rc.firewall,防火墙脚本。

#执行rc.ip_forwardIP转发脚本,如果你要共享上网,改它。

#一大堆网络服务程序(NFSBINDSSHINETD

rc.M执行完了,init按照inittab的配置打开终端,它创建若干个agetty进程,这些进程通过系统调用执行login程序,用户密码验证成功后,再执行shell。一天的工作开始了。在这之后,init除了监视运行级的改变外,还干一些副业:收养孤儿进程。

如果你是用的运行级4(多用户GUI运行级)init就会去执行rc.4,并打开gdmkdmGnomeKde的登录界面)。

11用户登录

Login会根据用户输入的用户帐号与

/etc/passwd /etc/shadow  存放的是用户的帐号和密码进行比对如果正确就启动

并为用户配置好应用环境

很重要的就是/etc/profile  /etc/bashrc  面向所有用户的配置

/root 下的.profile .bashrc            面向root用户的配置

/home/$user/ 下的.profile .bashrc 这些文件关系到用户使用的很多环境变量 面向一般用户的配置

.profile 如果被改变要起作用需要重新登陆,bashrc如果被改变,只要打开终端就会生效

 

 

 

阅读(1157) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~