灌溉梦想,记录脚步

nash和initrd.img分析

  nash仅仅是作为initrd.img当中加载驱动所使用的命令解释器而已,并没有对initrd.img当中的linuxrc脚本作一个深入的了解。Redhat ES3当中的initrd.img内容如下:
  #!/bin/nash
  echo “Loading scsi_mod.o module”
  insmod /lib/scsi_mod.o
  echo “Loading sd_mod.o module”
  insmod /lib/sd_mod.o
  echo “Loading libata.o module”
  insmod /lib/libata.o
  echo “Loading ata_piix.o module”
  insmod /lib/ata_piix.o
  echo “Loading jbd.o module”
  insmod /lib/jbd.o
  echo “Loading ext3.o module”
  insmod /lib/ext3.o
  echo Mounting /proc filesystem
  mount -t proc /proc /proc
  echo Creating block devices
  mkdevices /dev
  echo Creating root device
  mkrootdev /dev/root
  echo 0x0100 > /proc/sys/kernel/real-root-dev
  echo Mounting root filesystem
  mount -o defaults –ro -t ext3 /dev/root /sysroot
  pivot_root /sysroot /sysroot/initrd
  umount /initrd/proc

  前面是加载驱动部分,而后面是什么用处,就没有深究了。而我自己用的虚拟机里通常会把驱动和文件系统支持编译到内核,也压根用不着initrd.img,所以把这个宝矿放了过去。今天几个学生在Redhat 9的基础上升级内核到2.6.19,并且是驱动、文件系统用模块方式支持,终于出了问题。该来的还是要来的,应了那句话”出来混,迟早都是要还的”。学生们把前面的硬盘驱动、文件系统驱动都替换成2.6的模块,后半部分在我的误导下删除(当然没有删除的也多半没有成功),结果死活不能进入系统,报无法挂载根文件系统的kernel panic错误。查了半天,发现所有的驱动都加载正常,即便是在linuxrc当中加入bash获得一个shell,检查设备和文件系统的状况也都是正常,可就是提示找不到根文件系统。
  开始引起我注意的是,通常在硬盘驱动和文件系统支持都完备的情况下它并没有提示说VFS的root=xxxx错误,而直接提示的”VFS: Unable to mount root fs on (0, 0)”。这意味着它并未识别在grub.conf当中传递给kernel的root=/dev/xxx参数,因为Linux的设备主设备号是不会为0的。我曾怀疑root=参数没有被接受,但却注意到”Please append a correct “root=” boot option”的提示。
  为了找出问题,我在linuxrc中用bash取得了一个shell,然后挂载proc文件系统后检查/proc/sys/kernel/real_root_dev,发现其值为0。这说明kernel得到的真实root文件系统的设备号不正确(当然有例外,注意后面的解释)。我试着把正确的设备值(例如/dev/sda2用0x802)写入,退出bash之后启动果然正常了。这说明kernel解析参数root=/dev/xxx出现了错误。
  经过核对内核代码,发现kernel确实从root=这个参数传递中获得真实的根文件系统的位置,但是这些/dev/xxx会被转换成内核可识别的设备表示形式。转换的过程中内核会试图检查传递进来的/dev/xxx设备是否存在,而这一步是kernel初始化过程中完成的。当我们把硬盘驱动编译为模块时,kernel初始化过程中硬盘尚不能被识别(要等到kernel初始化完,使用initrd.img才能加载硬盘驱动),于是真实根文件系统的设备号就不能被正确转换,使得其保留为初始值0。
  那对于使用硬盘驱动的情况下如何解决这个问题呢?那就是initrd.img后半部分的工作。在加载完硬盘驱动后,脚本会用mkrootdev生成设备/dev/root,通过man nash你会发现这个命令的作用是根据内核传递参数当中的root=来创建对应该设备的节点,节点名就是/dev/root。之后它会把这个设备挂载到/sysroot这个位置,然后用pivot_root这个根交换的命令把真正运行的根文件系统切换到/sysroot之下,而运行linuxrc的initrd的文件系统将被挂载到真正的根系统下的initrd目录。至于”echo 0x0100 > /proc/sys/kernel/real-root-dev”这个命令,看起来是告诉内核真正的文件系统是/dev/ram0,其实是利用内核判断使用/dev/ram0为根文件系统时不再mount其他设备作为根文件系统的分支,作了一个小小的技巧骗过内核。
  整个脚本的关键在于mkrootdev这个命令。它不仅能够根据root=/dev/xxx来生成对应的设备节点,还能够在碰到root=LABEL=/的情况下探测所有的硬盘分区,以便找到对应着卷标为/的分区。这也解开了我一直没弄清楚的为什么root=LABEL=xxx的参数有些环境可以用而有些却不行的谜团。这个LABEL=/的解析根本不是内核完成的,而是initrd.img当中linuxrc脚本的mkrootdev命令来完成的。脚本的第二个关键在于它负责完成了本是由内核做的挂载真实根文件系统的动作,并对当前根(即initrd使用的内存文件系统)和真实根文件系统进行根切换,又利用欺骗让内核误认为当前使用/dev/ram0作为根文件系统可以不再挂载真实的根文件系统,可谓用心良苦啊 ^_^
  当然,如果完全不用initrd.img的机制,你会发现/proc/sys/kernel/real_root_dev的值也是0。这并不是内核也弄错了,而是只有在使用initrd.img机制时,real_root_dev才反映了内核中记录的真实根文件系统的值,虽然它不一定准确。
  最后,总结一下:
  1、当硬盘驱动以模块形式提供时root=xxx传递给内核的参数可能不会直接起作用,内核在检查这个参数时可能会发现这个设备(因为没有加载驱动而)不存在,因此导致内核没有接受root=xxx的参数。
  2、在这种情况下,initrd.img机制的作用不单单是加载驱动这么简单,还肩负着把正确的真实根的设备位置告知内核的艰巨任务。不过实现的方法有两种:
  2.1 把正确的根设备号写入/proc/sys/kernel/real_root_dev,或者
  2.2 自己挂载真正的根设备,并进行根交换把根系统切换到真实的根系统上,还要阻止内核去挂载它认为的真实根系统
  对于2.2,挂载真正的根系统用nash解释器的内置命令mkrootdev完成,它可以根据传递给kernel的参数(估计读了/proc/cmdline)获得/dev/xxx的字符串,或者得到LABEL=xxx的字符串后查询各个分区的卷标来得到对应的真实根设备号。
  3、如果没有使用initrd.img的机制,/proc/sys/kernel/real_root_dev的值没有任何处理,因为它只有在调用initrd.img的时候才会被同步于内核中的操作对象。
  另外,redhat 9所带的nash解释器(版本3.4.42)在处理mkrootdev的流程上是有bug的。如果传给kernel的参数使用root=/dev/xxx的形式,那么nash会从/proc/sys/kernel/real_root_dev里获取用户想使用的真实根文件系统位置,显然这在我们上面的分析当中是0,也就是错误的;而如果参数传递是root=LABEL=/的形式,那么nash的处理走的另外一个分支,它会通过解析所有分区的卷标来查找所要的真实根文件系统,并不再查询/proc/sys/kernel/real_root_dev,这倒让我们可以得到正确的结果。bug呀bug。
  不过FC6所带的nash 5.1.19已经完全不是这个流程了,应当不存在这样的bug。

使用cpio解压initrd.img

2.6内核中的initrd.img采用cpio压缩,不再是2.4内核使用的ext2格式,无法使用mount -o loop 挂载。需要使用gunzip解压缩,然后再使用cpio解包

cp /boot/initrd-2.6.18-8.1.15.el5.img initrd.img.gz
gunzip initrd.img.gz
mkdir initrd
mv initrd.img initrd
cd initrd
cpio -ivmd < initrd.img

通过以上命令就将initrd.img解压了,现在就可以对其进行编辑,完成后使用以下命令重新压制

find . | cpio -cv > ../initrd.new.img
gzip ../initrd.new.img

再将其改名拷贝至/boot目录,重启就可以观察修改后的效果

linux通过ISCSI无盘启动

一、环境

server: HP Athlon 64bit 3500+ | (running ietd,ISC dhcp,pxelinux,tftp-hpa)

client: DELL Latitude | D610 | (running iSCSI initiator Core)

kernel ver 2.6.14.5 , both server & client machines

二、Server Tasks:

  Setup ISC DHCP
  Setup Syslinux (for PXELinux) & TFTP-HPA
  Setup TFTP-HPA
  Setup iSCSI Target (ietd enterprise target)
  • ) Update! you can skip the dhcp,syslinux,tftp steps by running this auto-configurator!
 wget http://linux-iscsi.org/iscsiboot/server-scripts/pxeserver-setup.sh

三、Client Tasks:

  Setup iSCSI initiator (iSCSI initiator Core)
  Boot time

四、Setup ISC DHCP http://ftp.isc.org/isc/dhcp/dhcp-3.0.3.tar.gz

edit /etc/dhcp/dhcpd.conf

 allow booting;
 allow bootp;
 option routers 192.168.1.6;
 option subnet-mask 255.255.255.0;
 ddns-update-style ad-hoc;
 subnet 192.168.1.0 netmask 255.255.255.0 {
    range 192.168.1.111 192.168.1.115;
 }
 group {
    next-server 192.168.1.6;
    filename "pxelinux.0";
    host laptop-eth0 {
        hardware ethernet 00:00:00:00:00:00; (replace with your mac-address)
 }

五、Setup PXELinux http://kernel.org/pub/linux/utils/boot/syslinux/syslinux-3.11.tar.gz

1) untar syslinux, make && make install

2) untar tftp-hpa, make && make install

  mkdir -p /tftproot/pxelinux.cfg
  cp pxelinux.0 /tftproot
  • ) build a kernel for your client and cp to /tftproot/
  • ) make an initrd and cp to /tftproot

edit /tftproot/pxelinux.cfg/default

  TIMEOUT 50
  PROMPT 1
  LABEL iscsiboot
  KERNEL vmlinuzLaptop
  APPEND root=/dev/ram initrd=bblinux25M
  IPAPPEND 1
  LABEL disk
  LOCALBOOT 0

六、Setup TFTP-HPA http://www.kernel.org/pub/software/network/tftp/tftp-hpa-0.41.tar.gz

  tar zxvf tftp-hpa-0.41.tar.gz
  cd tftp-hpa-0.41
  ./configure
  make
  make install
  • ) Start tftpd: /sbin/in.tftpd -l -v -s /tftproot

Setup iSCSI Target

1) download ietd

  svn export svn://svn.berlios.de/iscsitarget/trunk
  cd trunk && make KERNELSRC=/usr/src/linux && make KERNELSRC=/usr/src/linux install

2) make some test disk.

  ie: dd if=/dev/zero of=/iscsi-diska bs=4096k count=1024

3) configure your new LUN in /etc/ietd.conf

  Target laptop:diska
  Lun 0 Path=/iscsi-diska,Type=fileio
  Alias dell
  DataPDUInOrder Yes
  DataSequenceInOrder Yes

4) start ietd

  /etc/init.d/iscsi-target start

(client side installation notes)

七、Setup iSCSI initiator Core

1) download core-iscsi-tools

http://kernel.org/pub/linux/utils/storage/iscsi/core-iscsi-tools-v3.3.tar.bz2

2) download core-iscsi

http://kernel.org/pub/linux/kernel/people/nab/iscsi-initiator-core/core-iscsi-v1.6.2.5.tar.bz2

3) compile core-iscsi

  make initiator KERNEL_DIR=/usr/src/linux && make install

4) compile core-iscsi-tools

  make install

iSCSI core stack is then loadable via iscsi_initiator_mod.ko,

core tools rely upon /etc/sysconfig/initiator

  CHANNEL="0 2 eth0 192.168.55.6 3260 0"

and /etc/sysconfig/iscsi_device_maps

  DEVICE="0 0 1 diska"

八、Boot time

1) Change bios on client to pxeboot before HD

2) at the pxelinux prompt, type iscsiboot (referring to label in pxelinux.cfg/default)

after successfully booting, do something like this:

  /bin/mount / -o rw,remount
  /bin/mount -t proc none /proc
  /bin/mount -o sysfs /sys
  /sbin/ifconfig eth0 192.168.1.92 255.255.255.0
  cd /dev && /bin/mknod sdb1 b 8 17
  NAME=$(/sbin/initiator-iname)
  echo "InitiatorName=$NAME" > /etc/initiatorname.iscsi
  /etc/rc.d/init.d/initiator start
  • ) If this is a new installation, partition and create a file system, then copy minimal files to your new disk
  /bin/fdisk /dev/sdb # (create partition)
  /bin/mke2fs /dev/sdb1
  /bin/mount /dev/sdb1 /laptop:diska
  cp -dpRav /bin /sbin /dev /etc /var /lib /usr /tmp /laptop:diska
  • ) And, lastly:
  /bin/chroot /laptop:diska /bin/bash

Linux中如何查看文件的最初创建时间

  在Linux中,没有文件创建时间的概念。只有文件的访问时间、修改时间、状态改变时间。也就是说不能知道文件的创建时间。但如果文件创建后就没有修改过,修改时间=创建时间;如果文件创建后,状态就没有改变过,那么状态改变时间=创建时间;如果文件创建后,没有被读取过,那么访问时间=创建时间,这个基本不太可能。
  与文件相关的几个时间:
  1、访问时间,读一次这个文件的内容,这个时间就会更新。比如对这个文件使用more命令。ls、stat命令都不会修改文件的访问时间。
  2、修改时间,对文件内容修改一次,这个时间就会更新。比如:vi后保存文件。ls -l列出的时间就是这个时间。
  3、状态改变时间。通过chmod命令更改一次文件属性,这个时间就会更新。查看文件的详细的状态、准确的修改时间等,可以通过stat命令 文件名。
  比如: [jing@zhjh c]$ stat temp.c
  引用:
  File: ‘temp.c’
  Size: 66 Blocks: 8 IO Block: 4096 \u4e00\u822c\u6587\u4ef6
  Device: 807h/2055d Inode: 1191481 Links: 1
  Access: (0664/-rw-rw-r–) Uid: ( 500/ jing) Gid: ( 500/ jing)
  Access: 2008-03-12 20:19:45.000000000 0800
  Modify: 2008-03-12 20:19:45.000000000 0800
  Change: 2008-03-12 20:19:45.000000000 0800
  说明:Access访问时间。Modify修改时间。Change状态改变时间。可以stat *查看这个目录所有文件的状态。

linux 的计划任务crontab

任务调度的crond常驻命令
crond 是linux用来定期执行程序的命令。当安装完成操作系统之后,默认便会启动此任务调度命令。crond命令每分锺会定期检查是否有要执行的工作,如果有要执行的工作便会自动执行该工作。而linux任务调度的工作主要分为以下两类:
1、系统执行的工作:系统周期性所要执行的工作,如备份系统数据、清理缓存
2、个人执行的工作:某个用户定期要做的工作,例如每隔10分钟检查邮件服务器是否有新信,这些工作可由每个用户自行设置。

一、任务调度设置文件的写法
其格式如下:
Minute Hour Day Month Dayofweek command
分钟 小时 天 月 天每星期 命令

每个字段代表的含义如下:
Minute 每个小时的第几分钟执行该任务
Hour 每天的第几个小时执行该任务
Day 每月的第几天执行该任务
Month 每年的第几个月执行该任务
DayOfWeek 每周的第几天执行该任务
Command 指定要执行的程序
在这些字段里,除了”Command”是每次都必须指定的字段以外,其它字段皆为可选字段,可视需要决定。对于不指定的字段,要用”*”来填补其位置。

举例如下:
1、指定每小时的第5分钟执行一次ls命令
5 * * * * ls

2、指定每天的 5:30 执行ls命令
30 5 * * * ls

3、指定每月8号的7:30分执行ls命令
30 7 8 * * ls

4、指定每年的6月8日5:30执行ls命令
30 5 8 6 * ls

5、指定每星期日的6:30执行ls命令
30 6 * * 0 ls
注:0表示星期天,1表示星期1,以此类推,也可以用英文来表示,sun表示星期天,mon表示星期一等。

6、每月10号及20号的3:30执行ls命令
30 3 10,20 * * ls
注:”,”用来连接多个不连续的时段

7、每天8-11点的第25分钟执行ls命令
25 8-11 * * * ls
注:”-“用来连接连续的时段

8、每15分钟执行一次ls命令
*/15 * * * * ls
即每个小时的第0 15 30 45 60分钟执行ls命令

9、每个月中,每隔10天6:30执行一次ls命令
30 6 */10 * * ls
即每月的1、11、21、31日是的6:30执行一次ls命令。

10、每天7:50以root 身份执行/etc/cron.daily目录中的所有可执行文件
50 7 * * * root run-parts /etc/cron.daily
注:run-parts参数表示,执行后面目录中的所有可执行文件。

二、新增调度任务
新增调度任务可用两种方法:
1、在命令行输入: crontab -e 然后添加相应的任务,wq存盘退出。
2、直接编辑/etc/crontab 文件,即vi /etc/crontab,添加相应的任务。

三、查看调度任务
crontab -l //列出当前的所有调度任务
crontab -l -u jp //列出用户jp的所有调度任务

四、删除任务调度工作
crontab -r //删除所有任务调度工作

五、任务调度执行结果的转向
例1:每天5:30执行ls命令,并把结果输出到/jp/test文件中
30 5 * * * ls >/jp/test 2>&1
注:2>&1 表示执行结果及错误信息。

编辑/etc/crontab 文件配置cron

  cron服务每分钟不仅要读一次/var/spool/cron内的所有文件,还需要读一次/etc/crontab,因此我们配置这个文件也能运用cron服务做一些事情。用crontab配置是针对某个用户的,而编辑/etc/crontab是针对系统的任务。此文件的文件格式是:

  SHELL=/bin/bash

  PATH=/sbin:/bin:/usr/sbin:/usr/bin

  MAILTO=root //如果出现错误,或者有数据输出,数据作为邮件发给这个帐号

  HOME=/ //使用者运行的路径,这里是根目录

  # run-parts

  01 * * * * root run-parts /etc/cron.hourly //每小时执行/etc/cron.hourly内的脚本

  02 4 * * * root run-parts /etc/cron.daily //每天执行/etc/cron.daily内的脚本

  22 4 * * 0 root run-parts /etc/cron.weekly //每星期执行/etc/cron.weekly内的脚本

  42 4 1 * * root run-parts /etc/cron.monthly //每月去执行/etc/cron.monthly内的脚本

  大家注意”run-parts”这个参数了,如果去掉这个参数的话,后面就可以写要运行的某个脚本名,而不是文件夹名了。

Centos无盘工作站安装配置

一、新建目录

Mkdir -p /diskless/x86_64/centos5.2/root

Mkdir /diskless/x86_64/centos5.2/snapshot

二、拷贝模板到/diskless/x86_64/centos5.2/root目录

rsync -auv -e ssh –delete –exclude=’/proc/*’ –exclude=’/sys/*’ –exclude=’/tmp/*’–exclude=’/var/log/*’ root@10.0.70.72:/ /diskless/x86_64/centos5.2/root/

三、配置tftp服务

Yum -y install tftp tftp-server

Yum -y install busybox

Vi /etc/xinetd/tftp

Diskable=no

Chkconfig –level 345 xinetd on

Chkconfig –level 345 tftp on

Service xinetd start

四、配置dhcp服务

Yum -y install dhcp-server

Chkconfig –level 345 dhcpd on


Vi /etc/dhcpd.conf

allow booting;

allow bootp;

class “pxeclients” {

match if substring(option vendor-class-identifier, 0, 9) = “PXEClient”;

next-server <server-ip>;

filename “linux-install/pxelinux.0”;

}

Service dhcpd start

五、配置nfs服务

Yum -y install portmap nfs

Vi /etc/exports

/diskless/x86_64/centos5.2/root *(ro,sync,no_root_squash)

/diskless/x86_64/centos5.2/snapshot/ *(rw,sync,no_root_squash)

Service portmap start

Service nfs start

六、配置无盘环境

If starting the Network Booting Tool for the first time, select Diskless from the First Time Druid. Otherwise, select Configure => Diskless from the pull-down menu, and then click Add.

A wizard appears to step you through the process:

1、Click Forward on the first page.

2、On the Diskless Identifier page, enter a Name and Description for the diskless environment. Click Forward.

3、Enter the IP address or domain name of the NFS server configured in Section 4.3 Configuring the NFS Server as well as the directory exported as the diskless environment. Click Forward.

4、The kernel versions installed in the diskless environment are listed. Select the kernel version to boot on the diskless system.

5、Click Apply to finish the configuration.

七、添加工作站

1、Hostname or IP Address/Subnet – Specify the hostname or IP address of a system to add it as a host for the diskless environment. Enter a subnet to specify a group of systems.

2、Operating System – Select the diskless environment for the host or subnet of hosts.

3、Serial Console – Select this checkbox to perform a serial installation.

4、Snapshot name – Provide a subdirectory name to be used to store all of the read/write content for the host.

5、Ethernet – Select the Ethernet device on the host to use to mount the diskless environment. If the host only has one Ethernet card, select eth0.

CSS隐藏内容的三种方法比较

1.display:none;

搜索引擎可能认为被隐藏的文字属于垃圾信息而被忽略
屏幕阅读器(是为视觉上有障碍的人设计的读取屏幕内容的程序)会忽略被隐藏的文字。

2. visibility: hidden ;
这个大家应该比较熟悉就是隐藏的内容会占据他所应该占据物理空间。

3.overflow:hidden;是比较合理的方法

.texthidden { display:block;/*统一转化为块级元素*/ overflow: hidden; width: 0; height: 0; }

就像上面的一段CSS所展示的方法,将宽度和高度设定为0,然后超过部分隐藏,就会弥补上述一、二方法中的缺陷,也达到了隐藏内容的目的。