为您找到与linux内核原理及分析相关的共200个结果:
“内核”指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。一个内核不是一套完整的操作系统。一套基于Linux内核的完整操作系统叫作Linux操作系统,或是GNU/Linux。读文网小编为大家带来了linux操作系统内核分析详解,希望大家喜欢。
一、操作系统概述
在Richard Stevens的unix环境高级编程中这样定义“它控制计算机硬件资源,提供程序运行环境。一般而言我们称这种软件为内核(kernel),它相对较小,位于环境的中心”。总结下就是控制硬件,提供环境。程序员主要关心的是所谓的环境,主要说下提供什么环境。
操作系统都会想它们运行的程序提供各种服务,执行新的程序,打开文件,读文件,分配存储空间,获得当前时间等(一般通过系统调用)。
广义上,操作系统还有内核外的系统调用,基于系统调用的shell(也是一种特殊的应用程序,为其他应用程序提供接口)和库函数(对系统调用的封装),和基于shell,系统调用,库函数(这三个东西基本组成了我们常用的环境)的应用软件。有图如下:
在使用linux的man帮助的时候可以指定是查询系统命令还是系统调用使用man时可以指定不同的section来浏览,各个section 如下:
1 - commands
2 - system calls
3 - library calls
其实还有其他的section 不常见就没有列出来,可以man 1 chmod 也可以 man 2 chmod 得到的帮助内容是不同的。
为了增加unix可移植性,IEEE定义了POSIX的标准,后来这个标准不只限于unix操作系统。POSIX标准只是定义了一套接口,并没有规定接口的实现(类似于概要设计),(各个操作系统对接口的实现可能有所不同),也没有详细的区分系统调用和库函数,所有的例程都叫做函数。需要说明的是,并不是每个操作系统都严格遵守POSIX标准,POSIX标准现在是一个很大的协议族(类似于TCP/IP),标准很多。
二、Linux 是什么内核是什么
Linus Torvalds1991年的一片文章上写道“
LINUX is a free unix-like kernel for 386-AT computers, coming with full source code. It is meant for hackers/computer science students to use, learn and enjoy. It is written mostly inC, but parts of it are in gnu-format assembler, and the boot-sequence is in intel 086 assembly language. TheC-code is relatively ANSI, with a few GNU enhancements (mostly__asm__ andinline).
”-其实,linux只是一个主要用c写的内核。
从不同的角度来看,内核担任的角色不同。从纯技术角度来看,内核只是软件和硬件的一个中间层,它把从软件发来的请求发送给硬件,完成寻址等操作,还充当了底层驱动。
从应用程序角度来看,内核是对硬件的一个高层次的抽象,应用程序与硬件没有联系,只与内核有联系,内核是应用程序知道的最底层。
从多个并发的进程的角度来看,内核是一个资源管理器,它完成对进程的切换,调度,共享计算机资源(CPU,内存,磁盘,网络等)。
还可以把内核看成一个库,通过系统调用向内核发送各种请求。
三、内核有什么
这个问题是淘宝面试的时候问我的问题,当时不知道从何下手,简单的总结下。有什么,最简单的就是直接看看内核源代码文件夹下有什么,一般内核文件在linux的目录/usr/src/kernels的文件夹下,我安装的操作系统是redhet的,当时没有安装上内核源文件,而且即使是安装上了也是2.6版本的,也不便于学习,所以下载了一个0.11版本的在http://www.oldlinux.org/index_cn.html上面,1.0版本及以上的可在http://www.kernel.org/pub/linux/kernel/上下载到。
简单看下1.0版本有什么文件主要的:
drivers:驱动代码
fs:文件系统的代码
include :包含文件,这个文件利用其他模块重建内核
init:初始化代码,内核工作的起点 //这里面有内核初始化程序main.c,是内核完成所有初始化工作并进入正常运行的关键
ipc:进程间通信的相关代码
kernel:主内核的代码 //最重要的是进程调度函数schedule()、sleep_on()函数和有关的系统调用程序
mm:内存管理的代码
net:网络管理的代码
0.11版本的.c文件代码有8578行,而1.0版本里面的.c文件代码大概有14w行,其中drives文件夹下就有7w行,2.6版本的有几百万行,估计那是任何大婶也读不完的~
上面简单的说明了源代码的目录结构,如果从系统的结构来看,linux操作系统可以分成五个比较核心的模块,进程调度模块,内存管理模块,文件系统模块,进程间通信模块和网络接口模块。其中的内存管理模块用于确保所有的进程能够安全地共享机器主要内存区,同时内存管理模块还支持虚拟内存的管理方式,使得Linux支持进程使用比实际内存空间多的内存容量。文件系统模块用于支持对外部设备的驱动和存储,虚拟文件系统模块通过对向所有的外部存储设备提供一个通用的文件接口,隐藏了各种硬件设备的不同细节,提高兼容性。下面是操作系统各个模块间的简单关系,虚线和虚框表示0.11上还为实现。
从图中可以看出,所有的模块都与进程调度模块存在依赖关系,因为他们都需要依靠进程调度程序来挂起(暂停)或重新运行它们的进程。还可以根据源代码的结构将内核结构划分成如下的形式:
浏览量:2
下载量:0
时间:
sysctl配置与显示在/proc/sys目录中的内核参数.可以用sysctl来设置或重新设置联网功能,如IP转发、IP碎片去除以及源路由检查等。用户只需要编辑/etc/sysctl.conf文件,即可手工或自动执行由sysctl控制的功能。小编为大家分享了 Linux怎么在系统运行过程中修改内核参数的方法,下面大家跟着读文网小编一起来了解一下吧。
RedHat向管理员提供了非常好的方法,使我们可以在系统运行时更改内核参数,而不需要重新引导系统。这是通过/proc虚拟文件系统实 现的。/proc/sys目录下存放着大多数的内核参数,并且设计成可以在系统运行的同时进行更改。下面我们以打开内核的 ip转发功能为例说明在系统运行时修改内核参数的两种方法。IP转发是指允许系统对来源和目的地都不是本机的数据包通过网络,RedHat默认屏蔽此功 能,在 需要用本机作为路由器、NAT等情况下需要开启此功能。
方法一:修改/proc下内核参数文件内容
直接修改内核参数ip_forward对应在/proc下的文件/proc/sys/net/ipv4/ip_forward。用下面命令查看ip_forward文件内容:
# cat /proc/sys/net/ipv4/ip_forward
该文件默认值0是禁止ip转发,修改为1即开启ip转发功能。修改命令如下:
# echo 1 >/proc/sys/net/ipv4/ip_forward
修改过后就马上生效,即内核已经打开ip转发功能。但如果系统重启后则又恢复为默认值0,如果想永久打开需要通过修改/etc/sysctl.conf文件的内容来实现。
方法二.修改/etc/sysctl.conf文件
默认sysctl.conf文件中有一个变量是
net.ipv4.ip_forward = 0
将后面值改为1,然后保存文件。因为每次系统启动时初始化脚本/etc/rc.d/rc.sysinit会读取/etc/sysctl.conf文件的 内容,所以修改后每次系统启动时都会开启ip转发功能。但只是修改sysctl文件不会马上生效,如果想使修改马上生效可以执行下面的命令:
# sysctl –p
在修改其他内核参数时可以向/etc/sysctl.conf文件中添加相应变量即可,下面介绍/proc/sys下内核文件与配置文件 sysctl.conf中变量的对应关系,由于可以修改的内核参数都在/proc/sys目录下,所以sysctl.conf的变量名省略了目录的前面部 分(/proc/sys)。
将/proc/sys中的文件转换成sysctl中的变量依据下面两个简单的规则:
1.去掉前面部分/proc/sys
2.将文件名中的斜杠这两条规则可以将/proc/sys中的任一文件名转换成sysctl中的变量名。
例如:
/proc/sys/net/ipv4/ip_forward =》 net.ipv4.ip_forward
/proc/sys/kernel/hostname =》 kernel.hostname
可以使用下面命令查询所有可修改的变量名
# sysctl –a
下面例举几个简单的内核参数:
1./proc/sys/kernel/shmmax
该文件指定内核所允许的最大共享内存段的大小。
2./proc/sys/kernel/threads-max
该文件指定内核所能使用的线程的最大数目。
3./proc/sys/kernel/hostname
该文件允许您配置网络主机名。
4./proc/sys/kernel/domainname
该文件允许您配置网络域名。
看过“ 怎么在 Linux系统运行过程中修改内核参数 ”
浏览量:2
下载量:0
时间:
由于内核更新速度很快,总是有更新,每更新一次,启动菜单上就会多一个内核版本菜单,时间一长,会积累很多,鉴于此,在不使用旧版内核时,可以将其删除。那么Linux系统怎么删除旧内核?下面跟着读文网小编一起去了解下吧。
Linux系统本身就是一个开源的系统,所以在使用过程中可以进行修改,只有它的内核是不变的,只有在一段时间之内,才可以对Linux内核进行升级。升级了以后就会留下一些旧的无用的内核,中本文就以Ubuntu系统为例,来介绍一下Linux系统如何删除旧内核?
首先可查看当前用的内核是哪个,可通过命令:uname -a 来获得信息。例如我台式机上显示为:
magc@magc-desktop:~$ uname -a
Linux magc-desktop 2.6.24-19-rt #1 SMP PREEMPT RT Thu Aug 21 02:08:03 UTC 2008 i686 GNU/Linux
然后通过查看本机上所有内核的列表来决定哪些需要删除掉:
运行命令:dpkg --get-selections|grep linux 例如我本机显示为:
magc@magc-desktop:~$ dpkg --get-selections|grep linux
libselinux1 install
linux-generic install
linux-headers-2.6.24-19 install
linux-headers-2.6.24-19-generic install
linux-headers-2.6.24-19-rt install
linux-headers-2.6.24-21 install
linux-headers-2.6.24-21-generic install
linux-headers-2.6.24-21-rt install
linux-headers-generic install
linux-headers-rt install
linux-image-2.6.24-19-generic deinstall
linux-image-2.6.24-19-rt install
linux-image-2.6.24-21-generic install
linux-image-generic install
linux-image-rt install
linux-restricted-modules-2.6.24-19-generic deinstall
linux-restricted-modules-2.6.24-19-rt install
linux-restricted-modules-2.6.24-21-generic install
linux-restricted-modules-common install
linux-restricted-modules-generic install
linux-restricted-modules-rt install
linux-rt install
linux-sound-base install
linux-ubuntu-modules-2.6.24-19-generic deinstall
linux-ubuntu-modules-2.6.24-19-rt install
linux-ubuntu-modules-2.6.24-21-generic install
util-linux install
util-linux-locales install
其中带有image的就是内核文件,因此可看出我的机器上共五个内核版本。我当前使用的是2.6.24-19-rt,所以决定将其它没用的内核删除。
删除的命令为:sudo apt-get remove linux-image-XXXX
例如删除linux-image-2.6.24-19-generic内核的办法就是:
sudo apt-get remove linux-image-2.6.24-19-generic
以上就是Linux系统如何删除旧内核的全部内容了,首先找到旧内核,记录它们的名称。然后用sudo apt-get remove删除就可以了。
看过“ Linux系统怎么删除旧内核 ”
浏览量:3
下载量:0
时间:
当我们需要在Linux系统中安装一些软件而去下载安装文件时,一般都需要确认到底下载哪个版本的安装包,这就需要我们知道自己的Linux系统到底是什么版本、什么内核,下面跟着读文网小编一起来了解一下Linux怎么查看系统已安装内核吧。
操作方法:
RHEL/CentOS/Fedora
在终端中执行如下命令查看已安装的 Linux 内核:
rpm -qa kernel
或
rpm -qa | grep -i kernel
Debian/Ubuntu/Linux Mint
要查看基于 DEB 系统的 Linux 内核列表,如:Debian、Ubuntu、Linux Mint、Elementary OS 等,可以使用如下命令:
dpkg --list | grep linux-image
SUSE/openSUSE
在 SUSE 或 openSUSE 系统中,可以使用如下命令查看 Linux 系统内核:
rpm -qa | grep -i kernel
Arch Linux
Arch Linux 及其衍生发行版本,可以使用如下命令查看已安装的内核列表:
pacman -Q linux
或
pacman -Q | grep linux
以上就是查看已安装的Linux内核的操作方法,如果你也不懂怎么查看内核,可以根据上面介绍的方法来操作。
浏览量:3
下载量:0
时间:
CPU作为电脑的核心组成部份,它的好坏直接影响到电脑的性能。下面是读文网小编带来的关于linux在多核处理器上的负载均衡原理的内容,欢迎阅读!
现在互联网公司使用的都是多CPU(多核)的服务器了,Linux操作系统会自动把任务分配到不同的处理器上,并尽可能的保持负载均衡。那Linux内核是怎么做到让各个CPU的压力均匀的呢?
做一个负载均衡机制,重点在于:
1. 何时检查并调整负载情况?
2. 如何调整负载?
先看第一个问题。
如果让我这样的庸俗程序员来设计,我第一个想到的就是每隔一段时间检查一次负载是否均衡,不均则调整之,这肯定不是最高效的办法,但肯定是实现上最简单的。实际上,2.6.20版linux kernel的确使用软中断来定时调整多CPU上的压力(调用函数run_rebalance_domains),每秒1次。
但每秒一次还是不能满足要求,对很多应用来说,1秒太长了,一秒钟内如果发生负载失衡对很多web应用都是不能接受的,何况其他实时应用。最好kernel能够紧跟进程的变化来调整。
那么,好,我们在进程创建和进程exit的时候检查并调整负载呢?可以,但是不完整,一个进程创建以后如果频繁的睡眠、醒来、睡眠、醒来,它这样折腾对CPU的负载是有影响的,你就不管它了吗?说到底,我们其实关注的是进程是否在使用CPU,而不是它是否诞生了。所以,我们应该在进程睡眠和醒来这两个时间点检查CPU们的负载。
再看第二个问题,怎么调整负载呢?从最繁忙的那个CPU上挪一个进程到最闲的那个CPU上,如果负载还不均衡,就再挪一个进程,如果还不均衡,继续挪....这也是个最笨的方法,但它却真的是linux CPU负载均衡的核心,不过实际的算法在此基础上有很多细化。对于Intel的CPU,压缩在同一个chip上的多核是共享同一个L2的(如下图,里面的一个Processor其实就是一个chip),如果任务能尽可能的分配在同一个chip上,L2 cache就可以继续使用,这对运行速度是有帮助的。所以除非“很不均衡”,否则尽量不要把一个chip上的任务挪到其他chip上。
于是,为了应对这种CPU core之间的异质性——在不同的core之间迁移任务,代价不同——Linux kernel引入了sched_domain和sched_group的概念。sched_domain和sched_group的具体原理,可参考刘勃的文章和英文资料。
【代码剖析】
SMP负载均衡检查或调整在两个内核函数里发生:
1. schedule()。当进程调用了sleep、usleep、poll、epoll、pause时,也就是调用了可能睡去的操作时都会转为内核代码里对schedule()函数的调用。
2. try_to_wake_up() 。说白了就是进程刚才睡了,现在要醒来,那醒来以后跑在哪个CPU上呢?这个选择CPU的过程,也就是负载均衡的过程。
我们先看schedule()的代码,我们忽略函数前面那些和负载均衡无关的代码(本文代码以内核2.6.20版为准):
[kernel/sched.c --> schedule() ]
3489 cpu = smp_processor_id();
3490 if (unlikely(!rq->nr_running)) {
3491 idle_balance(cpu, rq);
3492 if (!rq->nr_running) {
3493 next = rq->idle;
3494 rq->expired_timestamp = 0;
3495 wake_sleeping_dependent(cpu);
3496 goto switch_tasks;
3497 }
3498 }
每个CPU都有一个运行队列即这里的 rq,运行队列里放着该CPU要运行的进程,如果运行队列里没有进程了,就说明当前CPU没有可调度的任务了,那就要调用idle_balance从其它CPU上“平衡”一些(就是挪一些)进程到当前rq里。
再看 idle_balance()的实现:
[kernel/sched.c --> idle_balance()]
2806 /*
2807 * idle_balance is called by schedule() if this_cpu is about to become
2808 * idle. Attempts to pull tasks from other CPUs.
2809 */
2810 static void idle_balance(int this_cpu, struct rq *this_rq)
2811 {
2812 struct sched_domain *sd;
2813 int pulled_task = 0;
2814 unsigned long next_balance = jiffies + 60 * HZ;
2815
2816 for_each_domain(this_cpu, sd) {
2817 unsigned long interval;
2818
2819 if (!(sd->flags & SD_LOAD_BALANCE))
2820 continue;
2821
2822 if (sd->flags & SD_BALANCE_NEWIDLE)
2823 /* If we've pulled tasks over stop searching: */
2824 pulled_task = load_balance_newidle(this_cpu,
2825 this_rq, sd);
2826
2827 interval = msecs_to_jiffies(sd->balance_interval);
2828 if (time_after(next_balance, sd->last_balance + interval))
2829 next_balance = sd->last_balance + interval;
2830 if (pulled_task)
2831 break;
2832 }
2833 if (!pulled_task)
2834 /*
2835 * We are going idle. next_balance may be set based on
2836 * a busy processor. So reset next_balance.
2837 */
2838 this_rq->next_balance = next_balance;
2839 }
从子 sched_domain到父sched_domain遍历该CPU对应的domain(2816行),并调用load_balance_newidle,我们继续:
[kernel/sched.c --> load_balance_newidle()]
2730 static int
2731 load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
2732 {
2733 struct sched_group *group;
2734 struct rq *busiest = NULL;
2735 unsigned long imbalance;
2736 int nr_moved = 0;
2737 int sd_idle = 0;
2738 cpumask_t cpus = CPU_MASK_ALL;
2739
2740 /*
2741 * When power savings policy is enabled for the parent domain, idle
2742 * sibling can pick up load irrespective of busy siblings. In this case,
2743 * let the state of idle sibling percolate up as IDLE, instead of
2744 * portraying it as NOT_IDLE.
2745 */
2746 if (sd->flags & SD_SHARE_CPUPOWER &&
2747 !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
2748 sd_idle = 1;
2749
2750 schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
2751 redo:
2752 group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE,
2753 &sd_idle, &cpus, NULL);
2754 if (!group) {
2755 schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]);
2756 goto out_balanced;
2757 }
2758
2759 busiest = find_busiest_queue(group, NEWLY_IDLE, imbalance,
2760 &cpus);
2761 if (!busiest) {
2762 schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
2763 goto out_balanced;
2764 }
2765
2766 BUG_ON(busiest == this_rq);
2767
2768 schedstat_add(sd, lb_imbalance[NEWLY_IDLE], imbalance);
2769
2770 nr_moved = 0;
2771 if (busiest->nr_running > 1) {
2772 /* Attempt to move tasks */
2773 double_lock_balance(this_rq, busiest);
2774 nr_moved = move_tasks(this_rq, this_cpu, busiest,
2775 minus_1_or_zero(busiest->nr_running),
2776 imbalance, sd, NEWLY_IDLE, NULL);
原来就是我们上面说的“笨办法”,针对当前CPU所属的每个domain(从子到父),找到该 sched_domain里最忙的sched_group(2752行),再从该group里找出最忙的运行队列(2759行),最后从该“最忙”运行队列里挑出几个进程到当前CPU的运行队列里。move_tasks函数到底挪多少进程到当前CPU是由第4和第5个参数决定的,第4个参数是指最多挪多少个进程,第5个参数是指最多挪多少“压力”。有了这两个参数限制,就不会挪过头了(即把太多进程挪到当前CPU,造成新的不均衡)。
举个例子,假如有一台8核的机器,两个CPU插槽,也就是两个chip,每个chip上4个核,再假设现在core 4最忙,core 0第二忙,如图:
按照 刘勃的文章里的提法,首先是core domain,即Processor 0属于domain 1,Processor 1属于domain 2,其中domain 1包含4个sched_group,每个group对应一个core,如下图(group未画出):
假如现在是 Core 3 在执行idle_balance,则先在domain 1里找最忙的group,找到第二忙的group是core 0(core 4不在domain 1里,所以不会找到它),再从core 0里找最忙的runqueue(运行队列),core 0就一个运行队列,所以直接就是它对应的runqueue了,然后从该runqueue里挪出几个任务到Core 3,这一层domain的均衡做完了。
接着是domain 1的父domain,即 cpu_domain,下图的domain 0:
这个domain 0包含了两个group,每个group对应一个chip,即每个group对应了4个core。
在domain 0找最繁忙的group,显然会找到Processor1 对应的group(因为core 4超忙),那么继续在Processor 1里找最忙的runqueue,于是找到core 4,最后从core 4的runqueue里挑出几个任务挪到core 3,。
这样,整个系统8个核都基本平衡了。
也许有人要问,为什么是从子domain到父domain这样遍历,而不是倒过来,从父到子遍历呢?这是因为子domain通常都是在一个chip上,任务的很多数据在共享的L2 cache上,为了不让其失效,有必要尽量让任务保持在一个chip上。
也许还有人要问:如果core 3本来就是最忙的core,它如果运行idle_balance,会发生什么?答案是什么也不会发生。因为在find_busiest_group函数里,如果发现最忙的是“本CPU”,那么就直接返回NULL,也就不再做任何事。
那core 3岂不永远是最忙的了?呵呵,大家忘了,系统里总有闲的CPU(哪怕是相对比较闲),它总会执行schedule(),就算它从不调用sleep从不睡眠,时钟中断也会迫使其进程切换,进而调用schedule,进而将繁忙CPU的任务揽一部分到自己身上。这样,谁最闲,谁早晚会从忙人身上揽活儿过来,所以忙人不会永远最忙,闲人也不会永远最闲,所以就平等,就均衡了。
再看try_to_wake_up():
[kernel/sched.c --> try_to_wake_up()]
1398 static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
1399 {
......
1417
1418 cpu = task_cpu(p);
1419 this_cpu = smp_processor_id();
1420
1421 #ifdef CONFIG_SMP
1422 if (unlikely(task_running(rq, p)))
1423 goto out_activate;
1424
1425 new_cpu = cpu;
1426
1427 schedstat_inc(rq, ttwu_cnt);
1428 if (cpu == this_cpu) {
1429 schedstat_inc(rq, ttwu_local);
1430 goto out_set_cpu;
1431 }
变量this_cpu和变量cpu有什么区别?变量this_cpu是实际运行这个函数的处理器(“目标处理器”),而变量cpu是进程p在睡眠之前运行的处理器??为了方便我们暂且称之为“源处理器”。当然,这两个处理器也可能是同一个,比如进程p在处理器A上运行,然后睡眠,而运行try_to_wake_up的也是处理器A,其实这样就最好了,进程p在处理器A里cache的数据都不用动,直接让A运行p就行了??这就是1428行的逻辑。
如果this_cpu和cpu不是同一个处理器,那么代码继续:
1447 if (this_sd) {
1448 int idx = this_sd->wake_idx;
1449 unsigned int imbalance;
1450
1451 imbalance = 100 + (this_sd->imbalance_pct - 100) / 2;
1452
1453 load = source_load(cpu, idx);
1454 this_load = target_load(this_cpu, idx);
1455
1456 new_cpu = this_cpu; /* Wake to this CPU if we can */
1457
1458 if (this_sd->flags & SD_WAKE_AFFINE) {
1459 unsigned long tl = this_load;
1460 unsigned long tl_per_task;
1461
1462 tl_per_task = cpu_avg_load_per_task(this_cpu);
1463
1464 /*
1465 * If sync wakeup then subtract the (maximum possible)
1466 * effect of the currently running task from the load
1467 * of the current CPU:
1468 */
1469 if (sync)
1470 tl -= current->load_weight;
1471
1472 if ((tl <= load &&
1473 tl + target_load(cpu, idx) <= tl_per_task) ||
1474 100*(tl + p->load_weight) <= imbalance*load) {
1475 /*
1476 * This domain has SD_WAKE_AFFINE and
1477 * p is cache cold in this domain, and
1478 * there is no bad imbalance.
1479 */
1480 schedstat_inc(this_sd, ttwu_move_affine);
1481 goto out_set_cpu;
1482 }
1483 }
计算出“目标处理器”和“源处理器”各自的负载( 1453行和1454行),再计算“目标处理器”上的每任务平均负载 tl_per_task,最后进行判断:如果“目标处理器”的负载小于“源处理器”的负载且两处理器负载相加都比 tl_per_task小的话,唤醒的进程转为“目标处理器”执行。还有一种情况就是1474行的判断,如果“目标处理器”的负载加上被唤醒的进程的负载后,还比“源处理器”的负载(乘以imbalance后)的小的话,也要把唤醒的进程转为“目标处理器”执行。如果两个因素都不满足,那还是由p进程原来呆的那个CPU(即”源处理器“)继续来处理吧。
有点儿绕,是吧?其实代码虽绕,用意是简单的:
1472行-1473行其实是这样一个用意:如果“目标处理器”的负载很小,小得即使把压力全给到“源处理器”上去也不会超过“源处理器”上的平均任务负载,那么这“目标处理器”的负载是真的很小,值得把p进程挪过来。
1474行的用意则是:如果我们真的把p进程挪到“目标处理器”以后,“目标处理器”的压力也不比“源处理器”大多少,所以,还是值得一挪。
说来说去,还是那个笨原则:把任务从最忙的CPU那儿转到很闲的CPU这儿。
我们已经看过了睡眠和醒来时的内核函数,那么软中断里的 run_rebalance_domains又干了些什么呢?其实也很简单,它调用了load_balance函数,而这个函数和load_balance_newidle实现上基本一样,就不累述了。
浏览量:3
下载量:0
时间:
CPU是电脑的重要组成部分,是不可缺少的角色。下面是读文网小编带来的关于关于linux的进程中的各个线程cpu占用情况进行分析和查看的内容,欢迎阅读!
我们经常会在新开的服搭建一个游戏的服务器,有时候要进行压力测试,那么如何来看呢,一般我们会通过top命令查看各个进程的cpu和内存占用情况,获得到了我们的进程id,然后我们也许会通过pstack命令查看里边的各个线程id以及对应的线程现在正在做什么事情,分析多组数据就可以获得哪些线程里有慢操作影响了服务器的性能,从而得到解决方案。比如这样的以组数据:
[root@AY130816144542124256Z bin]# pstack 30222
Thread 9 (Thread 0x7f729adc1700 (LWP 30251)):
#0 0x00007f72a429b720 in sem_wait () from /lib64/libpthread.so.0
#1 0x0000000000ac5eb6 in Semaphore::down() ()
#2 0x0000000000ac5cac in Queue::get() ()
#3 0x00000000009a583f in DBManager::processUpdate(Queue*) ()
#4 0x00000000009a4bfb in dbUpdateThread(void*) ()
#5 0x00007f72a4295851 in start_thread () from /lib64/libpthread.so.0
#6 0x00007f72a459267d in clone () from /lib64/libc.so.6
Thread 8 (Thread 0x7f727c579700 (LWP 30252)):
#0 0x00007f72a429b720 in sem_wait () from /lib64/libpthread.so.0
#1 0x0000000000ac5eb6 in Semaphore::down() ()
#2 0x0000000000ac5cac in Queue::get() ()
#3 0x00000000009a5799 in DBManager::processQuery(Queue*) ()
#4 0x00000000009a4c3a in dbQueryThread(void*) ()
#5 0x00007f72a4295851 in start_thread () from /lib64/libpthread.so.0
#6 0x00007f72a459267d in clone () from /lib64/libc.so.6
Thread 7 (Thread 0x7f7257fff700 (LWP 30253)):
#0 0x00007f72a42997bb in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1 0x00007f72a549ee08 in utils::thread::condition_impl::timed_wait(int) () from /usr/local/utils-0.0.1/lib/libutils.so.0.0.1
#2 0x00007f72a549ebd3 in utils::thread::Condition::timed_wait(int) () from /usr/local/utils-0.0.1/lib/libutils.so.0.0.1
#3 0x00000000009d5f57 in utils::MessageQueue::pop() ()
#4 0x00000000009d5557 in FightReport::svc() ()
#5 0x00007f72a5494b45 in utils::Task_Base::thread_proc(void*) () from /usr/local/utils-0.0.1/lib/libutils.so.0.0.1
#6 0x00007f72a4295851 in start_thread () from /lib64/libpthread.so.0
#7 0x00007f72a459267d in clone () from /lib64/libc.so.6
Thread 6 (Thread 0x7f72397b7700 (LWP 30254)):
#0 0x00007f72a4588fc3 in poll () from /lib64/libc.so.6
#1 0x00007f72a0fbded4 in __libc_res_nsend () from /lib64/libresolv.so.2
#2 0x00007f72a0fba76a in __libc_res_nquery () from /lib64/libresolv.so.2
#3 0x00007f72a0fbad29 in __libc_res_nquerydomain () from /lib64/libresolv.so.2
#4 0x00007f72a0fbb9cf in __libc_res_nsearch () from /lib64/libresolv.so.2
#5 0x00007f729adc37a7 in _nss_dns_gethostbyname4_r () from /lib64/libnss_dns.so.2
#6 0x00007f72a457a4c3 in gaih_inet () from /lib64/libc.so.6
#7 0x00007f72a457cb20 in getaddrinfo () from /lib64/libc.so.6
#8 0x00007f72a56fc782 in Curl_getaddrinfo_ex () from /usr/lib64/libcurl.so.4
#9 0x00007f72a56f1d42 in Curl_getaddrinfo () from /usr/lib64/libcurl.so.4
#10 0x00007f72a56c9e77 in Curl_resolv () from /usr/lib64/libcurl.so.4
#11 0x00007f72a56ca138 in Curl_resolv_timeout () from /usr/lib64/libcurl.so.4
#12 0x00007f72a56d8d88 in ?? () from /usr/lib64/libcurl.so.4
#13 0x00007f72a56ddb79 in ?? () from /usr/lib64/libcurl.so.4
#14 0x00007f72a56de76e in Curl_connect () from /usr/lib64/libcurl.so.4
#15 0x00007f72a56e69b0 in Curl_perform () from /usr/lib64/libcurl.so.4
#16 0x0000000000ae6e3d in HttpClient::svc() ()
#17 0x00007f72a5494b45 in utils::Task_Base::thread_proc(void*) () from /usr/local/utils-0.0.1/lib/libutils.so.0.0.1
#18 0x00007f72a4295851 in start_thread () from /lib64/libpthread.so.0
#19 0x00007f72a459267d in clone () from /lib64/libc.so.6
Thread 5 (Thread 0x7f721af6f700 (LWP 30255)):
#0 0x00007f72a455691d in nanosleep () from /lib64/libc.so.6
#1 0x000000000098cb8a in Sleep(unsigned long) ()
#2 0x000000000098b87d in DynResource::svc() ()
#3 0x00007f72a5494b45 in utils::Task_Base::thread_proc(void*) () from /usr/local/utils-0.0.1/lib/libutils.so.0.0.1
#4 0x00007f72a4295851 in start_thread () from /lib64/libpthread.so.0
#5 0x00007f72a459267d in clone () from /lib64/libc.so.6
Thread 4 (Thread 0x7f71fc727700 (LWP 30256)):
#0 0x00007f72a455691d in nanosleep () from /lib64/libc.so.6
#1 0x000000000098cb8a in Sleep(unsigned long) ()
#2 0x0000000000a61516 in PlayerOpLogThread::svc() ()
#3 0x00007f72a5494b45 in utils::Task_Base::thread_proc(void*) () from /usr/local/utils-0.0.1/lib/libutils.so.0.0.1
#4 0x00007f72a4295851 in start_thread () from /lib64/libpthread.so.0
#5 0x00007f72a459267d in clone () from /lib64/libc.so.6
Thread 3 (Thread 0x7f71ddedf700 (LWP 30257)):
#0 0x00007f72a4592c73 in epoll_wait () from /lib64/libc.so.6
#1 0x00007f72a51f334f in Epoll_Reactor::run_reactor_event_loop() () from /usr/local/net_manager-0.0.2/lib/libnet_manager.so.0.0.2
#2 0x00007f72a51f2523 in Net_Thread::svc() () from /usr/local/net_manager-0.0.2/lib/libnet_manager.so.0.0.2
#3 0x00007f72a5494b45 in utils::Task_Base::thread_proc(void*) () from /usr/local/utils-0.0.1/lib/libutils.so.0.0.1
#4 0x00007f72a4295851 in start_thread () from /lib64/libpthread.so.0
#5 0x00007f72a459267d in clone () from /lib64/libc.so.6
Thread 2 (Thread 0x7f71bf697700 (LWP 30258)):
#0 0x00007f72a4592c73 in epoll_wait () from /lib64/libc.so.6
#1 0x00007f72a51f334f in Epoll_Reactor::run_reactor_event_loop() () from /usr/local/net_manager-0.0.2/lib/libnet_manager.so.0.0.2
#2 0x00007f72a51f2523 in Net_Thread::svc() () from /usr/local/net_manager-0.0.2/lib/libnet_manager.so.0.0.2
#3 0x00007f72a5494b45 in utils::Task_Base::thread_proc(void*) () from /usr/local/utils-0.0.1/lib/libutils.so.0.0.1
#4 0x00007f72a4295851 in start_thread () from /lib64/libpthread.so.0
#5 0x00007f72a459267d in clone () from /lib64/libc.so.6
Thread 1 (Thread 0x7f72a60ae7e0 (LWP 30222)):
#0 0x00007f72a4584c95 in _xstat () from /lib64/libc.so.6
#1 0x00007f72a45483e0 in __tzfile_read () from /lib64/libc.so.6
#2 0x00007f72a4547864 in tzset_internal () from /lib64/libc.so.6
#3 0x00007f72a4547b20 in tzset () from /lib64/libc.so.6
#4 0x00007f72a4546699 in timelocal () from /lib64/libc.so.6
#5 0x0000000000b0b08d in Achieve::GetRemainTime(AchieveTemplate*) ()
#6 0x0000000000b115ca in Achieve::update() ()
#7 0x0000000000a197ce in Player::update() ()
#8 0x0000000000b1b272 in PlayerMng::Tick() ()
#9 0x0000000000a73105 in GameServer::FrameTick(unsigned int) ()
#10 0x0000000000a6ff80 in GameServer::run() ()
#11 0x0000000000a773a1 in main ()
[root@AY130816144542124256Z gameserver]# ps -eLo pid,lwp,pcpu | grep 30222
30222 30222 31.4
30222 30251 0.0
30222 30252 0.0
30222 30253 0.0
30222 30254 0.0
30222 30255 0.0
30222 30256 1.2
30222 30257 1.2
30222 30258 1.0
多组数据显示表明我们的主逻辑线程的确占用的cpu很高,发现其实在Achieve::update() 的时候做了太多没有用的判断,并且可以减少循环进入的次数的,所以我在这里进行了优化
后来用了一下iptraf命令查看了网络流量:
第一项:IP流量监控
第二项:常规查看网卡流量状态。只查看各网卡的总流量
第三项:详细查看网卡流量状态。比如按TCP,UDP,ARP等协议查看
选all interfaces,查看所有网卡接口
界面分上下两部分,上部分可详细显示哪个与之相连的IP,发了多少包,即时流量是多少,下部分,可以显示udp等信息。
显示连接本地服务器的所有连接流量情况
另外不得不提到另外一个命令sar:
sar有很多用途,如果要来监控网络流量,使用下面的命令行方式:
sar -n DEV interval count
其中,interval是统计时间间隔,以秒为单位;count是总共统计几次,如果为0就不断的统计直到 Ctrl+C 打断,否则执行count次就退出。
比如:sar -n DEV 1 4
比如:sar -n DEV 10 0
IFACE:LAN接口
rxpck/s:每秒钟接收的数据包
txpck/s:每秒钟发送的数据包
rxbyt/s:每秒钟接收的字节数
txbyt/s:每秒钟发送的字节数
sar -n DEV -u 1 10
07:22:01 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
07:22:02 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
07:22:02 PM eth0 2.47 0.00 0.11 0.00 0.00 0.00 0.00
07:22:02 PM eth1 80.25 22.22 3.53 3.52 0.00 0.00 0.00
07:22:02 PM CPU %user %nice %system %iowait %steal %idle
07:22:03 PM all 1.85 0.00 1.06 0.00 0.00 97.09
07:22:02 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
07:22:03 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
07:22:03 PM eth0 0.00 0.00 0.00 0.00 0.00 0.00 0.00
07:22:03 PM eth1 66.67 19.75 2.95 3.22 0.00 0.00 0.00
07:22:03 PM CPU %user %nice %system %iowait %steal %idle
07:22:04 PM all 2.12 0.00 1.06 0.00 0.00 96.82
07:22:03 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
07:22:04 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
07:22:04 PM eth0 7.32 4.88 0.65 0.38 0.00 0.00 0.00
07:22:04 PM eth1 85.37 28.05 4.18 3.88 0.00 0.00 0.00
07:22:04 PM CPU %user %nice %system %iowait %steal %idle
07:22:05 PM all 3.96 0.00 2.64 0.00 0.00 93.40
07:22:04 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
07:22:05 PM lo 412.50 412.50 104.44 104.44 0.00 0.00 0.00
07:22:05 PM eth0 13.75 12.50 1.32 1.26 0.00 0.00 0.00
07:22:05 PM eth1 903.75 707.50 174.12 62.42 0.00 0.00 0.00
07:22:05 PM CPU %user %nice %system %iowait %steal %idle
07:22:06 PM all 5.25 0.00 4.46 2.10 0.00 88.19
07:22:05 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
07:22:06 PM lo 849.41 849.41 154.54 154.54 0.00 0.00 0.00
07:22:06 PM eth0 0.00 0.00 0.00 0.00 0.00 0.00 0.00
07:22:06 PM eth1 1287.06 1337.65 84.48 461.76 0.00 0.00 0.00
07:22:06 PM CPU %user %nice %system %iowait %steal %idle
07:22:07 PM all 1.85 0.00 1.06 0.00 0.00 97.09
07:22:06 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
07:22:07 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
07:22:07 PM eth0 4.94 0.00 0.22 0.00 0.00 0.00 0.00
07:22:07 PM eth1 97.53 19.75 4.32 3.18 0.00 0.00 0.00
07:22:07 PM CPU %user %nice %system %iowait %steal %idle
07:22:08 PM all 1.58 0.00 1.32 0.00 0.00 97.11
07:22:07 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
07:22:08 PM lo 4.94 4.94 0.31 0.31 0.00 0.00 0.00
07:22:08 PM eth0 1.23 0.00 0.06 0.00 0.00 0.00 0.00
07:22:08 PM eth1 67.90 24.69 3.02 3.94 0.00 0.00 0.00
Average: CPU %user %nice %system %iowait %steal %idle
Average: all 3.63 0.00 2.55 0.84 0.00 92.98
Average: IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
Average: lo 212.61 212.61 50.54 50.54 0.00 0.00 0.00
Average: eth0 42.79 41.70 3.27 41.84 0.00 0.00 0.00
Average: eth1 492.48 432.48 53.63 110.40 0.00 0.00 0.00
浏览量:3
下载量:0
时间:
脚本病毒原理分析编辑,你了解吗!下面由读文网小编给你做出详细的脚本病毒原理编辑分析介绍!希望对你有帮助!欢迎回访读文网网站,谢谢!
VBS病毒是用VB Script编写而成,该脚本语言功能非常强大,它们利用Windows系统的开放性特点,通过调用一些现成的Windows对象、组件,可以直接对文件系统、注册表等进行控制,功能非常强大。应该说病毒就是一种思想,但是这种思想在用VBS实现时变得极其容易。VBS脚本病毒具有如下几个特点:
1.编写简单,一个以前对病毒一无所知的病毒爱好者可以在很短的时间里编出一个新型病毒来。
2.破坏力大。其破坏力不仅表现在对用户系统文件及性能的破坏。他还可以使邮件服务器崩溃,网络发生严重阻塞。
3.感染力强。由于脚本是直接解释执行,并且它不需要像PE病毒那样,需要做复杂的PE文件格式处理,因此这类病毒可以直接通过自我复制的方式感染其他同类文件,并且自我的异常处理变得非常容易。
4.传播范围大。这类病毒通过htm文档,Email附件或其它方式,可以在很短时间内传遍世界各地。
5.病毒源码容易被获取,变种多。由于VBS病毒解释执行,其源代码可读性非常强,即使病毒源码经过加密处理后,其源代码的获取还是比较简单。因此,这类病毒变种比较多,稍微改变一下病毒的结构,或者修改一下特征值,很多杀毒软件可能就无能为力。
6.欺骗性强。脚本病毒为了得到运行机会,往往会采用各种让用户不大注意的手段,譬如,邮件的附件名采用双后缀,如.jpg.vbs,由于系统默认不显示后缀,这样,用户看到这个文件的时候,就会认为它是一个jpg图片文件。
7.使得病毒生产机实现起来非常容易。所谓病毒生产机,就是可以按照用户的意愿,生产病毒的机器(当然,这里指的是程序),目前的病毒生产机,之所以大多数都为脚本病毒生产机,其中最重要的一点还是因为脚本是解释执行的,实现起来非常容易,具体将在我们后面谈及。
正因为以上几个特点,脚本病毒发展异常迅猛,特别是病毒生产机的出现,使得生成新型脚本病毒变得非常容易。
看过“脚本病毒原理编辑分析 ”人还看了:
浏览量:3
下载量:0
时间:
linux发行版本有很多种,但是其内核大多使用的是标准的linux内核,只是版本不同而已,所以,想要深入学习linux开发及其原理,学习研究内核是必不可少的,下面读文网小编就为大家介绍一下如何下载linux内核
打开百度官网,输入kernel内核开始搜索,
找到官网,点击打开,网络速度可能比较慢
打开后我们在其首页就可以看到最近版本的linux内核下载按钮,这里我们下载的linux4.2.3版本的内核
下载好后我们会得到一个压缩包,但是根据我的实验,在windows下打开会报错,所以我们这里将其转入到linux下解压打开
如图,这是我解压后的linux内核压缩包,进入该文件夹,我们会看到很多内核相关的文件及文件夹
这时我们就可以用vi或者vim编辑器来研究分析我们的linux内核了
浏览量:4
下载量:0
时间:
内核配制详细说明
1. Code maturity level options
代码成熟等级。此处只有一项:prompt for development and/or incomplete code/drivers,如果你要试验现在仍处于实验阶段的功能,比如khttpd、IPv6等,就必须把该项选择为Y了;否则可以把它选择为N。
2. Loadable module support
对模块的支持。这里面有三项:
Enable loadable module support:除非你准备把所有需要的内容都编译到内核里面,否则该项应该是必选的。
Set version inFORMation on all module symbols:可以不选它。
Kernel module loader:让内核在启动时有自己装入必需模块的能力,建议选上。
3. Processor type and features
CPU类型。内容蛮多的,不一一介绍了,有关的几个如下:
Processor family:根据你自己的情况选择CPU类型。
High Memory Support:大容量内存的支持。可以支持到4G、64G,一般可以不选。
Math emulation:协处理器仿真。协处理器是在386时代的宠儿,现在早已不用了。
MTTR support:MTTR支持。可不选。
Symmetric multi-processing support:对称多处理支持。除非你富到有多个CPU,否则就不用选了。
4. General setup
这里是对最普通的一些属性进行设置。这部分内容非常多,一般使用缺省设置就可以了。下面介绍一下经常使用的一些选项:
Networking support:网络支持。必须,没有网卡也建议你选上。
PCI support:PCI支持。如果使用了PCI的卡,当然必选。
PCI access mode:PCI存取模式。可供选择的有BIOS、Direct和Any,选Any吧。
Support for hot-pluggabel devices:热插拔设备支持。支持的不是太好,可不选。
PCMCIA/CardBus support:PCMCIA/CardBus支持。有PCMCIA就必选了。
System V IPC
BSD Process Accounting
Sysctl support:以上三项是有关进程处理/IPC调用的,主要就是System V和BSD两种风格。如果你不是使用BSD,就按照缺省吧。
Power Management support:电源管理支持。
Advanced Power Management BIOS support:高级电源管理BIOS支持。
5. Memory Technology Device(MTD)
MTD设备支持。可不选。
6. Parallel port support
并口支持。如果不打算使用串口,就别选了。
7. Plug and Play configuration
即插即用支持。虽然Linux对即插即用目前支持的不如Windows好,但是还是选上吧,这样你可以拔下鼠标之类的体验一下Linux下即插即用的感觉。
8. Block devices
块设备支持。这个就得针对自己的情况来选了,简单说明一下吧:
Normal PC floppy disk support:普通PC软盘支持。这个应该必选。
XT hard disk support:
Compaq SMART2 support:
Mulex DAC960/DAC1100 PCI RAID Controller support:RAID镜像用的。
Loopback device support:
Network block device support:网络块设备支持。如果想访问网上邻居的东西,就选上。
Logical volume manager(LVM)support:逻辑卷管理支持。
Multiple devices driver support:多设备驱动支持。
RAM disk support:RAM盘支持。
9. Networking options
网络选项。这里配置的是网络协议。内容太多了,不一一介绍了,自己看吧,如果你对网络协议有所了解的话,应该可以看懂的。如果懒得看,使用缺省选项(肯定要选中TCP/IP networking哦)就可以了。让我们看看,TCP/IP、ATM、IPX、DECnet、Appletalk……支持的协议好多哦,IPv6也支持了,Qos and/or fair queueing(服务质量公平调度)也支持了,还有kHTTPd,不过这些都还在实验阶段。
10. Telephony Support
电话支持。Linux下可以支持电话卡,这样你就可以在IP上使用普通的电话提供语音服务了。记住,电话卡可和modem没有任何关系哦。
11. ATA/IDE/MFM/RLL support
这个是有关各种接口的硬盘/光驱/磁带/软盘支持的,内容太多了,使用缺省的选项吧,如果你使用了比较特殊的设备,比如PCMCIA等,就到里面自己找相应的选项吧。
12. SCSI support
SCSI设备的支持。我没有SCSI的设备,所以根本就不用选,如果你用了SCSI的硬盘/光驱/磁带等设备,自己找好了。
13. Fusion MPT device support
需要Fusion MPT兼容PCI适配器,不用选。
14. I2O device support
需要I2O接口适配器支持,在智能Input/Output(I2O)体系接口中使用。
15. Network device support
网络设备支持。上面选好协议了,现在该选设备了,可想而知,内容肯定多得很。还好还好,里面大概分类了,有ARCnet设备、Ethernet(10 or 100 Mbit)、Ethernet(1000Mbit)、Wireless LAN(non-hamradio)、Token Ring device、Wan interfaces、PCMCIA network device support几大类。我用的是10/100M的以太网,看来只需要选则这个了。还是10/100M的以太网设备熟悉,内容虽然多,一眼就可以看到我所用的RealTeck RTL-8139 PCI Fast Ethernet Adapter support,为了免得麻烦,编译到内核里面好了,不选M了,选Y。耐心点,一般说来你都能找到自己用的网卡。如果没有,你只好自己到厂商那里去要驱动了。
16. Amateur Radio support
配置业余无线广播。
17. IrDA(infrared)support
红外线支持。
18. ISDN subsystem
如果你使用ISDN上网,这个就必不可少了。
19. Old CD-ROM drivers(not SCSI、not IDE)
做的可真周到,原来那些非SCSI/IDE口的光驱谁还在用啊,自己选吧,用IDE的CD-ROM不用选。
20. Character devices
字符设备。这个内容又太多了,先使用缺省设置,需要的话自己就修改。把大类介绍一下吧:
I2C support:I2C是Philips极力推动的微控制应用中使用的低速串行总线协议。如果你要选择下面的Video For Linux,该项必选。
Mice:鼠标。现在可以支持总线、串口、PS/2、C&T 82C710 mouse port、PC110 digitizer pad,自己根据需要选择。
Joysticks:手柄。即使在Linux下把手柄驱动起来意义也不是太大,游戏太少了。
Watchdog Cards:虽然称为Cards,这个可以用纯软件来实现,当然也有硬件的。如果你把这个选中,那么就会在你的/dev下创建一个名为watchdog的文件,它可以记录你的系统的运行情况,一直到系统重新启动的1分钟左右。有了这个文件,你就可以恢复系统到重启前的状态了。
Video For Linux:支持有关的音频/视频卡。
Ftape, the floppy tape device driver:
PCMCIA character device support:
21. File systems
文件系统。内容又太多了,老法子,在缺省选项的基础上进行修改。介绍以下几项:
Quota support:Quota可以限制每个用户可以使用的硬盘空间的上限,在多用户共同使用一台主机的情况中十分有效。
DOS FAT fs support:DOS FAT文件格式的支持,可以支持FAT16、FAT32。
ISO 9660 CD-ROM file system support:光盘使用的就是ISO 9660的文件格式。
NTFS file system support:ntfs是NT使用的文件格式。
/proc file system support:/proc文件系统是Linux提供给用户和系统进行交互的通道,建议选上,否则有些功能没法正确执行。
还有另外三个大类都规到这儿了:Network File Systems(网络文件系统)、Partition Types(分区类型)、Native Language Support(本地语言支持)。值得一提的是Network File Systems里面的两种:NFS和SMB分别是Linux和Windows相互以网络邻居的形式访问对方所使用的文件系统,根据需要加以选择。
22. Console drivers
控制台驱动。一般使用VGA text console就可以了,标准的80*25的文本控制台。
23. Sound
声卡驱动。如果你能在列表中找到声卡驱动那自然最好,否则就试试OSS了。
24. USB supprot
USB支持。很多USB设备,比如鼠标、调制解调器、打印机、扫描仪等,在Linux都可以得到支持,根据需要自行选择。
25. Kernel hacking
配置了这个,即使在系统崩溃时,你也可以进行一定的工作了。普通用户是用不着这个功能的。
浏览量:2
下载量:0
时间:
欢迎来到读文网,本文介绍分析Linux系统rc.sysinit脚本,欢迎您阅读。
#!/bin/bash
#
# /etc/rc.d/rc.sysinit - run once at boot time
#
#
# Rerun ourselves through initlog https:// 通过 /sbin/initlog 命令重新运行自己
if [ -z "$IN_INITLOG" -a -x /sbin/initlog ]; then https:// 条件是 :如果 IN_INITLOG 变量的值不为空,且 /sbin/initlog 可执行
exec /sbin/initlog -r /etc/rc.d/rc.sysinit https:// 调用 exec /sbin/initlog ,-r 是表示运行某个程序
fi
######################################################################################################################################################
HOSTNAME=`/bin/hostname` # 取得主机名
HOSTTYPE=`uname -m` # 取得主机类型
unamer=`uname -r` # 取得内核的 release 版本(例如 2.4.9.30-8)
eval version=`echo $unamer | awk -F ‘.‘ ‘{ print "(" $1 " " $2 ")" }‘` # 取得版本号
if [ -f /etc/sysconfig/network ]; then # 如果存在 /etc/sysconfig/network ,则执行该文件。
. /etc/sysconfig/network # network 文件主要控制是否启用网络、默认网关、主机名
fi
if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then # 如果执行 network 文件后 HOSTNAME 为空或者为 "(none)" ,
HOSTNAME=localhost # 则将主机名设置为 "localhost"
fi
# Mount /proc and /sys (done here so volume labels can work with fsck) # 接下来是挂载 /proc 和 /sys ,这样 fsck 才能使用卷标
mount -n -t proc /proc /proc # -n 表示不写 /etc/mtab ,这在 /etc 所在的文件系统为只读时用。因为此时的/还是只读的
[ -d /proc/bus/usb ] && mount -n -t usbfs /proc/bus/usb /proc/bus/usb # 如果存在 /proc/bus/usb 目录则把 /proc/bus/usb 以 usbfs 挂载到 /proc/bus/usb 下
mount -n -t sysfs /sys /sys >/dev/null 2>&1 # 接下来就是把 /sys 目录以 sysfs 格式挂载到 /sys 目录下
########################################################################################################################################################
. /etc/init.d/functions # 执行 /etc/init.d/functions 文件,该文件提供了很多有用的函数,具体见 “functions 脚本提供的函数”一文
########################################################################################################################################################
#selinux段相关注释,邹立巍(mini.jerry@gmail.com)
# Check SELinux status #检察selinux状态
selinuxfs=`awk ‘/ selinuxfs / { print $2 }‘ /proc/mounts` #找到selinux的状态显示目录,默认为/selinux
SELINUX= #将SELINUX变量初始化
if [ -n "$selinuxfs" ] && [ "`cat /proc/self/attr/current`" != "kernel" ]; then
if [ -r $selinuxfs/enforce ] ; then
SELINUX=`cat $selinuxfs/enforce`
else
# assume enforcing if you can‘t read it
SELINUX=1
fi
fi
#以上if语句显示,当变量selinuxfs的值不为空,且/proc/self/attr/current文件内容不是kernel时(此时说明selinux的状态被设置为打开),
#检查/selinux/enforce是否可读,若可读,则设置SELINUX变量状态为/selinux/enforce文件内容。如果不可读,设置为1。
if [ -x /sbin/restorecon ] && LC_ALL=C fgrep -q " /dev " /proc/mounts ; then
/sbin/restorecon -R /dev 2>/dev/null
fi
#用restorecon命令重新标记/dev目录的安全上下文
disable_selinux() {
echo "*** Warning -- SELinux is active"
echo "*** Disabling security enforcement for system recovery."
echo "*** Run ‘setenforce 1‘ to reenable."
echo "0" > $selinuxfs/enforce
}
#定义函数disable_selinux(),此函数用来将selinux设置为Permissive状态,即selinux的调试状态
relabel_selinux() {
if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then
chvt 1
fi
#检查主机是否活动,如果活动则切换到tty1上
echo "
*** Warning -- SELinux relabel is required. ***
*** Disabling security enforcement. ***
*** Relabeling could take a very long time, ***
*** depending on file system size. ***
"
echo "0" > $selinuxfs/enforce #将selinux设置为Permissive状态,以便重新标记文件的安全上下文
/sbin/fixfiles -F relabel > /dev/null 2>&1 #用fixfile命令重新标记安全上下文
rm -f /.autorelabel #删除标记时产生的临时文件
echo "*** Enabling security enforcement. ***"
echo $SELINUX > $selinuxfs/enforce #将selinux设置为enforce状态
if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then
chvt 8
fi
#如过主机处于活动状态,切换到tty8
}
#定义函数relabel_selinux(),此函数用来重新标记所有文件的安全上下文
########################################################################################################################################################
if [ "$HOSTTYPE" != "s390" -a "$HOSTTYPE" != "s390x" ]; then
last=0
for i in `LC_ALL=C grep ‘^[0-9].*respawn:/sbin/mingetty‘ /etc/inittab | sed ‘s/^.* tty([0-9][0-9]*).*/1/g‘`; do
> /dev/tty$i
last=$i
done
if [ $last -gt 0 ]; then
> /dev/tty$((last+1))
> /dev/tty$((last+2))
fi
fi
########################################################################################################################################################
if [ "$CONSOLETYPE" = "vt" -a -x /sbin/setsysfont ]; then # 下面是设置屏幕的默认字体。如果 CONSOLETYPE 变量的值为 vt 且 /sbin/setsysfont 命令可执行
echo -n "Setting default font ($SYSFONT): " # 打印 "setting deafault font xxxx " ,默认字体应该是 xxxx
/sbin/setsysfont # 执行 /sbin/setsysfont
if [ $? -eq 0 ]; then # 如果上述命令执行返回的 exit status 为 0
success # 则调用 success 函数(来自于 functions 脚本),记录一个成功的事件
else
failure # 否则调用 failure 函数
fi
echo ; echo
fi
########################################################################################################################################################
# Print a text banner. # 下面部分是打印 "welcome to xxxxx" 的标题栏
echo -en $"Welcome to " # 打印 "Welcom to" ,同时不换行
if LC_ALL=C fgrep -q "Red Hat" /etc/redhat-release ; then # 从 /etc/redhat-release 文件中找出含有 "Red Hat" 的行,如果找到
[ "$BOOTUP" = "color" ] && echo -en "\033[0;31m" # 则变量 BOOTUP 的值为 color ,并设置输出字体输出红色
echo -en "Red Hat" # 同时打印 "Red Hat" ,接下来打印发行版本(产品)
[ "$BOOTUP" = "color" ] && echo -en "\033[0;39m" # 如果变量 BOOTUP 的值为 color 则设置输出字体为白色
PRODUCT=`sed "s/Red Hat (.*) release.*/1/" /etc/redhat-release` # 从 /etc/redhat-release 中找出含有 "Red Hat" 且后面若干字符,然后是 "release" 的行,并截取中间部分给 PRODUCT
echo " $PRODUCT" # 输出变量 PRODUCT 的值(白色)
elif LC_ALL=C fgrep -q "Fedora" /etc/redhat-release ; then , ; # 如果/etc/redhat-release 中没有 Red Hat 字符串,但有 Fedora ,则执行类似过程
[ "$BOOTUP" = "color" ] && echo -en "\033[0;31m"
echo -en "Fedora"
[ "$BOOTUP" = "color" ] && echo -en "\033[0;39m"
PRODUCT=`sed "s/Fedora (.*) release.*/1/" /etc/redhat-release`
echo " $PRODUCT"
else # 如果 /etc/redhat-release 中既没有含 Red Hat 也没有含 Fedora 的行,则
PRODUCT=`sed "s/ release.*https://g" /etc/redhat-release` # 找到含有 ‘release‘ 的行,并把它前面的部分输出,作为 PRODUCT 变量的值并输出
echo "$PRODUCT"
fi
# 补充 :实际效果是 Red Hat 两个字是红色,其他都是白色
########################################################################################################################################################
if [ "$PROMPT" != "no" ]; then # 如果变量 PROMPT 的值不为 "no" (表示允许交互启动),则
echo -en $"Press ‘I‘ to enter interactive startup." # 打印提示信息“Press I to enter interactive startup”,但此时按 I 还未起作用
echo
fi
########################################################################################################################################################
# 注释 :下面部分是设置输出到 console 的日志的详细级别
# Fix console loglevel # 设置控制台的日志级别
if [ -n "$LOGLEVEL" ]; then # 如果 LOGLEVEL 变量的值不为空
/bin/dmesg -n $LOGLEVEL # 则执行 dmesg ,设置打印到 consoel 的日志的级别为 $LOGLEVEL
fi
########################################################################################################################################################
# 注释 :下面部分是启动 udev 并加载 ide、scsi、network、audio 以及其他类型的设备的模块的部分
[ -x /sbin/start_udev ] && /sbin/start_udev # 如果 /sbin/start_udev 可执行,则执行它,会在屏幕上显示 “Starting udev ... [OK]”
# Only read this once.
cmdline=$(cat /proc/cmdline) # 读取 /proc/cmdline ,这是内核启动的时的参数,赋予变量 cmdline
# Initialize hardware # 下面初始化硬件
if [ -f /proc/sys/kernel/modprobe ]; then # 如果 /proc/sys/kernel/modprobe 文件存在(该文件告诉内核用什么命令来加载模块),则
if ! strstr "$cmdline" nomodules && [ -f /proc/modules ] ; then # 如果 $cmdline 变量的值含有 nomodules ,且存在 /proc/modules 文件,则
sysctl -w kernel.modprobe="/sbin/modprobe" >/dev/null 2>&1 # 使用 sysctl 设置 kernel.modprobe 为 /sbin/modprobe 命令
sysctl -w kernel.hotplug="/sbin/hotplug" >/dev/null 2>&1 # 使用 sysctl 设置 kernel.hotplug 为 /sbin/hotplug 命令
else # 如果不存在 /proc/sys/kernel/modprobe 文件,则
# We used to set this to NULL, but that causes ‘failed to exec‘ messages"
sysctl -w kernel.modprobe="/bin/true" >/dev/null 2>&1 # 使用 sysctl 设置 kernel.modprobe 为 /bin/true
sysctl -w kernel.hotplug="/bin/true" >/dev/null 2>&1 # kernel.hotplug 也一样
fi
fi
########################################################################################################################################################
# 注释 :下面开始真正的加载各种类型的设备的驱动
# 首先是找出那些模块需要被加载,并把模块名按类分别放到 ide、scsi、network、audio、other 5个变量中
echo -n $"Initializing hardware... " # 打印 "initalizing hardware.." (不换行),并开始初始化硬件
ide="" # 下面这些变量都是为了存储的型号,格式为 " ..."
scsi=""
network=""
audio=""
other=""
eval `kmodule | while read devtype mod ; do # 从 kmodule 命令的输出一次读入两个变量 devtype (设备类型)和 mod(模块名)
case "$devtype" in # 根据 devtype 做出适当的选择
"IDE") ide="$ide $mod" # 如果 devtype 的值为 IDE ,则把 mod 加入到现有的 ide 变量的值中
echo "ide="$ide"";; &nb, sp; # 输出 "ide=" 然后是变量 ide 的值
"SCSI") scsi="$scsi $mod" # 如果 devtype 的值为 SCSI ,则把 mod 变量的值加入到 scsi 变量的值中
echo "scsi="$scsi"";; # 输出 "scsi=" 再输出 $scsi
"NETWORK") network="$network $mod" # 下面的 NETWORK 和 AUDIO 也一样
echo "network="$network"";;
"AUDIO") audio="$audio $mod"
echo "audio="$audio"";;
*) other="$other $mod" # 如果是属于 other 类型的则把模块名 $mod 加入到 other 变量的值列表中
echo "other="$other"";;
esac
done`
load_module () { # 定义一个函数名为 load_module
LC_ALL=C fgrep -xq "$1" /etc/hotplug/blacklist 2>/dev/null || modprobe $1 >/dev/null 2>&1 # 在 /etc/hotplug/blacklist 文件中查找是否有指定的模块,如果没有,
} # 再用 modprobe 加载指定的模块
# IDE # 下面开始加载所有 IDE 类型的设备的模块
for module in $ide ; do # 从 ide 变量中每次取出1个值,赋予变量 module
load_module $module # 再用 load_module 函数加载它。如果该模块存在于 /etc/hotplug/blacklist ,则不会被加载(因为存在于黑名单中)
done
# SCSI # SCSI 方面的比较特殊,除了加载 scsi 变量中的模块外,还会从 modprobe -c (显示所有配置)中找出 scsi 卡(hostadapter)的模块
for module in `/sbin/modprobe -c | awk ‘/^alias[[:space:]]+scsi_hostadapter[[:space:]]/ { print $3 }‘` $scsi; do # 从 modprobe -c 中找出所有scsi卡的模块别名,
load_module $module # 并和 scsi 变量一起,通过 for 循环一一加载
done
load_module floppy # 然后加载 floppy 模块
echo -n $" storage" # 输出 "storage" ,表示存储方面的模块加载已经完成
# Network # 接下来是加载网络设备模块
pushd /etc/sysconfig/network-scripts >/dev/null 2>&1 # pushd 是一个 bash 的内建命令,把目录名放入目录堆栈的顶部,并进入指定目录
interfaces=`ls ifcfg* | LC_ALL=C egrep -v ‘(ifcfg-lo|:|rpmsave|rpmorig|rpmnew)‘ | # 找出 network-scripts 目录下所有 lscfg 开头的文件名,排除指定备份和loopback
LC_ALL=C egrep -v ‘(~|.bak)$‘ | # 排除以 ~ 和 .bask 结尾的文件名
LC_ALL=C egrep ‘ifcfg-[A-Za-z0-9._-]+$‘ | # 找出所有以 ifcfg- 开头,并以多个字母/数字结尾的文件名
sed ‘s/^ifcfg-https://g‘ | # 把前缀 ifcfg- 去掉,只留下后面的接口名
sed ‘s/[0-9]/ &/‘ | LC_ALL=C sort -k 1,1 -k 2n | sed ‘s/ https://‘` # 在数字前面加上空格,是类型和编号分离,便于 sort 排序,然后再组合回去
# 目的是按顺序启动接口
for i in $interfaces ; do # 对于在 $interfaces 变量中的每个接口
eval $(LC_ALL=C fgrep "DEVICE=" ifcfg-$i) # 从对应的文件 ifcfg-$i 找出 DEVICE= 行
load_module $DEVICE # 然后用 load_module 加载它,注意,DEVICE= 行可以是别名,例如 eth1.n7css
done
popd >/dev/null 2>&1 # 把 network-scripts 从目录名堆栈中弹出,并返回原来的目录
for module in $network ; do # 剩下还有 network 变量中的模块
load_module $module # 也一一加载
done
echo -n $" network" # 输出 network 字符串,表示加载网络设备模块工作完毕
# Sound
for module in `/sbin/modprobe -c | awk ‘/^alias[[:space:]]+snd-card-[[:digit:]]+[[:space:]]/ { print $3 }‘` $audio; do # 和 scsi 一样,加载在 modprobe -c 和 audio 变量
load_module $module # 中的模块
done
echo -n $" audio" &nbs, p; # 输出 audio ,表示声卡设备驱动加载完毕,一般会有多个驱动被加载
# Everything else (duck and cover) # 剩下的就是 other 类型的设备了
for module in $other ; do
load_module $module # 这个直接用 load_moudle 函数加载了
done
echo -n $" done" # 输出 done 表示完成
success # 调用 success 函数,记录该事件
echo
########################################################################################################################################################
# 注释 :下面是启用 Software-RAID 的检测
echo "raidautorun /dev/md0" | nash --quiet # 用 nash (小型脚本解释器)执行 "raidautorun /dev/md0" 命令,对所有paritition ID 为 0xFD 分区进行检查
########################################################################################################################################################
# Start the graphical boot, if necessary; /usr may not be mounted yet, so we # 显示图形模式的启动画面,但由于 rhgb 命令在 /usr 分区上,
# may have to do this again after mounting # 这时 /usr 分区还没有被挂载,所以在挂载后重新做一遍这部分脚本
RHGB_STARTED=0 # 初始化 RHGB_STARTED 变量的值为 0,表示尚未启动。RHGB 是 redhat graphical boot 的含义,
mount -n /dev/pts # 挂载 /dev/pts ,类型是 devpts ,目的是获得 pty ,这是一种伪文件系统
if strstr "$cmdline" rhgb && [ "$BOOTUP" = "color" -a "$GRAPHICAL" = "yes" -a -x /usr/bin/rhgb ]; then # 如果内核启动参数 $cmdline 含有 rhgb ,且
# BOOTUP 变量的值为 color ,且 GRPAHICAL 变量的值为 yes
# 且 /usr/bin/rhgb 文件存在并可执行
LC_MESSAGES= /usr/bin/rhgb # 把 "/usr/sbin/rhgb" 赋予变量 LC_MESSAGES
RHGB_STARTED=1 # RHGB_STARTED 变量的值为1。
fi
########################################################################################################################################################
# 注释 :下面部分是使用 sysctl 设置内核的参数
# Configure kernel parameters
update_boot_stage RCkernelparam # 调用 update_boot_stage 函数,该函数由 /etc/rc.d/init.d/functions 脚本定义,主要执行 "/usr/sbin/rhgb-client --update $1"
action $"Configuring kernel parameters: " sysctl -e -p /etc/sysctl.conf # 调用 action 函数,执行 sysctl 命令,它读取 /etc/sysctl.conf ,同时输出 “Configuring kernel
# parameters” 字符串,action 函数也是由 /etc/rc.d/init.d/functions 脚本定义
# 补充 :action 函数的作用是把第一个参数 $1 赋予变量 string 并输出到屏幕,同时把该字符串也写入 /etc/rhgb/temp/rhgb-console
# 然后把 $1 后面的部分作为命令交给 initlog 执行,并根据结果调用 success 或者 failure 函数。而 success 或者 failure 函数又会根据结果输出 [ OK ] 或者 [ FAILED ] 。
# 除了 success 和 failure 函数外,functions 脚本还定义了 passed 和 warnning 函数,它们又分别调用 echo_passwd() 和 echo_warnning()函数,
# 以输出 [ PASSED ] 和 [ WARNNING ]
########################################################################################################################################################
# 注释 :下面设置系统的硬件时钟
# Set the system clock. # 接下来设置系统时钟
update_boot_stage RCclock # 同样是告诉 update_boot_stage 该事件(执行 /usr/bin/rhgb-client --update="$1" 命令,这里 $1 就是 "RCclock")
ARC=0
SRM=0
UTC=0
if [ -f /etc/sysconfig/clock ]; then # 如果存在 /etc/sysconfig/clock 则执行该文件
. /etc/sysconfig/clock
# convert old style clock config to new values
if [ "${CLOCKMODE}" = "GMT" ]; then # 如果变量 CLOCKMODE 为旧式的 GMT 格式
UTC=true # 则 UTC 变量的值为 ture
elif [ "${CLOCKMODE}" = "ARC" ]; then # 如果 CLOCKMODE 的值是 ARC ,则
ARC=true # ARC 的值为 true
fi &nbs, p; # 如果 CLOCKMODE 不等于 GMT 或者 UTC ,则 UTC 的值等于 /etc/sysconfig/clock 中的值,一般都是 false
fi # 如果 CLOCKMODE 不等于 GMT 后者 ARC ,则 UTC 的值为 0
CLOCKDEF="" # CLOCKDEF 变量的值默认为空
CLOCKFLAGS="$CLOCKFLAGS --hctosys" # 而 CLOCKFLAGS 变量的值为原来的值(可能为空)加上 ‘--hctosys‘ ,表示把硬件时钟写入内核时钟
case "$UTC" in # 根据 UTC 变量的值进行选择
yes|true) CLOCKFLAGS="$CLOCKFLAGS --utc" # 如果 UTC 的值为 yes 或者 true,则变量 CLOCKFLAGS 的值加上 --utc ,表示采用 UTC 时区
CLOCKDEF="$CLOCKDEF (utc)" ;; # 同时变量 CLOCKDEF 的值加上 "(utc)"
no|false) CLOCKFLAGS="$CLOCKFLAGS --localtime" # 如果变量 UTC 的值为 false 或者 no,则
CLOCKDEF="$CLOCKDEF (localtime)" ;; # CLOCKDEF 的值加上 "(localtime)" 。由于安装 OS时没有选择 UTC,CLOCKDEF 的值一般最后就是 (localtime) 而已
esac
case "$ARC" in # 根据 ARC 变量的值来选择
yes|true) CLOCKFLAGS="$CLOCKFLAGS --arc" # 如果是 yes 或者 true ,则 CLOCKFLAGS 的值加上 --arc ,CLOCKDEF 的值加上 ‘(arc)‘
CLOCKDEF="$CLOCKDEF (arc)" ;; # 如果 ARC 的值为 0 ,则 CLOCKFLAGS 和 CLOCKDEF 的值都不变
esac
case "$SRM" in # 如果 SRM 的值是 yes 或者 true ,则 CLOCKFLAGS 的值加上 "--srm" ,CLOCKDEF 加上 "(srm)"
yes|true) CLOCKFLAGS="$CLOCKFLAGS --srm"
CLOCKDEF="$CLOCKDEF (srm)" ;;
esac
/sbin/hwclock $CLOCKFLAGS # 执行 hwclock $CLOCKFLAGS 命令,一般就是 /sbin/hwclock --hctosys
action $"Setting clock $CLOCKDEF: `date`" date # 并输出 "setting clock " 和 $CLOCKDEF ,并执行 date 输出当前时间,然后输出 [ OK ]
########################################################################################################################################################
# 注释 :下面部分是设置 key map
if [ "$CONSOLETYPE" = "vt" -a -x /bin/loadkeys ]; then # 接下来是设置 keymap ,一般都是 us
KEYTABLE= # 设置 KEYTABLE 和 KEYMAP
KEYMAP=
if [ -f /etc/sysconfig/console/default.kmap ]; then # 假如存在 /etc/sysconfig/console/default.kmap ,则
KEYMAP=/etc/sysconfig/console/default.kmap # KEYMAP 变量的值为 /etc/sysconfig/console/default.kmap
else # 否则
if [ -f /etc/sysconfig/keyboard ]; then # 如果存在 /etc/sysconfig/keyboard 文件,则执行它
. /etc/sysconfig/keyboard # 该文件设置 KEYTABLE 变量的值,例如 KEYTABLE="/usr/lib/kbd/keytables/us.map
fi
if [ -n "$KEYTABLE" -a -d "/lib/kbd/keymaps" ]; then # 如果 KEYTABLE 的值不为空,且存在 /lib/kbd/keymaps/ 目录,则
KEYMAP="$KEYTABLE.map" # KEYMAP 的值为 KEYTABLE 的值加上 ".map"
fi
fi
if [ -n "$KEYMAP" ]; then # 假如 KEYMAP 变量的值不为空(间接表示 KEYTABLE 不为空且存在 keymaps 目录)
# Since this takes in/output from stdin/out, we can‘t use initlog
if [ -n "$KEYTABLE" ]; then # 且 KEYTABLE 的值不为空
echo -n $"Loading default keymap ($KEYTABLE): " # 则输出 "Loading default keymap xxxx"
else
echo -n $"Loading default keymap: " # 否则只输出 Loading default keymap
fi
loadkeys $KEYMAP /dev/tty0 2>/dev/null && # 接下来用 loadkeys 加载 $KEYMAP 指定的键盘映射文件。
success $"Loading default keymap" || failure $"Loading default keymap" # 如果成功则调用 success 函数,否则调用 failure 函数
echo
fi
fi
########################################################################################################################################################
# 注释 :下面部分是设置主机名
# Set the hostname. # 接下来是设置主机名
update_boot_stage RChostname # 告诉 update_boot_stage 函数该事件,以执行 /usr/sbin/rhgb-client --update RChostname 命令
action $"Setting hostname ${HOSTNAME}: " hostname ${HOSTNAME} # 打印 "setting hostname xxxx" 字符串,并执行 hostname ${HOSTNAME}设置主机名
&, nbsp; # 注意,HOSTNAME 变量前面已经有过赋值的了,就是 `/bin/hostname` 命令返回的值
########################################################################################################################################################
# 注释 :下面设置 ACPI 部分
# Initialiaze ACPI bits
if [ -d /proc/acpi ]; then # 如果存在 /proc/acpi 目录,则
for module in /lib/modules/$unamer/kernel/drivers/acpi/* ; do # 对于在 /lib/moduleshttps://kernel/drivers/acpi/ 目录下的所有模块文件,
insmod $module >/dev/null 2>&1 # 都用 insmod 命令加载到内核中
done
fi
########################################################################################################################################################
# 注释 :下面是主要的部分,就是确认是否需要对 / 文件系统进行 fsck
if [ -f /fastboot ] || strstr "$cmdline" fastboot ; then # 接下来是看对 / 系统进行 fsck 的时候了。如果不存在 /fastboot 文件则看 cmdline 变量是否含有 fastboot 字符串
fastboot=yes # 如果有,则 fastboot 变量的值为 yes。/fastboot 是由 shutdown -f 创建的,表示重启时不作 fsck
fi
if [ -f /fsckoptions ]; then # 如果存在 /fsckoptions 文件,则把文件的内容赋予变量 fsckoptions 变量
fsckoptions=`cat /fsckoptions`
fi
if [ -f /forcefsck ] || strstr "$cmdline" forcefsck ; then # 如果不存在 /forcefsck 文件,则检查 cmdline 变量是否含有 forcefsck 字符串,如果有
fsckoptions="-f $fsckoptions" # 则在 fsckoptions 的值前面加上 "-f" 。/forcefsck 是由 shutdown -F 创建的,强制 fsck
elif [ -f /.autofsck ]; then # 如果存在 /.autofsck
if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then # 且文件 /usr/bin/rhgb-clinet 可执行,且 /usr/bin/rhgb 服务在运行(--pnig),则
chvt 1 # 切换到虚拟控制台 #1 (主要是显示 fsck 的信息用)
fi
echo $"Your system appears to have shut down uncleanly" # 并显示需要 fsck 的信息 “You system appears to have shut down uncleanly”
AUTOFSCK_TIMEOUT=5 # 设置超时时间为5秒
[ -f /etc/sysconfig/autofsck ] && . /etc/sysconfig/autofsck # 如果存在 /etc/sysconfig/autofsck 则执行它
if [ "$AUTOFSCK_DEF_CHECK" = "yes" ]; then # 如果执行该文件后 AUTOFSCK_DEF_CHECK 变量的值为 yes ,则
AUTOFSCK_OPT=-f # 变量 AUTOFSCK_OPT 的值为 "-f"
fi
if [ "$PROMPT" != "no" ]; then https:// 如果 PROMPT 的值不为 no ,则
if [ "$AUTOFSCK_DEF_CHECK" = "yes" ]; then https:// 且 AUTOFSCK_DEF_CHECK 的值为 yes
if /sbin/getkey -c $AUTOFSCK_TIMEOUT -m $"Press N within %d seconds to not force file system integrity check..." n ; then https:// 执行 getkey 命令,超时5秒,并
https:// 提示5秒内按下 n 键可跳过 fsck
AUTOFSCK_OPT= https:// 如果用户按下 n ,则 AUTOFSCK_OPT 的值为空,表示取消自动 fsck
fi
else https:// 如果 AUTOFSCK_DEF_CHECK 的值不为 yes ,则提示5秒内按y 可以强制 fsck
if /sbin/getkey -c $AUTOFSCK_TIMEOUT -m $"Press Y within %d seconds to force file system integrity check..." y ; then https:// 同样是用 getkey 捕捉 y 键
AUTOFSCK_OPT=-f https:// 如果用户按下了 y 键,则 AUTOFSCK_OPT 的值为 "-f"
fi
fi
echo
else https:// 如果 PROMPT 的值为 "no", 这是用户无法选择是否 fsck
# PROMPT not allowed
if [ "$AUTOFSCK_DEF_CHECK" = "yes" ]; then # 取决于 AUTOFSCK_DEF_CHECK 变量的值,如果是 yes ,则
echo $"Forcing file system integrity check due to default setting" # 提示由于默认的设置强制 fsck 。可能是 mount 次数达到限制,或者多长时间没有 fsck 了
else
echo $"Not forcing file system integrity check due to default setting" # 如果 AUTOFSCK_DEF_CHECK 的值为 no ,则表示不做 fsck
fi
fi
fsckoptions="$AUTOFSCK_OPT $fsckoptions"
fi
# 注释 :注意!到这里为止并没有执行 fsck 操作,只是判断是否需要执行 fsck 以及 fsck 命令的选项
if [ "$BOOTUP" = "color" ]; then # 如果 BOOTUP 的值为 color ,则
fsckoptions="-C $fsckoptions" # -C 表示显示 fsck 进度信息
else # 否则
fsckoptions="-V $fsckoptions" # -V 表示显示 verbose 信息
fi
if [ -f /etc/sysconfig/readonly-root ]; then # 如果存在 /etc/sysconfig/readonly-root ,则
. /etc/sysconfig/readonly-root # 执行该文件
if [ "$READONLY" = "yes" ]; then # 如果 READONLY 变量的值为 yes ,则
# Call rc.readonly to set up magic stuff needed for readonly root # 执行 /etc/rc.readonly 脚本
. /etc/rc.readonly
fi
fi
#########################################################################################################################################################
# 注释 :下面开始判断 / 文件系统的类型(是本地还是 nfs 格式)。如果是nfs则不执行 fsck ,否则继续
_RUN_QUOTACHECK=0 # 初始化 RUN_QUOTACHECK 的值为0.这里是作一个标记,因为后面的代码可能会导致重启。在这里做好标记
# 如果后面没有重启,就可以把 _RUN_QUOTACHECK 设置为1
ROOTFSTYPE=`awk ‘/ / / && ($3 !~ /rootfs/) { print $3 }‘ /proc/mounts` # 从 /proc/mounts 中找出 / 文件系统的类型,并赋予变量 ROOTFSTYPE
# 注释 :下面用到 -z "$fastboot" ,如果有 /fastboot ,则 fastboot 的值为 yes, 所以就不合 if 的条件,则跳过 fsck 。这就是 shutdown -f 快速启动的效果
if [ -z "$fastboot" -a "$READONLY" != "yes" -a "X$ROOTFSTYPE" != "Xnfs" -a "X$ROOTFSTYPE" != "Xnfs4" ]; then # 如果fastboot 变量的值为空且 READONLY 变量不为 yes
# 且 / 文件系统的类型不是 nfs 或者 nfs4 ,则
STRING=$"Checking root filesystem" # 初始化 string 变量并输出 "checking root filesystem"
echo $STRING
rootdev=`awk ‘/ / / && ($3 !~ /rootfs/) {print $1}‘ /proc/mounts` # 从 /proc/mounts 中找出 / 文件系统所在的设备,并赋予 rootdev 变量(例如 /dev/hdb2)
if [ -b /initrd/"$rootdev" ] ; then # 如果 /initrd/$rootdev 是一个 block 设备
rootdev=/initrd/"$rootdev" # 则 rootdev 就是 /initrd/rootdev
else # 否则 rootdev 就是 / ,正常情况应该是执行该步的,也就是 rootdev 最终为 /
rootdev=/ # rootdev 的值为 / ,因为 fsck 支持用 LABEL、mount point、device name 来指定要检查的文件系统
fi
# 注释 : 下面开始真正的 fsck 操作
if [ "${RHGB_STARTED}" != "0" -a -w /etc/rhgb/temp/rhgb-console ]; then # 如果 RHGB_STARTED 不为0且 /etc/rhgb/tmp/rhgb-console 文件可写,则
fsck -T -a $rootdev $fsckoptions > /etc/rhgb/temp/rhgb-console # 执行 fsck 命令,-T 表示不打印标题栏,-a 表示自动修复错误,设备是 / ,后面是选项
# 且信息写入 /etc/rhgb/temp/rhgb-console
else # 否则
initlog -c "fsck -T -a $rootdev $fsckoptions" # 调用 initlog 执行 fsck ,信息直接输出到屏幕,fsck 命令本身都是一样的。
fi
rc=$? # 把 fsck 的结果送给变量 rc
if [ "$rc" -eq "0" ]; then # 如果 rc的值为0,表示 fsck 成功通过
success "$STRING" # 则调用 success 打印 "checking root fileysyes [OK]"
echo
elif [ "$rc" -eq "1" ]; then # 如果 rc 为1 ,则打印 passed ,表示有错误但修复
passed "$STRING" # 这时调用的是 passed 函数(由 /etc/rc.d/init.d/functions 脚本定义,输出 "checking root filesystems [ PASSED ]")
echo
elif [ "$rc" -eq "2" -o "$rc" -eq "3" ]; then # 如果 rc 为 2 (表示系统应该重启)或者为 3(为 1+2 ,表示系统错误已修复,但需要重启)
echo $"Unmounting file systems" # 提示卸载 / 文件系统
umount -a # 把所有卸载,当然 / 除外
mount -n -o remount,ro / # 把 / 设备已 ro 模式重新 mount
echo $"Automatic reboot in progress." # 然后提示将要自动重启了
&, nbsp; reboot -f # 在这里执行 reboot -f ,强制重启
fi # 这个 fi 是结束 "[ "$rc" -eq "0" ]; " 的
# A return of 4 or higher means there were serious problems. # 如果 fsck 返回的值大于4(不含4,4表示错误未修复),则表示 / 文件系统出现重大错误,无法继续
if [ $rc -gt 1 ]; then # 这里之所以用 -gt 1 ,是因为如果前面返回2或者3就会自动重启了,如果执行到这里说明 rc 的值必须至少大于等于4
if [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then # 如果 rhgb-client 可执行且 rhgb 服务在运行
chvt 1 # 强制切换到 1# 虚拟控制台
fi
failure "$STRING" # 调用 failure 函数,打印 "checking root filesystem [ FAILURE ]"
echo
echo
echo $"*** An error occurred during the file system check." # 提示 fsck 过程出错
echo $"*** Dropping you to a shell; the system will reboot" # 提示将进入紧急模式的 shell
echo $"*** when you leave the shell." # 当你退出该 shell 时会自动重启
str=$"(Repair filesystem)" # 设置紧急模式下的 shell 提示符
PS1="$str # # "; export PS1 # 设置提示符变量 PS1 为 "(Repair filesystem) # " , 表示当前是第几个命令
[ "$SELINUX" = "1" ] && disable_selinux
sulogin # 自动执行 sulogin ,这不是 su ,而是 single-user login 的意思,自动进入单用户模式的 shell
# 注意这里将进入一个交互式的 shell 。只有你执行 exit 命令,才会执行下面的代码,否则下面的代码根本不会被执行
echo $"Unmounting file systems" # 提示卸载文件系统
umount -a # 卸载所有文件系统,/ 除外
mount -n -o remount,ro / # / 以 ro 模式挂载
echo $"Automatic reboot in progress." # 提示将自动重启
reboot -f # 立即重启
elif [ "$rc" -eq "1" ]; then # 如果 rc 的值等于1 ,则表示错误修复完毕
_RUN_QUOTACHECK=1 # 如果上面的 fsck 没有出错,自然就不会重启,所以这里把 _RUN_QUOTACHECK 的值设置为1,表示可以进行 quotacheck 了
fi # 这个 fi 是结束 " [ $rc -gt 1 ]; " 的
if [ -f /.autofsck -a -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --ping ; then # 如果 rhgb-clinet 可运行且 rhgb 服务在运行
chvt 8 # 则切换换 8# 控制台,也就是图形
fi
fi # 这个 fi 是结束前面的 ”[ -z "$fastboot" -a "$READONLY" != "yes" -a "X$ROOTFSTYPE" != "Xnfs" -a "X$ROOTFSTYPE" != "Xnfs4" ]; “ 的
# 所以如果存在 /fastboot 文件,就直接跳转到这里
########################################################################################################################################################
# 注释 :在 initrd 的 /linuxrc 或者 /init 脚本中会把初始/文件系统卸载掉,如果没有卸载完全,则在这里会重新做一次
# Unmount the initrd, if necessary # 接下来是卸载 initrd 初始/ 文件系统,一般 /init 都会在结尾 umount /initrd/dev 的
if LC_ALL=C fgrep -q /initrd /proc/mounts && ! LC_ALL=C fgrep -q /initrd/loopfs /proc/mounts ; then # 如果 /proc/mounts 文件还有 /initrd/proc 条目,
# 且不存在 /initrd/loops 条目,则
if [ -e /initrd/dev/.devfsd ]; then # 如果存在 /initrd/dev/.devfsd 文件,则
umount /initrd/dev # 卸载 /initrd/dev 目录
fi
umount /initrd # 最后把整个 /initrd 卸载
/sbin/blockdev --flushbufs /dev/ram0 >/dev/null 2>&1 # 最后用 blockdev --flushbs 命令清除 /dev/ram0 的内容,该社备就是被挂载为初始/的
fi
######################################################################################################################################################## # 注释 :下面是对 / 进行 quota 检查,其他文件系统暂时不执行 quotacheck
# Possibly update quotas if fsck was run on /. # 如果 fsck 已经对 / 进行了检查,则执行 quotacheck 更新 quota 情况
LC_ALL=C grep -E ‘[[:space:]]+/[[:space:]]+‘ /etc/fstab | # 在 /etc/fstab 中找出 / 文件系统所在的行,并打印第4个字段(属性)
awk ‘{ print $4 }‘ | # 这是属性字段
LC_ALL=C fgrep -q quota # 找出是否有 quota 字符串,不管是 usrquota 还是 grpquota
_ROOT_HAS_QUOTA=$? # 把结果赋予 _ROOT_HAS_QUOTA 变量
if [ "X$_RUN_QUOTACHECK" = "X1" -a # 如果 x$_RUN_QUOTACHECK 返回 X1 ,且
"X$_ROOT_HAS_QUOTA" = "X0" -a # X$_ROOT_HAS_QUOTA 返回 X0 ,则表示当前可以执行 quotacheck ,且 / 也启用了 quota
-x /sbin/quotacheck ]; then # 如果存在 quotacheck 命令
if [ -x /sbin/convertquota ]; then # 如果存在 convertquota 命令
if [ -f /quota.user ]; then # 且存在 /quota.user 则
action $"Converting old user quota files: " # 并调用 action 函数,打印提示信息,用 convertquota 转换成 v2 格式的 aquota.user 文件
/sbin/convertquota -u / && rm -f /quota.user # 然后删除 v1格式的 /quota.user
fi
if [ -f /quota.group ]; then # 同样对 /quota.group 转换成 v2 格式的 aquota.group,并删除 /quota.group 文件
action $"Converting old group quota files: "
/sbin/convertquota -g / && rm -f /quota.group # 同样在转换后删除旧的 v1 的 group quota 文件
fi
fi
action $"Checking root filesystem quotas: " /sbin/quotacheck -nug / # 然后执行 quotacheck -nug / 对 / 文件系统进行检查,并打印提示信息
fi # 这个 fi 是结束 "[ "X$_RUN_QUOTACHECK" = "X1" -a "X$_ROOT_HAS_QUOTA" = "X0" -a -x /sbin/quotacheck ]; " 的
########################################################################################################################################################
# 注释 :下面这个部分是设置 ISA 设备的,不过由于现在基本没有 ISA 设备了,所以可以跳过该部分,甚至可以在内核中指定不支持 ISA
if [ -x /sbin/isapnp -a -f /etc/isapnp.conf -a ! -f /proc/isapnp ]; then
# check for arguments passed from kernel
if ! strstr "$cmdline" nopnp ; then
PNP=yes
fi
if [ -n "$PNP" ]; then
action $"Setting up ISA PNP devices: " /sbin/isapnp /etc/isapnp.conf
else
action $"Skipping ISA PNP configuration at users request: " /bin/true
fi
fi
########################################################################################################################################################
# Remount the root filesystem read-write. # 现在 / 文件系统 fsck 过了,可以按照 read-write 的模式挂载了
update_boot_stage RCmountfs # 告诉 rhgb 服务器更新 RCmountfs 服务的状态
state=`awk ‘/ / / && ($3 !~ /rootfs/) { print $4 }‘ /proc/mounts` # 从 /proc/mounts 中找出 ‘ / ‘ 字符串并且第3个字段不等于 ‘rootfs‘,则打印其第4个字段,赋予 state
[ "$state" != "rw" -a "$READONLY" != "yes" ] && # 如果 state 变量的值不为 ‘rw‘ 且 READONLY 变量的值为 yes ,则
action $"Remounting root filesystem in read-write mode: " mount -n -o remount,rw / # 用 -o remount -o rw 重新挂载 / 为 rw 模式,并打印提示信息
########################################################################################################################################################
# 注释 :下面开始是 LVM2 的部分了
# LVM2 initialization # 下面部分是 LVM2 的初始化部分
if [ -x /sbin/lvm.static ]; then # 如果存在 /sbin/lvm.static 且可执行
if ! LC_ALL=C fgrep -q "device-mapper" /proc/devices 2>/dev/null ; then # 如果 /proc/devices 文件不含有 device-mapper ,则
modprobe dm-mod >/dev/null 2>&1 # 调用 modprobe 加载 dm-mod
fi
echo "mkdmnod" | /sbin/nash --quiet >/dev/null 2>&1 # 并调用 nash 执行 mkdmmod ,不过是以 quiet 模式执行的
[ -n "$SELINUX" ] && restorecon /dev/mapper/control >/dev/null 2>&1
if [ -c /dev/mapper/control -a -x /sbin/lvm.static ]; then # 假如存在 /dev/mapper/control 这个字符设备且 /sbin/lvm.static 可执行,则
if /sbin/lvm.static vgscan --mknodes --ignorelockingfailure > /dev/null 2>&1 ; then # 调用 lvm.static 执行 vgscan 扫描所有卷组(忽略锁错误)
action $"Setting up Logical Volume Management:" /sbin/lvm.static vgchange -a y --ignorelockingfailure # 如果扫描到卷组,则调用 action 函数,
fi # 打印提示信息,并执行 vgchange -ay 激活全部卷组
fi
fi
# LVM initialization # 这是 LVM1 的部分,因为系统可能同时存在 lVM1 和 lvm2 的 pv
if [ -f /etc/lvmtab ]; then # 如果存在 /etc/lvmtab 文件
[ -e /proc/lvm ] || modprobe lvm-mod > /dev/null 2>&1 # 且 /proc/lvm 文件存在,如果没有则调用 modprobe lvm-mod 加载 lvm-mod ,注意模块名的不同
if [ -e /proc/lvm -a -x /sbin/vgchange ]; then # 如果现在存在 /proc/lvm 文件且 /sbin/vgchange 可执行
action $"Setting up Logical Volume Management:" /sbin/vgscan && /sbin/vgchange -a y # 则调用 action 打印提示信息,并执行 vgchange -ay 激活它们
fi
fi
########################################################################################################################################################
# Clean up SELinux labels
if [ -n "$SELINUX" ]; then
for file in /etc/mtab /etc/ld.so.cache ; do
[ -r $file ] && restorecon $file >/dev/null 2>&1
done
fi
########################################################################################################################################################
# Clear mtab # 由于之前的 /etc/mtab 并不准确,所以现在把它的内容清掉
(> /etc/mtab) &> /dev/null # 用 >/etc/mtab 清空其内容
# Remove stale backups
rm -f /etc/mtab~ /etc/mtab~~ # 删除 /etc/mtab 的备份文件
# Enter root, /proc and (potentially) /proc/bus/usb and devfs into mtab. # 把 root ,/proc ,/proc/bus/usb,devpts 加入到 /etc/mtab 中
mount -f / # -f 表示只更新 /etc/mtab ,但不实际mount,因为这些文件系统在之前都挂载了,没有必要再挂载一次
mount -f /proc
mount -f /sys >/dev/null 2>&1
mount -f /dev/pts
[ -f /proc/bus/usb/devices ] && mount -f -t usbfs usbfs /proc/bus/usb # 如果存在 /proc/bus/usb/devices 文件,则用 mount -f -t usbfs 挂载到 /proc/bus/usb 下
[ -e /dev/.devfsd ] && mount -f -t devfs devfs /dev # 如果存在 /dev/.devfsd ,则同样挂载 devfs 到 /dev 下
########################################################################################################################################################
# configure all zfcp (scsi over fibrechannel) devices before trying to mount them
# zfcpconf.sh exists only on mainframe
[ -x /sbin/zfcpconf.sh ] && /sbin/zfcpconf.sh
########################################################################################################################################################
# The root filesystem is now read-write, so we can now log # 由于之前的 / 是只读的,所以通过 initlog 来记录信息,现在可以通过 syslog 了
# via syslog() directly..
if [ -n "$IN_INITLOG" ]; then
IN_INITLOG= # 如果 IN_INITLOG 的值不为空则清空它
fi
if ! strstr "$cmdline" nomodules && [ -f /proc/modules ] ; then # 如果内核启动参数含有 "nomodules" ,且存在 /proc/modules 文件,则
USEMODULES=y # 把 USEMODULES 设置为 y
fi
# Load modules (for backward compatibility with VARs)
if [ -f /etc/rc.modules ]; then
/etc/rc.modules
浏览量:2
下载量:0
时间:
今天,读文网小编就给大家说说Linux内核驱动fsync机制的实现,如果对本文有兴趣的可以跟着小编一起往下看,具体内容如下:
1、定义一个全局的struct fasync_struct指针;
2、实现file_operations中的fasync方法,基本就是调用内核的辅助函数fasync_helper。
3、在驱动某个可以获知数据可访问信息的例程中调用kill_fasync函数。
通过以上内核与应用的配合,就可以方便的使用内核异步通知机制。这种机制用起来简单,观其机制,一开始觉得挺复杂的,一旦深入将所有相关的结构体和例程整理一下就会发现,其实这个机制的实现也很清楚明了。读文网小编一直认为对于内核的学习,首先要理清构架及数据结构间的关系。而看别人的代码分析能让你适当的理解下构架,最后关键在于自己RTFSC。所以读文网小编现在一般不再博文中分析代码,而只说构架和图解,代码需要有兴趣的朋友自己分析。最后如果觉得本文不错的话,就在文章下方给小编点个赞吧。
浏览量:2
下载量:0
时间:
现如今,电脑的使用越来越普遍,几乎每家每户都有电脑,而电脑的操作离不开操作系统,在这里,读文网小编就向大家介绍Linux内核。
很多Linux 爱好者对内核很感兴趣却无从下手,本文旨在介绍一种解读Linux内核源码的入门方法,而不是讲解Linux复杂的内核机制。
1.核心源程序的文件组织
(1)Linux核心源程序通常都安装在/usr/src/Linux下,而且它有一个非常简单的编号约定:任何偶数的核心(中间数字)如:2.0.30都是一个稳定的发行的核心,而任何奇数的核心如:2.1.42都是一个开发中的核心。
本文基于稳定的2.2.5源代码,第二部分的实现平台为Redhat Linux 6.0。
(2)核心源程序的文件按树形结构进行组织,在源程序树的最上层你会看到这样一些目录:
arch:arch子目录包括了所有和体系结构相关的核心代码。它的每一个子目录都代表一种支持的体系结构,例如i386就是关于Intel CPU及与之相兼容体系结构的子目录。PC机一般都基于此目录;
include:include子目录包括编译核心所需要的大部分头文件。与平台无关的头文件在include/linux子目录下,与Intel CPU相关的头文件在include/asm-i386子目录下,而include/scsi目录则是有关SCSI设备的头文件目录;
init:这个目录包含核心的初始化代码(注:不是系统的引导代码),包含两个文件main.c和Version.c,这是研究核心如何工作的一个非常好的起点;
Mm:这个目录包括所有独立于CPU 体系结构的内存管理代码,如页式存储管理内存的分配和释放等,而和体系结构相关的内存管理代码则位于arch/*/mm/,例如arch/i386/mm/Fault.c;
Kernel:主要的核心代码,此目录下的文件实现了大多数Linux系统的内核函数,其中最重要的文件当属sched.c,同样,和体系结构相关的代码在arch/*/kernel中;
Drivers:放置系统所有的设备驱动程序;每种驱动程序又各占用一个子目录,如/block下为块设备驱动程序,比如ide(ide.c)。如果你希望查看所有可能包含文件系统的设备是如何初始化的,你可以看drivers/block/genhd.c中的device_setup()函数。它不仅初始化硬盘,也初始化网络,因为安装nfs文件系统的时候需要使用网络。
其他目录如Lib:放置核心的库代码;Net:核心与网络相关的代码;Ipc:包含核心的进程间通信的代码;Fs:所有的文件系统代码和各种类型的文件操作代码,它的每一个子目录支持一个文件系统,例如fat和ext2、Scripts,此目录包含用于配置核心的脚本文件等。
一般在每个目录下都有一个.depend 文件和一个Makefile 文件,这两个文件都是编译时使用的辅助文件,仔细阅读这两个文件对弄清各个文件之间的联系和依托关系很有帮助,而且在有的目录下还有Readme 文件,它是对该目录下的文件的一些说明,同样有利于我们对内核源码的理解。
2.解读实战:为你的内核增加一个系统调用
虽然Linux 的内核源码用树形结构组织得非常合理、科学,把与功能相关联的文件都放在同一个子目录下,这样使得程序更具可读性。然而,Linux 的内核源码实在是太大而且非常复杂,即便采用了很合理的文件组织方法,在不同目录下的文件之间还是有很多的关联,分析核心的一部分代码通常要查看其他的几个相关的文件,而且可能这些文件还不在同一个子目录下。
下面举一个具体的内核分析实例,希望能通过这个实例,使读者对Linux 的内核组织有些具体的认识,读者从中也可以学到一些对内核的分析方法。
以下即为分析实例:
(1)操作平台
硬件:CPU Intel Pentium II;
软件:Redhat Linux 6.0,内核版本2.2.5
(2)相关内核源代码分析
①系统的引导和初始化:Linux 系统的引导有好几种方式,常见的有Lilo、Loadin引导和Linux的自举引导(bootsect-loader),而后者所对应源程序为arch/i386/boot/bootsect.S,它为实模式的汇编程序,限于篇幅在此不做分析。无论是哪种引导方式,最后都要跳转到arch/i386/Kernel/setup.S。setup.S主要是进行实模式下的初始化,为系统进入保护模式做准备。此后,系统执行arch/i386/kernel/head.S (对经压缩后存放的内核要先执行arch/i386/boot/compressed/head.S);head.S 中定义的一段汇编程序setup_idt,它负责建立一张256项的idt表(Interrupt Descriptor Table),此表保存着所有自陷和中断的入口地址,其中包括系统调用总控程序system_call 的入口地址。当然,除此之外,head.S还要做一些其他的初始化工作。
②系统初始化后运行的第一个内核程序asmlinkage void __init start_kernel(void) 定义在/usr/src/linux/init/main.c中,它通过调用usr/src/linux/arch/i386/kernel/traps.c 中的一个函数void __init trap_init(void) 把各个自陷和中断服务程序的入口地址设置到idt表中,其中系统调用总控程序system_cal就是中断服务程序之一;void __init trap_init(void)函数则通过调用一个宏set_system_gate(SYSCALL_VECTOR,&system_call),把系统调用总控程序的入口挂在中断0x80上。
其中SYSCALL_VECTR是定义在/usr/src/linux/arch/i386/kernel/irq.h中的一个常量0x80,而system_call 即为中断总控程序的入口地址,中断总控程序用汇编语言定义在/usr/src/linux/arch/i386/kernel/entry.S中。
③中断总控程序主要负责保存处理机执行系统调用前的状态,检验当前调用是否合法,并根据系统调用向量,使处理机跳转到保存在sys_call_table 表中的相应系统服务例程的入口,从系统服务例程返回后恢复处理机状态退回用户程序。
而系统调用向量则定义在/usr/src/linux/include/asm-386/unistd.h 中,sys_call_table 表定义在/usr/src/linux/arch/i386/kernel/entry.S 中,同时在/usr/src/linux/include/asm-386/unistd.h 中也定义了系统调用的用户编程接口。
④由此可见,Linux的系统调用也像DOS系统的int 21h中断服务,大把0x80中断作为总的入口,然后转到保存在sys_call_table表中的各种中断服务例程的入口地址,提供各种不同的中断服务。
提供上源代码分析可知,要增加一个系统调用就必须在sys_call_table表中增加一项,并在其中保存好自己的系统服务例程的入口地址,然后重新编译内核,当然,系统服务例程是必不可少的。
由此可知,在此版Linux内核源程序<2.2.5>中,与系统调用相关的源程序文件就包括以下这些:
* arch/i386/boot/bootsect.S
* rch/i386/Kernel/setup.S
* rch/i386/boot/compressed/head.S
* rch/i386/kernel/head.S
* nit/main.c
* rch/i386/kernel/traps.c
* rch/i386/kernel/entry.S
* rch/i386/kernel/irq.h
* nclude/asm-386/unistd.h
当然,这只是涉及到的几个主要文件。而事实上,增加系统调用真正要修改的文件只有include/asm-386/unistd.h 和arch/i386/kernel/entry.S两个。
(3)源码的修改
①kernel/sys.c中增加系统服务例程如下:
asmlinkage int sys_addtotal(int numdata)
{ int i=0,enddata=0;
while(i<=numdata)
enddata+=i++;
return enddata; }
该函数有一个int 型入口参数numdata , 并返回从0 到numdata 的累加值,然而也可以把系统服务例程放在一个自己定义的文件或其他文件中,只是要在相应文件中作必要的说明。
②把smlinkage int sys_addtotal( int) 的入口地址加到sys_call_table表中。
arch/i386/kernel/entry.S 中的最后几行源代码修改前为:
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
.rept NR_syscalls-190
.long SYMBOL_NAME(sys_ni_syscall)
.endr
修改后为:
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
/* add by I */
.long SYMBOL_NAME(sys_addtotal)
.rept NR_syscalls-191
.long SYMBOL_NAME(sys_ni_syscall)
.endr
③把增加的sys_call_table 表项所对应的向量,在include/asm-386/unistd.h 中进行必要申明,以供用户进程和其他系统进程查询或调用。
增加后的部分/usr/src/linux/include/asm-386/unistd.h 文件如下:
#define __NR_sendfile 187
#define __NR_getpmsg 188
#define __NR_putpmsg 189
#define __NR_vfork 190
/* add by I */
#define __NR_addtotal 191
④测试程序(test.c)如下:
#include
#include
_syscall1(int,addtotal,int, num)
main()
{int i,j;
do
printf("Please input a numbern");
while(scanf("%d",&i)==EOF);
if((j=addtotal(i))==-1)
printf("Error occurred in syscall-addtotal(),n");
printf("Total from 0 to %d is %d n",i,j); }
对修改后的新的内核进行编译,并引导它作为新的操作系统,运行几个程序后可以发现一切正常;在新的系统下对测试程序进行编译(注:由于原内核并未提供此系统调用,所以只有在编译后的新内核下,此测试程序才可能被编译通过),运行情况如下:
$gcc .test test.c
$./test
Please input a number
36
Total from 0 to 36 is 666
修改成功后对相关源码进一步分析可知,在此版本的内核中,从/usr/src/linux/arch/i386/kernel/entry.S 文件中对sys_call_table 表的设置可以看出,有好几个系统调用的服务例程都是定义在/usr/src/linux/kernel/sys.c 中的同一个函数:
asmlinkage int sys_ni_syscall(void)
{return -ENOSYS; }
例如第188项和第189项就是如此:
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
而这两项在文件/usr/src/linux/include/asm-386/unistd.h 中却申明如下:
#define __NR_sendfile 187
#define __NR_getpmsg 188 /* some people actually want streams */
#define __NR_putpmsg 189 /* some people actually want streams */
#define __NR_vfork 190
由此可见,在此版本的内核源代码中,由于asmlinkage int sys_ni_syscall(void) 函数并不进行任何操作,所以包括getpmsg, putpmsg 在内的好几个系统调用都是不进行任何操作的,即有待扩充的空调用;但它们却仍然占用着sys_call_table表项,估计这是设计者们为了方便扩充系统调用而安排的,所以只需增加相应服务例程(如增加服务例程getmsg或putpmsg),就可以达到增加系统调用的作用。
3.结束语
要完全解读庞大复杂的Linux内核,一篇文章远远不能介绍清楚,而且与系统调用相关的代码也只是内核中极其微小的一部分,重要的是方法,掌握好的分析方法,所以上述分析只是起个引导作用,而真正的分析还有待读者自己的努力。
浏览量:2
下载量:0
时间:
Linux系统操作中,安装设备驱动时有时需要安装内核头文件,而很多朋友并不知道什么是内核头文件,自然也不知道要如何安装,下面读文网小编就给大家介绍下Linux安装内核头文件的方法。
提问:我在安装一个设备驱动前先要安装内核头文件。怎样安装合适的内核头文件?
当你在编译一个设备驱动模块时,你需要在系统中安装内核头文件。内核头文件同样在你编译与内核直接链接的用户空间程序时需要。当你在这些情况下安装内核头文件时,你必须确保内核头文件精确地与你当前内核版本匹配(比如:3.13.0-24-generic)。
如果你的内核是发行版自带的内核版本,或者使用默认的包管理器的基础仓库升级的(比如:apt-ger、aptitude或者yum),你也可以使用包管理器来安装内核头文件。另一方面,如果下载的是kernel源码并且手动编译的,你可以使用make命令来安装匹配的内核头文件。
现在我们假设你的内核是发行版自带的,让我们看下该如何安装匹配的头文件。
在 Debian、Ubuntu 或者 Linux Mint 上安装内核头文件
假设你没有手动编译内核,你可以使用apt-get命令来安装匹配的内核头文件。
$ rpm -qa | grep kernel-headers-$(uname -r)
kernel-headers-3.10.0-123.9.3.el7.x86_64
Fedora、CentOS 或者 RHEL上默认内核头文件的位置是/usr/include/linux。
上面就是Linux安装内核头文件的方法介绍了,需要注意的是,在安装内核头文件的时候使用yum命令可以自动找到合适的头文件安装,避免不必要的麻烦。
浏览量:2
下载量:0
时间:
编译加载linux驱动和内核模块
到目前为止,我们在构建initramfs时还没有涉及内核模块的支持,所用到的硬件驱动程序都是直接编译到内核中。现在我们就看看如何使initramfs支持内核模块。
编译内核模块
首 先,内核配置要支持模块,并支持内核模块的自动加载功能:在内核配置菜单中的激活下面的配置项,编译进内核
Load module support / Enable loadable module support / Automatic kernel loading ;
然后把需要的硬件驱动程序配置模块形式,比如把我的机器上的硬盘控制器的驱动编译成模块,则选择
Device Driver
|---->SCSI device support
|---->SCSI disk support
|----->verbose SCSI error reporting (不是必须的,但可方便问题定位)
|----->SCSI low-level drivers
|---->Serial ATA (SATA) support
|---->intel PIIX/ICH SATA support
把它们配置成模块。
最后,编译内核,并把编译好的内核模块安装到image的目录下:
make
make INSTALL_MOD_PATH=~/initramfs-test/image modules_install
命 令执行完毕后,在image/lib/modules/2.6.17.13/kernel/drivers/scsi目录下安装了4个内核模文 件:scsi_mod.ko、sd_mod.ko、ata_piix.ko、libata.ko,它们就是所需的硬盘控制器的驱动程序。
加载内核模块
busybox的modprobe命令执行不正常,不能加载内核 模块。怀疑是busybox的modprobe命令配置或编译有问题。否则可以自动加载驱动。先用insmod命令依次加载。查看/lib/modules /2.6.17.13/modules.dep,弄清楚了4个模块的依赖关系,执行下面的命令加载:
insmod scsi_mod
insmod libata
insmod ata_piix
insmod sd_mod
然后再用
mdev -s
命令生成硬盘的设备文件。 好了,可以安装硬盘分区,了并把根文件系统切换到硬盘分区:
mount /dev/sda8 /mnt
exec switch_root /mnt /sbin/init
系统正常启动到了CLFS,我们可以做到用initramfs中的硬盘控制器的驱动模块安装硬盘分区了。
最终init文件
分区要换成自己的分区。
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
insmod scsi_mod
insmod libata
insmod ata_piix
insmod sd_mod
mdev -s
mount /dev/sda8 /mnt
exec switch_root /mnt /sbin/init
浏览量:2
下载量:0
时间:
今天读文网小编就要跟大家讲解下从Linux内核访问用户空间内存的方法~那么对此感兴趣的网友可以多来了解了解下。下面就是具体内容!!!
Linux内核访问用户空间内存的方法
首先读文网小编必须要给大家科普下什么是Linux 内存
在 Linux 中,用户内存和内核内存是独立的,在各自的地址空间实现。地址空间是虚拟的,就是说地址是从物理内存中抽象出来的(通过一个简短描述的过程)。由于地址空间是虚拟的,所以可以存在很多。事实上,内核本身驻留在一个地址空间中,每个进程驻留在自己的地址空间。这些地址空间由虚拟内存地址组成,允许一些带有独立地址空间的进程指向一个相对较小的物理地址空间(在机器的物理内存中)。不仅仅是方便,而且更安全。因为每个地址空间是独立且隔离的,因此很安全。
但是与安全性相关联的成本很高。因为每个进程(和内核)会有相同地址指向不同的物理内存区域,不可能立即共享内存。幸运的是,有一些解决方案。用户进程可以通过 Portable Operating System Interface for UNIX? (POSIX) 共享的内存机制(shmem)共享内存,但有一点要说明,每个进程可能有一个指向相同物理内存区域的不同虚拟地址。
虚拟内存到物理内存的映射通过页表完成,这是在底层软件中实现的(见图 1)。硬件本身提供映射,但是内核管理表及其配置。注意这里的显示,进程可能有一个大的地址空间,但是很少见,就是说小的地址空间的区域(页面)通过页表指向物理内存。这允许进程仅为随时需要的网页指定大的地址空间。
图 1. 页表提供从虚拟地址到物理地址的映射
由于缺乏为进程定义内存的能力,底层物理内存被过度使用。通过一个称为 paging(然而,在 Linux 中通常称为 swap)的进程,很少使用的页面将自动移到一个速度较慢的存储设备(比如磁盘),来容纳需要被访问的其它页面(见图 2 )。这一行为允许,在将很少使用的页面迁移到磁盘来提高物理内存使用的同时,计算机中的物理内存为应用程序更容易需要的页面提供服务。注意,一些页面可以指向文件,在这种情况下,如果页面是脏(dirty)的,数据将被冲洗,如果页面是干净的(clean),直接丢掉。
图 2. 通过将很少使用的页面迁移到速度慢且便宜的存储器,交换使物理内存空间得到了更好的利用
MMU-less 架构
不是所有的处理器都有 MMU。因此,uClinux 发行版(微控制器 Linux)支持操作的一个地址空间。该架构缺乏 MMU 提供的保护,但是允许 Linux 运行另一类处理器。
选择一个页面来交换存储的过程被称为一个页面置换算法,可以通过使用许多算法(至少是最近使用的)来实现。该进程在请求存储位置时发生,存储位置的页面不在存储器中(在存储器管理单元 [MMU] 中无映射)。这个事件被称为一个页面错误 并被硬件(MMU)删除,出现页面错误中断后该事件由防火墙管理。该栈的详细说明见 图 3。
Linux 提供一个有趣的交换实现,该实现提供许多有用的特性。Linux 交换系统允许创建和使用多个交换分区和优先权,这支持存储设备上的交换层次结构,这些存储设备提供不同的性能参数(例如,固态磁盘 [SSD] 上的一级交换和速度较慢的存储设备上的较大的二级交换)。为 SSD 交换附加一个更高的优先级使其可以使用直至耗尽;直到那时,页面才能被写入优先级较低的交换分区。
图 3. 地址空间和虚拟 - 物理地址映射的元素
并不是所有的页面都适合交换。考虑到响应中断的内核代码或者管理页表和交换逻辑的代码,显然,这些页面决不能被换出,因此它们是固定的,或者是永久地驻留在内存中。尽管内核页面不需要进行交换,然而用户页面需要,但是它们可以被固定,通过 mlock(或 mlockall)函数来锁定页面。这就是用户空间内存访问函数的目的。如果内核假设一个用户传递的地址是有效的且是可访问的,最终可能会出现内核严重错误(kernel panic)(例如,因为用户页面被换出,而导致内核中的页面错误)。该应用程序编程接口(API)确保这些边界情况被妥善处理。
内核 API
现在,让我们来研究一下用户操作用户内存的内核 API。请注意,这涉及内核和用户空间接口,而下一部分将研究其他的一些内存 API。用户空间内存访问函数在表 1 中列出。
表 1. 用户空间内存访问 API
正如您所期望的,这些函数的实现架构是独立的。例如在 x86 架构中,您可以使用 ./linux/arch/x86/lib/usercopy_32.c 和 usercopy_64.c 中的源代码找到这些函数以及在 ./linux/arch/x86/include/asm/uaccess.h 中定义的字符串。
当数据移动函数的规则涉及到复制调用的类型时(简单 VS. 聚集),这些函数的作用如图 4 所示。
图 4. 使用 User Space Memory Access API 进行数据移动
access_ok 函数
您可以使用 access_ok 函数在您想要访问的用户空间检查指针的有效性。调用函数提供指向数据块的开始的指针、块大小和访问类型(无论这个区域是用来读还是写的)。函数原型定义如下:
access_ok(type,addr,size);
type 参数可以被指定为 VERIFY_READ 或 VERIFY_WRITE。VERIFY_WRITE 也可以识别内存区域是否可读以及可写(尽管访问仍然会生成 -EFAULT)。该函数简单检查地址可能是在用户空间,而不是内核。
get_user 函数
要从用户空间读取一个简单变量,可以使用 get_user 函数,该函数适用于简单数据类型,比如,char 和 int,但是像结构体这类较大的数据类型,必须使用 copy_from_user 函数。该原型接受一个变量(存储数据)和一个用户空间地址来进行 Read 操作:
get_user(x,ptr);
get_user 函数将映射到两个内部函数其中的一个。在系统内部,这个函数决定被访问变量的大小(根据提供的变量存储结果)并通过 __get_user_x 形成一个内部调用。成功时该函数返回 0,一般情况下,get_user 和 put_user 函数比它们的块复制副本要快一些,如果是小类型被移动的话,应该用它们。
put_user 函数
您可以使用 put_user 函数来将一个简单变量从内核写入用户空间。和 get_user 一样,它接受一个变量(包含要写的值)和一个用户空间地址作为写目标:
put_user(x,ptr);
和 get_user 一样,put_user 函数被内部映射到 put_user_x 函数,成功时,返回 0,出现错误时,返回 -EFAULT。
clear_user 函数
clear_user 函数被用于将用户空间的内存块清零。该函数采用一个指针(用户空间中)和一个型号进行清零,这是以字节定义的:
clear_user(ptr,n);
在内部,clear_user 函数首先检查用户空间指针是否可写(通过 access_ok),然后调用内部函数(通过内联组装方式编码)来执行 Clear 操作。使用带有 repeat 前缀的字符串指令将该函数优化成一个非常紧密的循环。它将返回不可清除的字节数,如果操作成功,则返回 0。
copy_to_user 函数
copy_to_user 函数将数据块从内核复制到用户空间。该函数接受一个指向用户空间缓冲区的指针、一个指向内存缓冲区的指针、以及一个以字节定义的长度。该函数在成功时,返回 0,否则返回一个非零数,指出不能发送的字节数。
copy_to_user(to,from,n);
检查了向用户缓冲区写入的功能之后(通过 access_ok),内部函数 __copy_to_user 被调用,它反过来调用 __copy_from_user_inatomic(在 ./linux/arch/x86/include/asm/uaccess_XX.h 中。其中 XX 是 32 或者 64 ,具体取决于架构。)在确定了是否执行 1、2 或 4 字节复制之后,该函数调用 __copy_to_user_ll,这就是实际工作进行的地方。在损坏的硬件中(在 i486 之前,WP 位在管理模式下不可用),页表可以随时替换,需要将想要的页面固定到内存,使它们在处理时不被换出。i486 之后,该过程只不过是一个优化的副本。
copy_from_user 函数
copy_from_user 函数将数据块从用户空间复制到内核缓冲区。它接受一个目的缓冲区(在内核空间)、一个源缓冲区(从用户空间)和一个以字节定义的长度。和 copy_to_user 一样,该函数在成功时,返回 0 ,否则返回一个非零数,指出不能复制的字节数。
copy_from_user(to,from,n);
该函数首先检查从用户空间源缓冲区读取的能力(通过 access_ok),然后调用 __copy_from_user,最后调用 __copy_from_user_ll。从此开始,根据构架,为执行从用户缓冲区到内核缓冲区的零拷贝(不可用字节)而进行一个调用。优化组装函数包含管理功能。
strnlen_user 函数
strnlen_user 函数也能像 strnlen 那样使用,但前提是缓冲区在用户空间可用。strnlen_user 函数带有两个参数:用户空间缓冲区地址和要检查的最大长度。
strnlen_user(src,n);
strnlen_user 函数首先通过调用 access_ok 检查用户缓冲区是否可读。如果是 strlen 函数被调用,max length 参数则被忽略。
strncpy_from_user 函数
strncpy_from_user 函数将一个字符串从用户空间复制到一个内核缓冲区,给定一个用户空间源地址和最大长度。
strncpy_from_user(dest,src,n);
由于从用户空间复制,该函数首先使用 access_ok 检查缓冲区是否可读。和 copy_from_user 一样,该函数作为一个优化组装函数(在 ./linux/arch/x86/lib/usercopy_XX.c 中)实现。
内存映射的其他模式
上面部分探讨了在内核和用户空间之间移动数据的方法(使用内核初始化操作)。Linux 还提供一些其他的方法,用于在内核和用户空间中移动数据。尽管这些方法未必能够提供与用户空间内存访问函数相同的功能,但是它们在地址空间之间映射内存的功能是相似的。
在用户空间,注意,由于用户进程出现在单独的地址空间,在它们之间移动数据必须经过某种进程间通信机制。Linux 提供各种模式(比如,消息队列),但是最着名的是 POSIX 共享内存(shmem)。该机制允许进程创建一个内存区域,然后同一个或多个进程共享该区域。注意,每个进程可能在其各自的地址空间中映射共享内存区域到不同地址。因此需要相对的寻址偏移(offset addressing)。
mmap 函数允许一个用户空间应用程序在虚拟地址空间中创建一个映射,该功能在某个设备驱动程序类中是常见的,允许将物理设备内存映射到进程的虚拟地址空间。在一个驱动程序中,mmap 函数通过 remap_pfn_range 内核函数实现,它提供设备内存到用户地址空间的线性映射。
结束语
本文讨论了 Linux 中的内存管理主题,然后讨论了使用这些概念的用户空间内存访问函数。在用户空间和内核空间之间移动数据并没有表面上看起来那么简单,但是 Linux 包含一个简单的 API 集合,跨平台为您管理这个复杂的任务。
浏览量:2
下载量:0
时间:
欢迎大家来到读文网,本文教你Linux六大误区,欢迎大家阅读。
原理:利用md5值的不同进行文件的对比。
操作背景:
XP安装光盘;
病毒样本;
U盘;
Ubuntu 7.10 LiveCD
所需的几个对比md5和转化二进制文件格式的程序
操作过程:
1. 全盘格式化,同时安装Windows(也可采用ghost回去,但是一定注意其他磁盘可能的病毒感染)
2. 在刚装好的Windows下,导出注册表。将导出文件放入C盘根目录下。这里我命名为1.reg
3. 进入Ubuntu系统,注意,进入前f2选择简体中文模式
4. 挂载C盘:
mkdir /mnt/hdd1 (生产系统C盘挂载点)
mount -t ntfs -o iocharset=cp936 /dev/hdd1 /mnt/hdd1 (将系统C盘挂载到/mnt/hdd1下,注意文件格式和设备号视具体情况而定)
5. 挂载U盘:
mkdir /mnt/usb (生成U盘挂载点)
mount -t vfat /dev/sda1 /mnt/usb (将U盘挂载到/mnt/usb下,同样注意文件格式和设备号)
6. 将导出的注册表信息放入U盘:
假设U盘上已经有test目录,同时,在test目录下有parse.sh,parseWinReg,ShowList 三个程序
cp /mnt/hdd1/1.reg /mnt/usb/test (将导出注册表拷贝至/mnt/usb/test目录下)
cd /mnt/usb/test (进入U盘test 目录)
./parseWinReg 1.reg origreg (将导出注册表进行格式转换,生成origreg)
7. 计算C盘所有文件md5值:
rm /mnt/hdd1/pagefile.sys (这个文件太大影响计算速度,删除)
/mnt/usb/test/parse.sh /mnt/hdd1/ > /mnt/usb/origfile (计算磁盘文件md5值,并将结果导出至U盘test目录下origfile)
8. 重新进入Windows,同时,激发病毒文件
注意:先将病毒文件放入磁盘,拔掉U盘,拔掉网线,再激发!
9. 重复3,4,5,6,7步骤
mkdir /mnt/hdd1
mount -t ntfs -o iocharset=cp936 /dev/hdd1 /mnt/hdd1
mkdir /mnt/usb
mount -t vfat /dev/sda1 /mnt/usb
cp /mnt/hdd1/2.reg /mnt/usb/test (这里假设导出的注册表是2.reg)
cd /mnt/usb/test
./parseWinReg 2.reg newreg
rm /mnt/hdd1/pagefile.sys
/mnt/usb/test/parse.sh /mnt/hdd1/ > /mnt/usb/newfile
10. 至此,我们得到了原始的系统信息:origreg, origfile,中病毒之后的信息:newreg, newfile
11. 比较文件不同之处:diff -Nur origfile newfile > filediff
12. 比较注册表不同之处:diff -Nur origreg newreg > regdiff
13. 分析filediff 和 regdiff,得到结论
分析小技巧:
一般情况下前面出现+的就是病毒释放的,-就是有过改动的(感染的),如果是md5值是成双成对出现(一个+和一个-),那那一行一般不是,如果前面没有任何标记,那说明也不是。咱们把没用的删除,只留下有单个+或者单个-的,最好看文件路径,即得到了病毒的产生文件或者是感染文件。
浏览量:2
下载量:0
时间:
menuconfig
menuconfig是常用的配制工具,不用特意安装,好像是和GCC一起装上的。
注:menuconfig要用到ncurses的库,所以要安装它。下面的命令可以安装。
apt-get install libncurses*
选择相应的配置时,有三种选择,它们分别代表的含义如下:
“Y”- 将该功能编译进内核
“N”- 不将该功能编译进内核
“M”- 将该功能编译成可以在需要时动态插入到内核中的模块。
将与核心其它部分关系较远且不经常使用的部分功能代码编译成为可加载模块,有利于减小内核的长度,减小内核消耗的内存,简化该功能相应的环境改变时对内核的影响。许多功能都可以这样处理,例如像上面提到的网卡的支持、对FAT等文件系统的支持。
make menuconfig,则需要使用空格键进行选取。你会发现在每一个选项前都有个括号, 但有的是中括号有的是尖括号,还有一种圆括号。 用空格键选择时可以发现,中括号里要么是空,要么是"*",而尖括号里可以是空,"*"和"M"这表示前者对应的项要么不要,要么编译到内核里;后者则多一样选择,可以编译成模块。而圆括号的内容是要你在所提供的几个选项中选择一项。
中括号:要么是空,要么是"*",代表要么不要,要么编译到内核里。
尖括号:可以是空,"*"和"M",多一样选择,可以编译成模块。
圆括号:所提供的几个选项中选择一项。
menuconfig相关命令:
$sudo make menuconfig
配置用到的键只有几个,esc退出菜单;空格改变选项状态;光标键上下左右移动,回车选定。
选项意义:M是编译成可以随时加入的模块,*是编译进入内核,空就是不要。
浏览量:2
下载量:0
时间: