用 UUID 在 fstab 中挂载分区

文章来源: www.linuxgem.org

fstab 文件大家都很熟悉,Linux 在启动的时候通过 fstab 中的信息挂载各个分区,一个典型的分区条目就像这样: 

/dev/sdb5              /mnt/usb            vfat      utf8,umask=0              0 0

/dev/sda4 为需要挂载的分区,sda4 是 Linux 检测硬盘时按顺序给分区的命名,一般来讲,这个名称并不会变化,但是如果你有多块硬盘,硬盘在电脑中的顺序变化的时候,相同的名称可能代表着不同的硬盘分 区,如果你是从 USB 设备启动,与其他 USB 设备的插入顺序也会导致分区识别的困难。

这个时候 UUID 就派上用场了,UUID 全称是 Universally Unique Identifier,也就是说,每个分区有一个唯一的 UUID 值,这样就不会发生分区识别混乱的问题了。

在 fstab 中用 UUID 挂载分区,看起来向这样: 

UUID=1234-5678              /mnt/usb            vfat      utf8,umask=0              0 0

在 UUID= 后面填入分区相应的 UUID 值,就可以正确挂载分区了。

那么,我们如何知道一个分区的 UUID 呢?

有 3 种方法:

1. 通过浏览 /dev/disk/by-uuid/ 下的设备文件信息。

# ls -l /dev/disk/by-uuid/
------
lrwxrwxrwx 1 root root 10 10-13 09:14 0909-090B -> ../../sdb5
lrwxrwxrwx 1 root root 10 10-13 09:13 7c627a81-7a6b-4806-987b-b5a8a0a93645 -> ../../sda4
.....

2. 通过 vol_id 命令。

# vol_id /dev/sdb5
ID_FS_USAGE=filesystem
ID_FS_TYPE=vfat
ID_FS_VERSION=FAT32
ID_FS_UUID=0909-090B
ID_FS_UUID_ENC=0909-090B
ID_FS_LABEL=SWAP
ID_FS_LABEL_ENC=SWAP
ID_FS_LABEL_SAFE=SWAP

3. 通过 blkid 命令

# blkid /dev/sdb5
/dev/sdb5: LABEL="SWAP" UUID="0909-090B" TYPE="vfat"

通过这三种方法都可以获得分区的 UUID (黄色高亮部分),UUID 依据分区不同,长度和格式都不相同。


翻译 & 修改自: http://linux.byexamples.com/archives/321/fstab-with-uuid/

探索 /proc 目录

文章来源: www.linuxgem.org

/proc 在 Linux 中是一个比较奇妙的目录,保存了当前系统所有的详细信息,包括进程、文件系统、硬件…… 而且还可以通过 /proc 来即时修改系统中的某些参数。

你可能会认为,“文件”指的就是硬盘上保存的数据,要么是文本,要么就是二进制文件。而在 Linux 的世界中,所有的东西都可以通过文件来表示和管理,哪怕是硬件设备,也可以通过 /dev 下的设备文件来操作硬件设备。

/proc 就是这样一种文件,它并不存在于硬盘上,每当系统启动的时候,操作系统自动创建 /proc 下的内容,你可以查看这些文件的列表,但是你会发现大部分文件的大小都是 0 ,这并不奇怪,因为这些文件属于“virtual files“,也就是说,当你读取这些文件的时候,系统内核为你即时生成文件中的内容。

/proc 下的信息包括了有关硬件、进程、系统的详细信息,先看看 /proc 下大致都有啥吧:

localhost ~ # ls /proc
1      143    19218  28326  28357  28406  5630  5784  5807  79   924        diskstats    interrupts  locks    pagetypeinfo  timer_list
1013   144    19223  28327  28377  28407  5713  5785  5808  814  asound     dma          iomem       meminfo  partitions    tty
11079  18990  2      28329  28382  28796  5714  5786  5809  816  buddyinfo  driver       ioports     misc     self          uptime
11086  19060  25659  28332  28385  3      5718  5787  5861  85   bus        execdomains  irq         modules  slabinfo      version
11108  19068  28300  28334  28397  3454   5750  5798  71    88   cmdline    fb           kallsyms    mounts   stat          vmstat
139    19070  28316  28338  28400  4      5781  5800  737   882  config.gz  filesystems  kcore       mtd      swaps         zoneinfo
141    19174  28317  28342  28403  5      5782  5805  74    883  cpuinfo    fs           kmsg        mtrr     sys
142    19178  28322  28347  28404  5059   5783  5806  78    893  devices    ide          loadavg     net      sysvipc

可以看到,除了一些文件之外,更多的是一堆以数字为名称的目录,每个目录代表了系统中的一个进程,目录下是有关这个进程的详细信息,这个等下我们再说。 /proc 下还有一个 self 文件,实际上是一个连接,指向了当前运行中的进程目录。

首先我们看看 /proc 目录下一些非常有用的文件,查看这些文件的内容很简单,用 cat 命令就可以了~

/proc/cpuinfo

localhost ~ # cat /proc/cpuinfo
processor    : 0
vendor_id    : GenuineIntel
cpu family    : 15
model        : 2
model name    : Intel(R) Pentium(R) 4 CPU 2.40GHz
stepping    : 7
cpu MHz        : 2394.017
cache size    : 512 KB
fdiv_bug    : no
hlt_bug        : no
f00f_bug    : no
coma_bug    : no
fpu        : yes
fpu_exception    : yes
cpuid level    : 2
wp        : yes
flags        : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe pebs bts sync_rdtsc cid xtpr
bogomips    : 4792.93
clflush size    : 64

/proc/cpuinfo 即是当前系统 cpu 的详细信息,从型号到支持的特性,如果你是多核 cpu 的话,会看到多个这样的输出。检测 cpu 的程序,也是通过 /proc/cpuinfo 来得到当前 cpu 的详细信息的。

/proc/meminfo

localhost ~ # cat /proc/meminfo
MemTotal:       514624 kB
MemFree:         10144 kB
Buffers:         20248 kB
Cached:         156248 kB
SwapCached:         60 kB
Active:         387864 kB
Inactive:        79612 kB
SwapTotal:     1052216 kB
SwapFree:      1051740 kB
Dirty:               8 kB
Writeback:           0 kB
AnonPages:      290940 kB
Mapped:          66216 kB
Slab:            25404 kB
SReclaimable:    16872 kB
SUnreclaim:       8532 kB
PageTables:       2152 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   1309528 kB
Committed_AS:   801488 kB
VmallocTotal:   515808 kB
VmallocUsed:     48176 kB
VmallocChunk:   463580 kB

/proc/meminfo 是当前系统内存的详细信息,当然,随着系统的运行,这些信息也会随时变化。像 top、free 这些可以查看当前系统内存信息的程序,就是通过读取 /proc/meminfo 来实现的。

/proc/version

localhost ~ # cat /proc/version
Linux version 2.6.24-gentoo-r2 (root@localhost) (gcc version 4.2.2 (Gentoo 4.2.2 p1.0)) #1 Wed Feb 13 22:18:22 UTC 2008

/proc/version 是当前系统的版本信息,uname 这个命令,就是通过它来得到内核版本和系统版本的。

/proc/filesystems

localhost ~ # cat /proc/filesystems
nodev    sysfs
nodev    rootfs
nodev    bdev
nodev    proc
nodev    sockfs
nodev    usbfs
nodev    pipefs
nodev    anon_inodefs
nodev    futexfs
nodev    tmpfs
nodev    inotifyfs
nodev    devpts
    reiserfs
    ext3
    ext2
nodev    ramfs
    msdos
    vfat
    iso9660
nodev    cifs
    ntfs
    udf

/proc/filesystems 为当前系统支持的文件系统列表,你可以在程序中读取这个文件,以获得当前系统对文件系统的支持信息。

上面这几个只是比较常用的,实际上 /proc 下的信息相当丰富,很多文件都可以 cat 一下看看,比如:

    * /proc/apm: APM 高级电源管理信息。
    * /proc/acpi: 目录下为 ACPI 的详细信息。 比方说, 你想知道你的笔记本电脑是否连接了电源, 你可以 cat /proc/acpi/ac_adapter/AC/state 看看结果是 "on line" 还是 "off line" 。
    * /proc/cmdline: 显示内核的启动参数,一般就是你 grub 中传入内核的那些参数,比如我的就是: root=/dev/sda9 video=uvesafb:1680x1050-32,mtrr:3,ywrap
    * /proc/loadav: 显示系统的负载,w、top 这类程序也是从此得到系统负载信息。
    * /proc/uptime: 系统自启动来所经历的秒数,uptime 程序就是从此计算出系统启动后经历的时间的。
    * /proc/devices: 系统中所有可用的字符和块设备。
    * /proc/ioports: IO 端口信息。
    * /proc/dma: 当前可用的 DMA 通道。
    * /proc/mounts: 系统当前的挂载信息。

除此之外,还有一些文件和硬件相关,比如 /proc/interrupts 为终端信息,/proc/irq 为 IRQ 信息,还有 /proc/pci、/proc/bus 等等。

现在我们来看看开始提到的那些数字目录,也就是和进程相关的目录。

如前面所说,每个数字目录都代表了一个正在运行的进程,目录的数字名就是进程的 ID,每当一个新进程启动,一个新的目录就会被创建,同理进程结束的时候,相应的目录也会消失。

让我们看看进程目录下面都有啥:

localhost / # ls /proc/11108
auxv        cmdline          cwd      exe  fdinfo  maps  mounts      oom_adj    root   stat   status  wchan
clear_refs  coredump_filter  environ  fd   limits  mem   mountstats  oom_score  smaps  statm  task

随便挑选了一个名称为 11108 的目录,在我的机子上对应的进程是 firefox-bin,让我们看看目录下这些文件都是啥:

    * cmdline: 启动进程的命令和参数。
    * cwd: 指向进程当前目录的一个连接。
    * environ: 进程所有的环境变量。
    * fd: 进程所有打开的文件描述符,目录下是一个个以数字为名称的连接,指向了进程当前正在使用的文件。
    * maps, statm, mem: 进程的内存信息。
    * stat, status: 进程的状态信息,比如查看 /proc/status 中是否含有 “Zombie”字样,来查看僵尸进程。

/proc/sys

/proc/sys 目录下不仅提供了系统某些设置信息,你还可以修改这些文件来在运行中改变系统的参数,比如,你想让别人 ping 不到你,只要:

# echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all

这样就可以让系统忽略所有的 ICMP 回应,别人就 ping 不到你了。

/proc/sys 下的可配置的选项很多,主要有 6 类: debug、dev、fs、kernel、net、vm,只要文件属性是可读写的,一般都对应了系统某个可以修改的参数。

不过系统重启之后参数就恢复默认值了,其实有专门的工具来修改这些参数,那就是 sysctl 和 /etc/sysctl.conf 这个配置文件,不过这不是本文的内容,感兴趣的就去搜一下吧~

如上所述,/proc 是一个强大的特殊目录,其中的文件提供了非常详细的系统信息,很多常用的程序就是从此得到系统各个方面的信息的,在你写的程序和脚本中,也可以通过 /proc 方便的获得一些系统参数,甚至修改系统的某些参数,本文只是 /proc 的一个简要的介绍,更详细的内容留给各位自己去探索吧~

watch -- 监测命令的运行结果

文章来源: www.linuxgem.org

watch 是一个非常实用的命令,基本所有的 Linux 发行版都带有这个小工具,如同名字一样,watch 可以帮你监测一个命令的运行结果,省得你一遍遍的手动运行。

举例来说,Linux 系统有一个基础命令 w,可以显示当前的 uptime、负载还有登录的用户,非常方便,但是如果我想监测这些数据,看看有没有新用户登入,看看某段的时间的负载是不是太大之类的,就得手动一遍遍的运行这个命令,然后查看结果,虽然命令只有一个字母,但是还是很郁闷……

watch 就是干这个用的,直接在 watch 后面接你想运行的命令,watch 就会帮你重复运行,并把每次的结果都更新在屏幕上~

要想监测 w 命令的运行结果,只要 watch w 就可以了:

默认 watch 会以 2s 的间隔重复运行命令,你也可以用 -n 参数指定时间间隔~

还有一个实用的参数是 -d,这样 watch 会帮你高亮显示变化的区域,这样更加一目了然了~

Ctrl c 就可以退出~

你可以拿他来监测你想要的一切命令的结果变化,比如 tail 一个 log 文件,ls 监测某个文件的大小变化,看你的想象力了~

如果你的发行版中不幸没有这个命令,可以到这里下载安装,watch 属于 procps 这个软件包。

 

制作LFS过程中各个阶段恢复工作状态的方法

文章来源: http://www.linuxsir.org/bbs/showthread.php?t=242880

前提:
  对于做过一两次LFS的朋友,想必对LFS的漫长制作时间印象深刻,特别是对机器不太好的朋友,有时候LFS的制作时间真是“可怕”,有时候不得以必须关机然后重新启动并恢复到工作状态,但对一些不太清楚LFS的工作原理的朋友,可能一时无法正确的恢复到工作状态,因此为了能成功的完成LFS,有的会开个一两天的机器不关,本人特别针对这个问题写了一些自己的经验,以下的过程全部经过测试,应该是正确的,希望能给还在LFS制作中的朋友减轻一些“痛苦”。
为了说明方便,例子采用VMWare5.0的环境下开始的,但也同样适合使用真实机器的情况,只是用真实的机器需要在相应的磁盘设备名上修改成实际的设备名。(用VMWare只是为了说明方便,VMware本身就具有暂停的功能,所以不必计较这个问题)
文章使用VMWare5.0虚拟的SCSI设备,并使用sda设备名,sda1用于swap,而sda2用于目标系统的根目录。

以下是按照LFS6.1.1-3里面的章节数写的,如果你使用的LFS-Book与下面的章节数有出入,以章节数后面的标题为准。

开始~4.4. Setting Up the Environment
从头开始好了,没什么好可惜的。

4.5. About SBUs~5.33. Stripping
从现在开始一直到第五章结束,也就是完成Stripping中间的步骤中如果重新启动的恢复步骤:
1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/sda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/sda1
4.建立工具链的链接
ln -sv $LFS/tools /
5.创建lfs用户
groupadd lfs
useradd -s /bin/bash -g lfs -m -k /dev/null lfs
passwd lfs
chown -v lfs $LFS/tools
chown -v lfs $LFS/sources
su - lfs
6.建立lfs用户的环境
cat > ~/.bash_profile << "EOF"
exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash
EOF

cat > ~/.bashrc << "EOF"
set +h
umask 022
LFS=/mnt/lfs
LC_ALL=POSIX
PATH=/tools/bin:/bin:/usr/bin
export LFS LC_ALL PATH
EOF

source ~/.bash_profile
7.检查一下
export命令查看输出,应该是
declare -x HOME="/home/lfs"
declare -x LC_ALL="POSIX"
declare -x LFS="/mnt/lfs"
declare -x OLDPWD
declare -x PATH="/tools/bin:/bin:/usr/bin"
declare -x PS1="\\u:\\w\\\$ "
declare -x PWD="/home/lfs"
declare -x SHLVL="1"
declare -x TERM="linux"
基本上就恢复工作状态了。

6.1. Introduction
这个时候也许你想睡觉关机了,那么重新开机后回到工作状态的步骤是:
1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/sda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/sda1
相关知识点:
这时候已经制作好了工具链,因此可以不需要建立根目录下的tools链接了。

6.2. Mounting Virtual Kernel File Systems~6.8. Populating /dev
这个时候如果你关机或重新启动,那么重新开机后回到工作状态的步骤是:
1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/sda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/sda1
4.加载必要的文件系统
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
5.Chroot到目标系统下
chroot "$LFS" /tools/bin/env -i \
HOME=/root TERM="$TERM" PS1='\u:\w\$ ' \
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin \
/tools/bin/bash --login +h

6.9. Linux-Libc-Headers-2.6.11.2~6.37. Bash-3.0
从现在开始一直到第六章的File-4.13之前,也就是Bash-3.0结束后,这个阶段如果你关机或重新启动,那么重新开机后回到工作状态的步骤是:
1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/sda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/sda1
4.加载必要的文件系统
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
5.Chroot到目标系统下
chroot "$LFS" /tools/bin/env -i \
HOME=/root TERM="$TERM" PS1='\u:\w\$ ' \
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin \
/tools/bin/bash --login +h
6.创建/dev下的设备文件
mount -nvt tmpfs none /dev
mknod -m 622 /dev/console c 5 1
mknod -m 666 /dev/null c 1 3
mknod -m 666 /dev/zero c 1 5
mknod -m 666 /dev/ptmx c 5 2
mknod -m 666 /dev/tty c 5 0
mknod -m 444 /dev/random c 1 8
mknod -m 444 /dev/urandom c 1 9
chown -v root:tty /dev/{console,ptmx,tty}
ln -sv /proc/self/fd /dev/fd
ln -sv /proc/self/fd/0 /dev/stdin
ln -sv /proc/self/fd/1 /dev/stdout
ln -sv /proc/self/fd/2 /dev/stderr
ln -sv /proc/kcore /dev/core
mkdir -v /dev/pts
mkdir -v /dev/shm
mount -vt devpts -o gid=4,mode=620 none /dev/pts
mount -vt tmpfs none /dev/shm
6.进入编译目录
cd /sources

6.38. File-4.13~6.58. Udev-056
从现在开始一直到第六章的Udev-056完成之前,这个阶段如果你关机或重新启动,那么重新开机后回到工作状态的步骤是:
1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/sda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/sda1
4.加载必要的文件系统
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
5.Chroot到目标系统下
chroot "$LFS" /tools/bin/env -i \
HOME=/root TERM="$TERM" PS1='\u:\w\$ ' \
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin \
/bin/bash --login +h
6.创建/dev下的设备文件
mount -nvt tmpfs none /dev
mknod -m 622 /dev/console c 5 1
mknod -m 666 /dev/null c 1 3
mknod -m 666 /dev/zero c 1 5
mknod -m 666 /dev/ptmx c 5 2
mknod -m 666 /dev/tty c 5 0
mknod -m 444 /dev/random c 1 8
mknod -m 444 /dev/urandom c 1 9
chown -v root:tty /dev/{console,ptmx,tty}
ln -sv /proc/self/fd /dev/fd
ln -sv /proc/self/fd/0 /dev/stdin
ln -sv /proc/self/fd/1 /dev/stdout
ln -sv /proc/self/fd/2 /dev/stderr
ln -sv /proc/kcore /dev/core
mkdir -v /dev/pts
mkdir -v /dev/shm
mount -vt devpts -o gid=4,mode=620 none /dev/pts
mount -vt tmpfs none /dev/shm
6.进入编译目录
cd /sources

6.59. Util-linux-2.12q~6.60. About Debugging Symbols
从现在开始一直到第六章的Stripping Again之前,这个阶段如果你关机或重新启动,那么重新开机后回到工作状态的步骤是:
1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/sda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/sda1
4.加载必要的文件系统
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
5.Chroot到目标系统下
chroot "$LFS" /tools/bin/env -i \
HOME=/root TERM="$TERM" PS1='\u:\w\$ ' \
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin \
/bin/bash --login +h
6.创建/dev下的设备文件
mount -nvt tmpfs none /dev
/sbin/udevstart
mkdir -v /dev/pts
mkdir -v /dev/shm
mount -vt devpts -o gid=4,mode=620 none /dev/pts
mount -vt tmpfs none /dev/shm
6.进入编译目录
cd /sources

6.61. Stripping Again
如果现在重新启动,那么重新开机后回到工作状态的步骤是:
1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/sda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/sda1
4.加载必要的文件系统
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
5.Chroot到目标系统下
chroot $LFS /tools/bin/env -i \
HOME=/root TERM=$TERM PS1='\u:\w\$ ' \
PATH=/bin:/usr/bin:/sbin:/usr/sbin \
/tools/bin/bash --login
6.创建/dev下的设备文件
mount -nvt tmpfs none /dev
/sbin/udevstart
mkdir -v /dev/pts
mkdir -v /dev/shm
mount -vt devpts -o gid=4,mode=620 none /dev/pts
mount -vt tmpfs none /dev/shm
6.进入编译目录
cd /sources

6.62. Cleaning Up~结束
从现在开始一直到制作结束,重新开机后回到工作状态的步骤是:
1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/sda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/sda1
4.加载必要的文件系统
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys
5.Chroot到目标系统下
chroot "$LFS" /usr/bin/env -i \
HOME=/root TERM="$TERM" PS1='\u:\w\$ ' \
PATH=/bin:/usr/bin:/sbin:/usr/sbin \
/bin/bash --login
6.创建/dev下的设备文件
mount -nvt tmpfs none /dev
/sbin/udevstart
mkdir -v /dev/pts
mkdir -v /dev/shm
mount -vt devpts -o gid=4,mode=620 none /dev/pts
mount -vt tmpfs none /dev/shm
6.进入编译目录
cd /sources
 

VMware Workstation + LFS LiveCD + SSH

终于可以通过SSH来控制虚拟机中的LFS LiveCD Operating System了, 嘻嘻。

简述过程如下:

我的Host OS是ubuntu 8.10

1. WMware Workstation的安装应该不是问题,而且至少有一个月的试用期。

2. 下载LFS LiveCD镜像,我是从官网上下载的,下了好久。

3. 从WMware Workstation中通过镜像文件安装OS, 虚拟机的配置等可以参考:
    http://www.linuxsir.org/bbs/showthread.php?t=244052
   

    不过我在安装过程中出现键盘无法使用的问题,好在已有前人将该问题解决:
    在~/.vmware文件夹中添加config文件,内容添加:
    xkeymap.nokeycodeMap=true
    另外,不熟悉虚拟机的人可能需要注意键盘无法使用的另一个原因可能是当前active的不是客户端的操作系统,只需在客户端操作系统的窗口点击鼠标即能解决,按    Ctrl+Alt组合键则又回到主操作系统。

4. 看网上文章说,VMware Workstation下的LFS LiveCD无法安装VMware Tools, 这将导致在虚拟机中的操作非常不便,解决的方法就是通过SSH来从主操作系统连接客户端操作系统,具体方法如下:

a. 设置客户端操作系统中root的密码
b. 修改/etc/ssh/sshd_config文件, 去掉Port 22前的注释 #
c. /etc/rc.d/init.d/sshd restart  重新启动ssh服务
d. 从主操作系统中使用ssh命令连接

另外,可以使用net-setup命令来设置客户端操作系统的网络,一般LFS会自动配置好网络(我在开启虚拟机时使用的是NAT), 这样就可以通过ifconfig来查看地址.

ubuntu 安装VMware Workstation 6.5.1

在初学Linux From Scratch的过程中,无意中接触到了虚拟机,所以就去官网下载了最新的VMware Workstation.

安装过程非常简单,只需下载.bundle格式的文件,然后:
chmod a+x vmware*****.bundle
./vmware*****.bundle

因为VMware只提供30天的试用期,感觉不爽,所以就google 疯狂搜索注册码,结果终于找到一个可以用的嘻嘻:

QAXU0-TDFA3-Q2HFA-4M8N2

理解Linux的守护进程

Linux服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户。提供这些服务的程序是由 运行在后台的守护进程(daemons)来执行的。守护进程是生存期长的一种进程。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事 件。他们常常在系统引导装入时启动,在系统关闭时终止。linux系统有很多守护进程,大多数服务器都是用守护进程实现的。同时,守护进程完成许多系统任 务,比如,作业规划进程crond、打印进程lqd等。有些书籍和资料也把守护进程称作:“服务”。选择运行哪些守护进程,要根据具体需求决定。

一、Linux守护进程简介


1.alsasound :Alsa声卡驱动守护程序。Alsa声卡驱动程序本来是为了 一种声卡Gravis UltraSound(GUS)而写的,该程序被证 明很优秀,于是作者就开始为一般的声卡写 驱动程序。 Alsa和OSS/Free 及OSS/Linux兼容,但是有自己的接 口,甚至比OSS优秀。
2.acpid:acpid(Advanced Configuration and Power Interface)是为替代传统的APM电源管理标准而推出的新型电源管理标准。通常笔记本电脑需要启动电源进行管理。
3.atalk:AppleTalk网络守护进程。注意不要在后台运行该程序,该程序的数据结构必须在运行其他进程前先花一定时间初始化。
4.amd: 自动安装NFS守护进程。
5.anacron:一个自动化运行任务守护进程。Red Hat Linux 随带四个自动化任务的工具:cron、 anacron、at、和 batc。当你的Linux服务器并不是全天运行,这个anacron就可以帮你执行在"crontab"设定的时间内没有执行的工作。
6.apmd:apmd(Advanced Power Management)是高级电源管理。传统的电源管理标准,对于笔记本电脑比较有用,可以了解系统的电池电量信息。并将相关信息通过syslogd 写入日志。也可以用来在电源不足时关机。
7.arptables_jf :为arptables网络的用户控制过滤的守护进程。
8.arpwatch: 记录日志并构建一个在LAN接口上看到的以太网地址和IP地址对数据库 。
atd:at和batch命令守护进程,用户用at命令调度的任务。Batch用于在系统负荷比较低时  运行批处理任务。
9.autofs:自动安装管理进程automount,与NFS相关,依赖于NIS服务器。
10.bootparamd:引导参数服务器,为LAN上的无盘工作站提供引导所需的相关信息。
11.bluetooch:蓝牙服务器守护进程。
12.crond :cron是Unix下的一个传统程序,该程序周期地运行用户 调度的任务。比起传统的Unix版本,Linux版本添加了不少属性,而且更安全,配置更简单。类似计划任务。
13.chargen:使用tcp协议的chargen server,chargen(Character Generator  Protocol)是一种网络服务,主要功能是提供类似远程打字的功能。
14.chargen-udp:使用UDP协议的chargen server。
15.cpuspeed:监测系统空闲百分比,降低或加快CPU时钟速度和电压从而在系统空闲时将能源消耗降为最小,而在系统繁忙时最大化加快系统执行速度。
16.dhcpd:动态主机控制协议(Dynamic Host Control Protocol)的服务守护进程。
17.cups: cups(Common UNIX Printing System)是通用UNIX打印守护进程,为Linux提供第三代打印功能。
18.cups-config-daemons:cups打印系统切换守护进程。
19.cups-lpd:cups行打印守护进程。
20.daytime:使用TCP 协议的Daytime守护进程,该协议为客户机实现从远程服务器获取日期 和时间的功能。预设端口:13。
21.daytime-udp:使用UDP 协议的Daytime守护进程。
22.dc_server:使用SSL安全套接字的代理服务器守护进程。
23.dc_client:使用SSL安全套接字的客户端守护进程。
24.diskdump:服务器磁盘备份守护进程。
25.echo:服务器回显客户数据服务守护进程。
26.echo-udp:使用UDP协议的服务器回显客户数据服务守护进程。
27.eklogin:接受rlogin会话鉴证和用kerberos5加密的一种服务的守护进程。
28.gated :网关路由守护进程。它支持各种路由协议,包括RIP版本1和2、DCN HELLO协议、 OSPF版本2以及EGP版本2到4。
29.gpm:gpm(General Purpose Mouse Daemon )守护进程为文本模式下的Linux程序如mc(Midnight Commander)提供了鼠标的支持。它也支持控制台下鼠标 的拷贝,粘贴操作以及弹出式菜单。
30.gssftp: 使用kerberos 5认证的ftp守护进程
31.httpd:Web服务器Apache守护进程,可用来提供HTML文件以 及CGI动态内容服务。
32.inetd :因特网操作守护程序。监控网络对各种它管理的服务的需求,并在必要的时候启动相应的服务程序。在Redhat 和Mandrake linux中被xinetd代替。Debian, Slackware, SuSE仍然使用。
33.innd:Usenet新闻服务器守护进程。
34.iiim:中文输入法服务器守护进程。
35.iptables:iptables防火墙守护进程。
36.irda:红外端口守护进程。
37.isdn:isdn启动和中止服务守护进程。
38.krb5-telnet:使用kerberos 5认证的telnet守护进程。
39.klogin:远程登陆守护进程。
40.keytable: 该进程的功能是转载在/etc/sysconfig/keyboards里定义的键盘映射表,该表可以通过kbdconfig工具进行选择。您应该使该程序处于激活状态。
41.irqbalance:对多个系统处理器环境下的系统中断请求进行负载平衡的守护程序。如果你只安装了一个CPU,就不需要加载这个守护程序。
42.kshell :kshell守护进程。
43.kudzu: 硬件自动检测程序,会自动检测硬件是否发生变动,并相应进行硬件的添加、删除工作。当系统启动时,kudzu会对当前的硬件进行检测,并且和存储在       /etc/sysconfig/hwconf中的硬件信息进行对照,如果某个硬件从系统中被添加或者删除时,那么kudzu就会察觉到,并且通知用户是否 进行相关配置,然后修改etc/sysconfig/hwconf,使硬件资料与系统保持同步。如果/etc/sysconfig/hwconf这个文件 不存在,那么kudzu将会从/etc/modprobe.conf,/etc/sysconfig/network-scripts/和 etc/X11/XF86Config中探测已经存在的硬件。如果你不打算增加新硬件,那么就可以关闭这个启动服务,以加快系统启动时间。
44.ldap:ldap(Lightweight Directory Access Protocol)目录访问协议服务器守护进程。
45.lm_seroems:检测主板工作情况守护进程。
46.lpd :lpd是老式打印守护程序,负责将lpr等程序提交给打印 作业。
47.mdmonitor:RAID相关设备的守护程序。
48.messagebus:D-BUS是一个库,为两个或两个以上的应用程序提供一对一的通讯。 dbus-daemon-1是一个应用程序,它使用这个库来实现messagebus守护程序。多个应用程序通过连接messagebus守护程序可以实现与其他程序交换信息。
49.microcode_ctl:可编码以及发送新的微代码到内核以更新Intel IA32系列处理器守护进程。
50.mysqld: 一个快速高效可靠的轻型SQL数据库引擎守护进程。
51.named:DNS(BIND)服务器守护进程。
52.netplugd:netplugd(network cable hotplug management daemon)守护程序,用于监控一个或多个网络接口的状态,当某些事件触发时运行一个外部脚本程序。
53.netdump:远程网络备份服务器守护进程。
54.netfs:Network Filesystem Mounter,该进程安装和卸载NFS、SAMBA和NCP网络文件系统。
55.nfs:网络文件系统守护进程。
56.nfslock:NFS是一个流行的通过TCP/IP网络共享文件的协议,此守护进程提供了NFS文件锁定功能。
57.ntpd:Network time Protocol daemon(网络时间校正协议)。ntpd是用来使系统和一个精确的时间源保持时间同步的协议守护进程。
58.network:激活/关闭启动时的各个网络接口守护进程。
59.psacct:该守护进程包括几个工具用来监控进程活动的工具,包括ac,lastcomm, accton 和sa。
60.pcmcia:主要用于支持笔记本电脑接口守护进程。
61.portmap:该守护进程用来支持RPC连接,RPC被用于NFS以及NIS 等服务。
62.postgresql: PostgreSQL 关系数据库引擎。
63.proftpd: proftpd 是Unix下的一个配置灵活的ftp服务器的守护程序。
64.pppoe:ADSL连接守护进程。
65.random :保存和恢复系统的高质量随机数生成器,这些随机数是系 统一些随机行为提供的。
66.rawdevices:在使用集群文件系统时用于加载raw设备的守护进程。
67.readahead、readahead_early:readahead和readahead_early是在Fedora core 2中最新推出的两个后台运行的守护程序。其作用是在启动系统期间,将启动系统所要用到的文件首先读取到内存中,然后在内存中进行执行,以加快系统的启动速度。
68.rhnsd:Red Hat 网络服务守护进程。通知官方的安全信息以及为系统打补丁。
69.routed :该守护程序支持RIP协议的自动IP路由表维护。RIP主要 使用在小型网络上,大一点的网络就需要复杂一点的协议。
70.rsync:remote sync远程数据备份守护进程。 
71.rsh :远程主机上启动一个shell,并执行用户命令。
72.rwhod: 允许远程用户获得运行rwho守护程序的机器上所有已登录用户的列表。
73.rstatd:一个为LAN上的其它机器收集和提供系统信息的守候进程。
74.ruserd:远程用户定位服务,这是一个基于RPC的服务,它提供关于当前记录到LAN上一个机器日志中的用户信息
75.rwalld:激活rpc.rwall服务进程,这是一项基于RPC的服务,允许用户给每个注册到LAN机器上的其他终端写消息 。
76.rwhod:激活rwhod服务进程,它支持LAN的rwho和ruptime服务。
77.saslauthd: 使用SASL的认证守护进程。
78.sendmail:邮件服务器sendmail守护进程。
79.smb:Samba文件共享/打印服务守护进程。
80.snmpd:本地简单网络管理守护进程。
81.squid:代理服务器squid守护进程。
82.sshd:OpenSSH服务器守护进程。Secure Shell Protocol可以实现安全地远程管理主机。
83.smartd:Self Monitor Analysis and Reporting Technology System,监控你的硬盘是否出现故障。
84.syslog:一个让系统引导时起动syslog和klogd系统日志守候进程的脚本。
85.time :该守护进程从远程主机获取时间和日期,采用TCP协议。
86.time-udp: 该守护进程从远程主机获取时间和日期,采用UDP协议。
87.tux:在Linux内核中运行apache服务器的守护进程。
88.vsftpd:vsftpd服务器的守护进程。
89.vncserver: VNC (Virtual Network Computing,虚拟网络计算),它提供了一种在本地系统上显示远程计算机整个"桌面"的轻量型协议。
90.xfs:X Window字型服务器守护进程,为本地和远程X服务器提供字型集。
91.xinetd:支持多种网络服务的核心守护进程。
92.ypbind:为NIS(网络信息系统)客户机激活ypbind服务进程 。
93.yppasswdd:NIS口令服务器守护进程。
94.ypserv:NIS主服务器守护进程。
95.yum:RPM操作系统自动升级和软件包管理守护进程。

二、守护进程工作原理和方式


 在Client/Server模式下。服务器监听 (Listen)在一个特定的端口上等待客户连接。连接成功后服务器和客户端通过端口进行数据通信。守护进程的工作就是打开一个端口,并且等待 (Listen)进入连接。如果客户端产生一个连接请求,守护进程就创建(Fork)一个子服务器响应这个连接,而主服务器继续监听其他的服务请求。

守护进程工作方式:
(1)运行独立的守护进程
  独立运行的守护进程由init脚本负责管理,所有独立运行的守护进程的脚本在/etc/rc.d/init.d/目录下。系统服务都是独立运行的守护进程 包括:syslogd和cron等。运行独立的守护进程工作方式称作:stand-alone。它Unix传统的C/S模式的访问模式。服务器监听 (Listen)在一个特点的端口上等待客户端的联机。如果客户端产生一个连接请求,守护进程就创建(Fork)一个子服务器响应这个连接,而主服务器继 续监听。以保持多个子服务器池等待下一个客户端请求。stand-alone模式工作原理见图1。


 
                图1 stand-alone工作模式
工 作在stand-alone模式下的网络服务有route、gated。另外是大家最熟悉是Web服务器:Apache和邮件服务器Sendmail、域 名服务器Bind。因为这些负载很大服务器上,预先创子服务器,可以通过客户的服务速度。在Linux系统中通过stand-alone工作模式启动的服 务由/etc/rc.d/下面对应的运行级别当中的符号链接启动。

(2)xinetd模式
从守护进程的概念可以看出,对于系统所要通过的每一种 服务,都必须运行一个监听某个端口连接所发生的守护进程,这通常意味着资源浪费。为了解决这个问题,Linux引进了“网络守护进程服务程序”的概念。 Redhat Linux 9.0使用的网络守护进程是xinted(eXtended InterNET daemon)。和stand-alone模式相比xinted模式也称 Internet Super-Server(超级服务器)。xinetd能够同时监听多个指定的端口,在接受用户请求时,他能够根据用户请求的端口不同,启动不同的网络服 务进程来处理这些用户请求。可以把xinetd看做一个管理启动服务的管理服务器,它决定把一个客户请求交给那个程序处理,然后启动相应的守护进程。 xinetd模式工作原理见图3。


                 图3  xinetd工作模式

    和stand-alone工作模式相比,系统不想要每一个网络服务进程都监听其服务端口。运行单个xinetd就可以同时监听所有服务端口,这样就降低了 系统开销,保护系统资源。但是对于访问量大、经常出现并发访问时,xinetd想要频繁启动对应的网络服务进程,反而会导致系统性能下降。察看系统为 Linux服务提供那种模式方法在Linux命令行可以使用pstree命令可以看到两种不同方式启动的网络服务。一般来说系统一些负载高的服务: sendmail、Apache服务是单独启动的。而其他服务类型都可以使用xinetd超级服务器管理。查看目前运行的守护进程可以使用命令: “pstree”

三、守护进程管理工具


Linux提供了三种不同的守护进程管理工具:redhat-config-services、ntsysv、chkconfig,可以根据具体需要灵活运用。
(1) redhat-config-services
  redhat-config-services是一个一个图形化应用程序,它显示了每项服务的描述,以及每项服务是否在引导时启动(运行级别3、4、 5),并允许你启动、停止、或重新启动/etc/rc.d/init.d 中的哪些 SysV 服务,哪些 xinetd 服务。要从桌面启动服务配置工具,点击面板上的「主菜单」 => 「系统设置」 => 「服务器设置」 => 「服务」,或在 shell 提示下,键入命令:“redhat-config-services” (见图4)。 


  
    图4 redhat-config-services配置工具
  redhat-config-services列出了 /etc/rc.d/init.d 中的服务和由 xinetd 控制的服务。点击左侧列表中的服务名来显示该服务的简短描述以及它的服务状态。如果这个服务不是 xinetd 服务,状态窗口会显示该服务目前是否在运行。如果该服务被 xinetd 所控制,状态窗口会显示「xinetd 服务」这个短语。要立即启动、停止、或重新启动某项服务,从列表中选择该项服务,然后点击工具栏上的相应按钮(或从「行动」拉下菜单中选择行动)。如果该 服务是一个 xinetd 服务,行动按钮会被禁用,因为它们不能被单个地启动或停止。 如果你通过选择或取消选择服务名旁的复选箱来启用或禁用了 xinetd 服务,你必须从拉下菜单中选择「文件」 => 「保存改变」来重新启动 xinetd,并立即启用或禁用你所改变的 xinetd 服务。xinetd 还被配置成自动记忆设置。你可以同时启用或禁用多个 xinetd 服务,在结束后再保存改变。
(2)ntsysv
 ntsysv 工具为激活或停运服务提供了简单的界面。你可以使用 ntsysv 来启动或关闭由 xinetd 管理的服务。你还可以使用 ntsysv 来配置运行级别。按照默认设置,只有当前运行级别会被配置。要配置不同的运行级别,使用 --level 选项来指定一个或多个运行级别。譬如,命令 ntsysv --level 345 配置运行级别3、4、和5。 ntsysv 的工作界面见图1。使用上下箭头来上下查看列表。使用空格键来选择或取消选择服务,或用来“按”「确定」和「取消」按钮。要在服务列表和「确定」、「取 消」按钮中切换,使用 [Tab]键。* 标明某服务被设为启动。[F1] 键会弹出每项服务的简短描述。
(3)chkconfig
 chkconfig 命令也可以用来激活和解除服务。chkconfig --list 命令显示系统服务列表,以及这些服务在运行级别0到6中已被启动(on)还是停止(off)。chkconfig 还能用来设置某一服务在某一指定的运行级别内被启动还是被停运。譬如,要在运行级别3、4、5中停运 nfs 服务,使用下面的命令:
chkconfig --level 345 nfs off
 

四、合理选择守护进程规避安全隐患


 运行不必要或有漏洞的守护进程会给操作系统带来安全和性能上的影响。对于系统安全来说,如果操作系统中的任何一个漏洞,都可能 使整个系统受到攻击。所以,增加系统安全的最佳办法就是尽量监视系统的功能。文章开始介绍了重要的守护进程,其中“crond、syslog、 keytable、xinetd、kudzu、iptables”等是需要运行的,echo、echo-udp、daytime、daytime- udp、chargen、chargen-udp主要是做调试用,普通用户基本用不到,可以关闭。
 r字开头的守护进程:rsh、 rstatd、rsync、rusersd、rwalld这些命令都是Berkley远程命令,因为都以字母r开头,故称r*命令。主要使用来使一台计算 机上的某个用户以相同的帐户远程执行另一台计算机的一个程序。但是,r命令已经被证实存在安全风险。对于确实需要的守护进程,应该尽量选用最新的版本程 序,并增加其安全防范。 
 另外我们还要合理选择守护进程例如innd是运行新闻组服务的进程,如果用户不做Usenet服务器,应该关掉。
 
总结:
 基于开放源代码的Linux给用户提供了这样一个平台:可以根据自己的软、硬件环境,定制自己的Linux守护进程。因此,根据每个用户不同的应用范围定制应用环境,可以将Linux系统的安全和性能提升到新的高度。

 

 原文地址 http://www.pcvz.com/server/ServerYJ/server_94202.html

GCC 详解

文章来源: www.cublog.cn/u/13991/showart.php

 

The History of GCC


1984年,Richard Stallman发起了自由软件运动,GNU (Gnu's Not Unix)项目应运而生,3年后,最初版的GCC横空出世,成为第一款可移植、可优化、支持ANSI C的开源C编译器。
GCC最初的全名是GNU C Compiler,之后,随着GCC支持的语言越来越多,它的名称变成了GNU Compiler Collection。
这里介绍的gcc是GCC的前端,C编译器.


警告信息


    -Wall : 显示所有常用的编译警告信息。
    -W    : 显示更多的常用编译警告,如:变量未使用、一些逻辑错误。

    -Wconversion : 警告隐式类型转换。
    -Wshadow : 警告影子变量(在代码块中再次声明已声明的变量)
    -Wcast-qual :警告指针修改了变量的修饰符。如:指针修改const变量。
    -Wwrite-strings : 警告修改const字符串。
    -Wtraditional : 警告ANSI编译器与传统C编译器有不同的解释。
    -Werror : 即使只有警告信息,也不编译。(gcc默认:若只有警告信息,则进行编译,若有错误信息,则不编译)


C语言标准


 

你可以在gcc的命令行中通过指定选项来选择相应的C语言标准: 从传统c到最新的GNU扩展C. 默认情况下, gcc使用最新的GNU C扩展.

    -ansi : 关闭GNU扩展中与ANSI C相抵触的部分。
    -pedantic          : 关闭所有的GNU扩展。
    -std=c89           : 遵循C89标准
    -std=c99           : 遵循C99标准
    -std=traditional : 使用原始C
注意:后4个选项可以与-ansi结合使用,也可以单独使用。

可在gcc中使用大量GNU C扩展.

生成特定格式的文件


以hello.c为例子,可以设置选项生成hello.i, hello.s, hello.o以及最终的hello文件:

    hello.c : 最初的源代码文件;
    hello.i : 经过编译预处理的源代码;
    hello.s : 汇编处理后的汇编代码;
    hello.o : 编译后的目标文件,即含有最终编译出的机器码,但它里面所引用的其他文件中函数的内存位置尚未定义。
    hello / a.out : 最终的可执行文件

    (还有.a(静态库文件), .so(动态库文件), .s(汇编源文件)留待以后讨论)

如果你不通过-o指定生成可执行文件名,那么会默认生成a.out. 不指定生成文件名肯能覆盖你上次生成的a.out.

e.g.
$ gcc hello.c
在不给gcc传递任何参数的情况下, gcc执行默认的操作: 将源文件编译为目标文件--> 将目标文件连接为可执行文件(名为a.out) --> 删除目标文件.

-c生成.o文件时,默认生成与源代码的主干同名的.o文件。比如对应hello.c生成hello.o. 但也可在生成目标文件时指定目标文件名(注意同时要给出.o后缀): $ gcc -c -o demo.o demo.c

    $ gcc -Wall -c hello.c              : 生成hello.o
    $ gcc -Wall -c -save-temps hello.c  : 生成hello.i, hello.s, hello.o
    注意-Wall 选项的使用场合:仅在涉及到编译(即会生成.o文件时,用-Wall)  

多文件编译、连接


如果原文件分布于多个文件中:file1.c, file2,c
    $ gcc -Wall file1.c file2.c -o name

若对其中一个文件作了修改,则可只重新编译该文件,再连接所有文件:
    $ gcc -Wall -c file2.c
    $ gcc file1.c file2.o -c name

注意:若编译器在命令行中从左向右顺序读取.o文件,则它们的出现顺序有限制:含有某函数定义的文件必须出现在含有调用该函数的文件之后。好在GCC无此限制。

编译预处理


以上述的hello.c为例, 要对它进行编译预备处理, 有两种方法: 在gcc中指定-E选项, 或直接调用cpp.gcc的编译预处理命令程序为cpp,比较新版本的gcc已经将cpp集成了,但仍提供了cpp命令. 可以直接调用cpp命令, 也可以在gcc中指定-E选项指定它只进行编译预处理.

 

$

gcc -E hello.c                            ==  $ cpp hello.c

上述命令马上将预处理结果显示出来. 不利于观看. 可采用-c将预处理结果保存:

 

$

gcc -E -c hello.i hello.c              ==  $ cpp -o hello.i hello.c

注意, -c指定名称要给出".i"后缀.

 

另外, gcc针对编译预处理提供了一些选项:

 

(1) 除了直接在源代码中用 #define NAME来定义宏外,gcc可在命令行中定义宏:-DNAME(其中NAME为宏名),  也可对宏赋值: -DNAME=value 注意等号两边不能有空格! 由于宏扩展只是一个替换过程,也可以将value换成表达式,但要在两边加上双括号: -DNAME="statement"

 

e.g. $

gcc -Wall -DVALUE="2+2" tmp.c -o tmp

如果不显示地赋值,如上例子,只给出:-DVALUE,gcc将使用默认值:1.

 

(2) 除了用户定义的宏外, 有一些宏是编译器自动定义的,它们以__开头,运行: $

cpp -dM /dev/null

, 可以看到这些宏. 注意, 其中含有不以__开头的非ANSI宏,它们可以通过-ansi选项被禁止。

 

 


查看宏扩展

1, 运行 $

gcc -E test.c

,gcc对test.c进行编译预处理,并立马显示结果. (不执行编译) 2, 运行 $

gcc -c -save-temps test.c

,不光产生test.o,还产生test.i, test.s,前者是编译预处理结果, 后者是汇编结果.

 

   


利用Emacs查看编译预处理结果

针对含有编译预处理命令的代码,可以利用emacs方便地查看预处理结果,而不需执行编译,更为方便的是,可以只选取一段代码,而非整个文件:

 

1,选择想要查看的代码

 

2,C-c C-e (M-x c-macro-expand)

 

这样,就自动在一个名为"Macroexpansion"的buffer中显示pre-processed结果.



生成汇编代码


使用"-S"选项指定gcc生成以".s"为后缀的汇编代码:

 

$

gcc -S hello.c

$

gcc -S -o hello.s hello.c

生成汇编语言的格式取决于目标平台. 另外, 如果是多个.c文件, 那么针对每一个.c文件生成一个.s文件.

 

包含头文件


在程序中包含与连接库对应的头文件是很重要的方面,要使用库,就一定要能正确地引用头文件。一般在代码中通过#include引入头文件, 如果头文件位于系统默认的包含路径(/usr/includes), 则只需在#include中给出头文件的名字, 不需指定完整路径.  但若要包含的头文件位于系统默认包含路径之外, 则有其它的工作要做: 可以(在源文件中)同时指定头文件的全路径. 但考虑到可移植性,最好通过-I在调用gcc的编译命令中指定。

下面看这个求立方的小程序(阴影语句表示刚开始不存在):

#include <stdio.h>
#include <math.h>
int main(int argc, char *argv[])
{
  double x = pow (2.0, 3.0);
  printf("The cube of 2.0 is %f\n", x);
  return 0;
}

使用gcc-2.95来编译它(-lm选项在后面的连接选项中有介绍, 这里只讨论头文件的包含问题):
$ gcc-2.95 -Wall pow.c -lm -o pow_2.95
pow.c: In function `main':
pow.c:5: warning: implicit declaration of function `pow'

程序编译成功,但gcc给出警告: pow函数隐式声明。
$ ./pow_2.95
The cube of 2.0 is 1.000000

明显执行结果是错误的,在源程序中引入头文件(#include <math.h>),消除了错误。

不要忽略Warning信息!它可能预示着,程序虽然编译成功,但运行结果可能有错。故,起码加上"-Wall"编译选项!并尽量修正Warning警告。

搜索路径

首先要理解 #include<file.h>和#include"file.h"的区别:
#include<file.h>只在默认的系统包含路径搜索头文件
#include"file.h"首先在当前目录搜索头文件, 若头文件不位于当前目录, 则到系统默认的包含路径搜索头文件.

UNIX类系统默认的系统路径为:

头文件,包含路径: /usr/local/include/  or  /usr/include/
库文件,连接路径: /usr/local/lib/          or  /usr/lib/ 
  

对于标准c库(glibc或其它c库)的头文件, 我们可以直接在源文件中使用#include <file.h>来引入头文件.

如果要在源文件中引入自己的头文件, 就需要考虑下面的问题:

1, 如果使用非系统头文件, 头文件和源文件位于同一个目录, 如何引用头文件呢?
——我们可以简单地在源文件中使用 #include "file.h", gcc将当前目录的file.h引入到源文件. 如果你很固执, 仍想使用#include <file.h>语句, 可以在调用gcc时添加"-I."来将当前目录添加到系统包含路径. 细心的朋友可能会想到: 这样对引用其它头文件会不会有影响? 比如, #include<file.h>之后紧接着一个#include<math.h>, 它能正确引入math.h吗? 答案是: 没有影响. 仍然能正确引用math.h. 我的理解是: "-I."将当前目录作为包含路径的第一选择, 若在当前目录找不到头文件, 则在默认路径搜索头文件. 这实际上和#include"file.h"是一个意思.

2, 对于比较大型的工程, 会有许多用户自定义的头文件, 并且头文件和.c文件会位于不同的目录. 又该如何在.c文件中引用头文件呢?
—— 可以直接在.c文件中利用#include“/path/file.h", 通过指定头文件的路径(可以是绝对路径, 也可以是相对路径)来包含头文件. 但这明显降低了程序的可移植性. 在别的系统环境下编译可能会出现问题. 所以还是利用"-I"选项指定头文件完整的包含路径.

针对头文件比较多的情况, 最好把它们统一放在一个目录中, 比如~/project/include. 这样就不需为不同的头文件指定不同的路径. 如果你嫌每次输入这么多选项太麻烦, 你可以通过设置环境变量来添加路径:
$ C_INCLUDE_PATH=/opt/gdbm-1.8.3/include
$ export C_INCLUDE_PATH
$ LIBRART_PATH=/opt/gdbm-1.8.3/lib
$ export LIBRART_PATH

可一次指定多个搜索路径,":"用于分隔它们,"."表示当前路径,如:
$ C_INCLUDE_PATH=.:/opt/gdbm-1.8.3/include:/net/include
$ LIBRARY_PATH=.:/opt/gdbm-1.8.3/lib:/net/lib
(可以添加多个路径,路径之间用:相隔,.代表当前目录,若.在最前头,也可省略)

当然,若想永久地添加这些路径,可以在.bash_profile中添加上述语句.

3, 还有一个比较猥琐的办法: 系统默认的包含路径不是/usr/include或/usr/local/include么? 我把自己的头文件拷贝到其中的一个目录, 不就可以了么? 的确可以这样, 如果你只想在你自己的机器上编译运行这个程序的话.

前面介绍了三种添加搜索路径的方法,如果这三种方法一起使用,优先级如何呢?

 

命令行设置 > 环境变量设置 > 系统默认

 

与外部库连接


前面介绍了如何包含头文件. 而头文件和库是息息相关的, 使用库时, 要在源代码中包含适当的头文件,这样才能声明库中函数的原型(发布库时, 就需要给出相应的头文件).

 

和包含路径一样, 系统也有默认的连接路径:


头文件,包含路径: /usr/local/include/  or  /usr/include/
库文件,连接路径: /usr/local/lib/          or  /usr/lib/  

同样地, 我们想要使用某个库里的函数, 必须将这个库连接到使用那些函数的程序中.

 

有一个例外: libc.a或libc.so (C标准库,它包含了ANSI C所定义的C函数)是不需要你显式连接的, 所有的C程序在运行时都会自动加载c标准库.

 

除了C标准库之外的库称之为"外部库", 它可能是别人提供给你的, 也可能是你自己创建的(后面有介绍如何创建库的内容).

 

外部库有两种:(1)静态连接库lib.a
                     (2)共享连接库lib.so

两者的共同点:
    .a, .so都是.o目标文件的集合,这些目标文件中含有一些函数的定义(机器码),而这些函数将在连接时会被最终的可执行文件用到。

两者的区别:
    静态库.a  : 当程序与静态库连接时,库中目标文件所含的所有将被程序使用的函数的机器码被copy到最终的可执行文件中. 静态库有个缺点: 占用磁盘和内存空间. 静态库会被添加到和它连接的每个程序中, 而且这些程序运行时, 都会被加载到内存中. 无形中又多消耗了更多的内存空间.

    共享库.so : 与共享库连接的可执行文件只包含它需要的函数的引用表,而不是所有的函数代码,只有在程序执行时, 那些需要的函数代码才被拷贝到内存中, 这样就使可执行文件比较小, 节省磁盘空间(更进一步,操作系统使用虚拟内存,使得一份共享库驻留在内存中被多个程序使用).共享库还有个优点: 若库本身被更新, 不需要重新编译与 它连接的源程序。

静态库

下面我们来看一个简单的例子,计算2.0的平方根(假设文件名为sqrt.c):

#include <math.h>
#include <stdio.h>
int
main (void)
{
double x = sqrt (2.0);
printf ("The square root of 2.0 is %f\n", x);
return 0;
}

用gcc将它编译为可执行文件:
$ gcc -Wall sqrt.c -o sqrt
编译成功,没有任何警告或错误信息。执行结果也正确。
$ ./sqrt
The square root of 2.0 is 1.414214
    
下面我们来看看刚才使用的gcc版本:
$ gcc --version
  gcc (GCC) 4.0.2 20050808 (prerelease) (Ubuntu 4.0.1-4ubuntu9)

现在我用2.95版的gcc把sqrt.c再编译一次:
$ gcc-2.95 -Wall sqrt.c -o sqrt_2.95
  /tmp/ccVBJd2H.o: In function `main':
  sqrt.c:(.text+0x16): undefined reference to `sqrt'
     collect2: ld returned 1 exit status
    
编 译器会给出上述错误信息,这是因为sqrt函数不能与外部数学库"libm.a"相连。sqrt函数没有在程序中定义,也不存在于默认C库 "libc.a"中,如果用gcc-2.95,应该显式地选择连接库。上述出错信息中的"/tmp/ccVBJd2H.o"是gcc创造的临时目标文件, 用作连接时用。

使用下列的命令可以成功编译:
$ gcc-2.95 -Wall sqrt.c /usr/lib/libm.a -o sqrt_2.95
它告知gcc:在编译sqrt.c时,加入位于/usr/lib中的libm.a库(C数学库)。

C库文件默认位于/usr/lib, /usr/local/lib系统目录中; gcc默认地从/usr/local/lib, /usr/lib中搜索库文件。(在我的Ubuntu系统中,C库文件位于/urs/lib中。

这里还要注意连接顺序的问题,比如上述命令,如果我改成:
$ gcc-2.95 -Wall /usr/lib/libm.a sqrt.c -o sqrt_2.95
gcc会给出出错信息:
 /tmp/cc6b3bIa.o: In function `main':
 sqrt.c:(.text+0x16): undefined reference to `sqrt'
 collect2: ld returned 1 exit status

正如读取目标文件的顺序,gcc也在命令行中从左向右读取库文件——任何包含某函数定义的库文件必须位于调用该函数的目标文件之后!

指定库文件的绝对路径比较繁琐,有一种简化方法,相对于上述命令,可以用下面的命令来替代:
$ gcc-2.95 -Wall sqrt.c -lm -o sqrt_2.95
其中的"-l"表示与库文件连接,"m"代表"libm.a"中的m。一般而言,"-lNAME"选项会使gcc将目标文件与名为"libNAME.a"的库文件相连。(这里假设使用默认目录中的库,对于其他目录中的库文件,参考后面的“搜索路径”。)

上面所提到的"libm.a"就是静态库文件,所有静态库文件的扩展名都是.a!
$ whereis libm.a
  libm: /usr/lib/libm.a /usr/lib/libm.so

正如前面所说,默认的库文件位于/usr/lib/或/usr/local/lib/目录中。其中,libm.a是静态库文件,libm.so是后面会介绍的动态共享库文件。

如果调用的函数都包含在libc.a中(C标准库被包含在/usr/lib/libc.a中,它包含了ANSI C所定义的C函数)。那么没有必要显式指定libc.a:所有的C程序运行时都自动包含了C标准库!(试试 $ gcc-2.95 -Wall hello.c -o hello)。

共享库

正因为共享库的优点,如果系统中存在.so库,gcc默认使用共享库(在/usr/lib/目录中,库文件以共享和静态两种版本存在)。 

运行:$ gcc -Wall -L. hello.c -lNAME -o hello
gcc先检查是否有替代的libNAME.so库可用。   

正如前面所说,共享库以.so为扩展名(so == shared object)。

那么,如果不想用共享库,而只用静态库呢?可以加上 -static选项
$ gcc -Wall -static hello.c -lNAME -o hello
它等价于:
$ gcc -Wall hello.c libNAME.a -o hello

$ gcc-2.95 -Wall sqrt.c -static -lm -o sqrt_2.95_static
$ gcc-2.95 -Wall sqrt.c -lm -o sqrt_2.95_default
$ gcc-2.95 -Wall sqrt.c /usr/lib/libm.a -o sqrt_2.95_a
$ gcc-2.95 -Wall sqrt.c /usr/lib/libm.so -o sqrt_2.95_so

$ ls -l sqrt*
-rwxr-xr-x  1 zp zp  21076 2006-04-25 14:52 sqrt_2.95_a
-rwxr-xr-x  1 zp zp   7604 2006-04-25 14:52 sqrt_2.95_default
-rwxr-xr-x  1 zp zp   7604 2006-04-25 14:52 sqrt_2.95_so
-rwxr-xr-x  1 zp zp 487393 2006-04-25 14:52 sqrt_2.95_static

上述用四种方式编译sqrt.c,并比较了可执行文件的大小。奇怪的是,-static -lm 和 /lib/libm.a为什么有区别?有知其原因着,恳请指明,在此谢谢了! :)

如果libNAME.a在当前目录,应执行下面的命令:
$ gcc -Wall -L. hello.c -lNAME -o hello
-L.表示将当前目录加到连接路径。

利用GNU archiver创建库

$ ar cr libhello.a hello_fn.o by_fn.o
从hello_fn.o和by_fn.o创建libihello.a,其中cr表示:creat & replace
$ ar t libhello.a
列出libhello.a中的内容,t == table
(也可创建libhello.so)

关于创建库的详细介绍,可参考本blog的GNU binutils笔记


调试

 


一般地,可执行文件中是不包含任何对源代码的参考的,而debugger要工作,就要知道目标文件/可执行文件中的机器码对应的源代码的信息(如:哪条语 句、函数名、变量名...). debugger工作原理:将函数名、变量名,对它们的引用,将所有这些对象对应的代码行号储存到目标文件或可执行文件的符 号表中。

GCC提供-g选项,将调试信息加入到目标文件或可执行文件中。
$ gcc -Wall -g hello.c -o hello

注意:若发生了段错误,但没有core dump,是由于系统禁止core文件的生成!
$ ulimit -c  ,若显示为0,则系统禁止了core dump

解决方法:
$ ulimit -c unlimited  (只对当前shell进程有效)
或在~/.bashrc 的最后加入: ulimit -c unlimited (一劳永逸)

优化


GCC具有优化代码的功能,代码的优化是一项比较复杂的工作,它可归为:源代码级优化、速度与空间的权衡、执行代码的调度。

GCC提供了下列优化选项:
    -O0  : 默认不优化(若要生成调试信息,最好不优化)
    -O1  : 简单优化,不进行速度与空间的权衡优化;   
    -O2  : 进一步的优化,包括了调度。(若要优化,该选项最适合,它是GNU发布软件的默认优化级别;
    -O3  : 鸡肋,兴许使程序速度更慢;
    -funroll-loops  : 展开循环,会使可执行文件增大,而速度是否增加取决于特定环境;
    -Os  : 生成最小执行文件;

一般来说,调试时不优化,一般的优化选项用-O2(gcc允许-g与-O2联用,这也是GNU软件包发布的默认选项),embedded可以考虑-Os。

注意:此处为O!(非0或小写的o,-o是指定可执行文件名)。

检验优化结果的方法:$ time ./prog

time测量指定程序的执行时间,结果由三部分组成:
    real : 进程总的执行时间, 它和系统负载有关(包括了进程调度,切换的时间)
    user: 被测量进程中用户指令的执行时间
    sys  : 被测量进程中内核代用户指令执行的时间

user和sys的和被称为CPU时间.

注意:对代码的优化可能会引发警告信息,移出警告的办法不是关闭优化,而是调整代码

命令: fuser与lsof

Command: fuser
标识使用文件或套接字的进程
例如: fuser /home/simplyzhao
进程ID后的字母表示占用资源的方式,有下面几种表示:

c 当前路径(current directory.)我的理解是表示这个资源的占用是以文件目录方式,也就是进进入了需要释放的资源的路径,这是最常用的资源占用方式。

e 正在运行可执行文件(executable being run.),比如运行了光盘上的某个程序

f 打开文件( open file),缺省模式下f忽略。所以上面的例子中,虽然是开打了光盘上的Autorun.inf文件,但是给出的标识是c,而不是f。

r root目录(root directory).没有明白什么意思,难道是说进入了/root这个特定目录?

m mmap文件或者共享库( mmap’ed file or shared library).这应该是说某个进程使用了你要释放的资源的某个共享文件。

在查找的同时,你还可定指定一些参数,比如

-k 杀死这些正在访问这些文件的进程。除非使用-signal修改信号,否则将发送SIGKILL信号。

Command: lsof
lsof的功能很多,特別提醒大家, -c,-g,-p,-u,这四个参数最有用。更详细的资料请参看:man lsof。

1、查看文件系统阻塞

   根据工作需要,系统管理员想卸载一个文件系统并执行umount /mountpoint,但程序报告常常显示:umount: /mountpoint: device is busy;这是因为该文件系统上有正在打开的文件而不允许你这么做。这时,我们需要知道哪些文件、程序及用户仍在使用该系统,以便通知用户退出该系统,可 以使用lsof识别正在打开一个特定文件系统的进程,执行如下命令:
/usr/sbin/lsof /mountpoint
在这里,mountpoint就是安装位置。例如:
# /usr/sbin /lsof /home
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
bash12134 meng cwdDIR8,5 4096 32705 /home/meng
telnet 12176 meng cwdDIR8,5 4096 32705 /home/meng
bash19809 meng cwdDIR8,5 4096 32705 /home/meng
bash20276 meng cwdDIR8,5 4096 32705 /home/meng
su 20315 root cwdDIR8,5 4096 32705 /home/meng
bash20316 root cwdDIR8,5 4096 32705 /home/meng
csh 20374 root cwdDIR8,5 4096 32705 /home/meng
lsof 20396 root cwdDIR8,5 4096 32705 /home/meng
lsof 20397 root cwdDIR8,5 4096 32705 /home/meng

  显然,所有使用这些被打开的文件的进程都需要在文件系统能够被卸载前被终止。管理员以root身份,kill掉占用这个文件系统的进程,解除文件系统阻塞。

  2、搜索打开的网络连接

  如果想搜索IP地址为10.645.64.23的远程连接主机的所有网络连接,可以执行如下命令:
/usr/sbin/lsof
–i@10.65.64.23可以打开系统中该远程知己所有打开的套接字。
# lsof
-i@10.65.64.23
COMMAND PID USER FD TYPE DEVICE SIZE/OFF INODE NAME
telnetd 6605 root0u inet 0x14813f00 0t0 TCP xpp3:telnet->linuxone:33143 (ESTABLISHED)
telnetd 6605 root1u inet 0x14813f00 0t0 TCP xpp3:telnet->linuxone:33143 (ESTABLISHED)
telnetd 6605 root2u inet 0x14813f00 0t0 TCP xpp3:telnet->linuxone:33143 (ESTABLISHED)

  3、寻找本地断开的打开文件

  用户经常遇到这种情况,当一个进程正在向一个文件写数据时,该文件的目录可能被移动。这就产生了一个非常大的问题。例如,用户可能发现正在向/data写数据,但是却看不到文件增大,LSOF这个工具可以找到这样的错误,例如:
/usr/sbin/lsof +L1,通常可以看到下面的信息:
# lsof +L1
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINKNODE NAME
svrMgt_mi458 root 4r VREG 8,00 0 3418 / (/dev/rz0a)
yes 677 root 1w VREG 8,0 186523648 0 92888 / (/de v/rz0a)
# lsof +L1
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
svrMgt_mi458 root 4r VREG 8,0 0 0 3418 / (/dev/rz0a)
yes 677 root1w VREG 8,0 2735882240 92888 / (/dev/rz0a)

  我们可以用kill -9 PID命令来结束PID显示的命令排除错误,释放空间。

我们还可以用-a选项来限制lsof报告单文件系统中的链接数量。例如,为了限制到/data部分的输出,可以输入:/usr/sbin/lsof –a +L1 /data

  4、搜索被程序打开的所有文件及打开的文件相关联进程

  如果想知道执行PID号为637的sendmail命令打开了哪些文件的话,可以执行lsof -p 637命令。输出的结果如下:

  # lsof -p 637
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sendmail 637 root cwd VDIR8,6 512 470400 /usr/var/spool/mqueue
sendmail 637 root txt VREG8,6 466944 9650 /usr (/dev/rz0g)
sendmail 637 root txt VREG8,0 139264 16016 /sbin/loader
sendmail 637 root txt VREG8,0 1663104 38402 /shlib/libc.so
sendmail 637 root0r VCHR2,2 0t0 9607 /dev/null
sendmail 637 root1w VCHR2,2 0t0 9607 /dev/null
sendmail 637 root2w VCHR2,2 0t0 9607 /dev/null
sendmail 637 root3u unix 0x0c2fc280 0t0->0x1ead2b40
sendmail 637 root4u inet 0x0c34c200 0t0TCP *:smtp (LISTEN)

  上述输出信息显示了该程序当前打开的所有文件、设备、库及套接字等。

  执行下面的命令可以发现哪些进程正在使用某个特定的文件,如下所示,可以看出,只有系统记录后台进程syslogd打开messages这个文件。

  # lsof /var/adm/messages
COMMAND PID USER FD TYPE DEVICE SIZE/OFF INODE NAME
syslogd 147 root 16w VREG8,6 2653365 22501 /usr/var/adm/messages

  5、其它使用命令(更详细的资料请man lsof,这部分参看了一些资料给大家总结一下)
若沒有加上任何的参数,lsof 会列出所有被程序打开的文件。
参数可以相互结合,ex: -a -b -c 等同于 -abc
-? -h 这两个参数意思相同,显示出 lsof 的使用说明。

  -a 参数被视为 AND (注意:-a参数一但加上 ,会影响全部的参数。)

  -c c 显示出以字母 c开头进程现在打开的文件
例:显示以init进程现在打开的文件
# lsof -c init
COMMAND PID USER FD TYPE DEVICE SIZE/OFF INODE NAME
init 1 root cwd VDIR 4095,365376 8192 2 /
init 1 root txt VREG 4095,365376 286720 463 /sbin/init

  +d s 依照文件夹s来搜寻,此参数将不会继续深入搜寻此文件夹
例:显示在/usr/users/tongxl目录下被程序正在打开的文件(如下所示)
# lsof +d /usr/users/tongxl
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ksh 26946 root cwd VDIR8,6 512 51281 /usr/users/tongxl/c
a.out 26953 root cwd VDIR8,6 512 51281 /usr/users/tongxl/c

  +D D 同上,但是会搜索目录下的目录,时间较长。(注意︰lsof以此参数进行时,须花费较多的动态记忆体。尤其在处理较大的文件夹时,请务必审慎使用之。)
例:显示在/usr/local/文件夹下被程序正在打开的文件(如下)很明显可以看出二者的差别
# lsof +D /usr/users/tongxl
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ksh 26946 root cwd VDIR8,6 512 51281 /usr/users/tongxl/c
a.out 26953 root cwd VDIR8,6 512 51281 /usr/users/tongxl/c
a.out 26953 root txt VREG8,624576 51311 /usr/users/tongxl/c/a.out

  -d s 此参数以file descriptor (FD)值显示结果,可以采用范围表示,如 1-3 或 3-10 但 最前面的数一定要比最后面的数小。
举例:以FD为4显示
# lsof -d 4
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
syslogd 147 root4u inet 0x1fe0b980 0t0UDP *:syslog
binlogd 151 root4u inet 0x1fe0bd40 0t0UDP *:*
portmap 319 root4u inet 0x1fe0b740 0t0UDP *:111
mountd321 root4u VREG8,6 253 22516 /usr (/dev/rz0g)
nfsd 323 root4u inet 0x0c349e00 0t0TCP *:2049 (LISTEN)
rpc.statd 330 root4u inet 0x1ab42000 0t0TCP xpp3:1024 (LISTEN)
rpc.lockd 332 root4u inet 0x1fe0bbc0 0t0UDP xpp3:1028
snmpd 449 root4u unix 0x1aaf6500 0t0/var/esnmp/esnmpd
svrMgt_mi 457 root4r VREG8,00 3424 / (/dev/rz0a)
os_mibs 458 root4u inet 0x1ab475c0 0t0UDP *:*
cpq_mibs 460 root4u unix 0x1aaf77c0 0t0/var/esnmp/esnmp_sub460
advfsd472 root4u inet 0x0c320000 0t0TCP *:AdvFS (LISTEN)
insightd 475 root4r VDIR8,6 512 25610 /usr (/dev/rz0g)
inetd 506 root4u inet 0x1ab26700 0t0TCP *:ftp (LISTEN)
lpd 567 root4wW VREG8,64 451219 /usr (/dev/rz0g)
dtlogin 605 root4w VREG8,64 344028 /usr (/dev/rz0g)
Xdec 616 root4w VREG8,64 344028 /usr (/dev/rz0g)
sendmail 702 root4u inet 0x0c321900 0t0TCP *:smtp (LISTEN)
dtlogin 891 root4w VREG8,64 344028 /usr (/dev/rz0g)
dxconsole 907 root4w VREG8,64 344028 /usr (/dev/rz0g)
dtgreet 908 root4w VREG8,64 344028 /usr (/dev/rz0g)

  -g [s] 以程序的PGID (process group IDentification)显示,也可以采用范围(1-3)或个别(3,5)表示,若没有特别指定,则显示全部。
举例:以PGID为3显示
# lsof -g 3
COMMAND PID PGID USER FD TYPE DEVICE SIZE/OFF NODE NAME
kloadsrv 33 root cwd VDIR8,0 2560 2 /
kloadsrv 33 root txt VREG8,0 221184 16041 /sbin/kloadsrv
kloadsrv 33 root0r VCHR0,0 0t0 9608 /dev/console
kloadsrv 33 root1w VCHR0,0 0t0 9608 /dev/console
kloadsrv 33 root2w VCHR0,0 0t0 9608 /dev/console

  -i [i] 用以监听有关的任何符合的位址。若没有相关位置被指定,则监听全部。
语法: lsof -i[46] [protocol][@hostname|hostaddr][:service|port]
46 --> IPv4 or IPv6
protocol --> TCP or UDP
hostname --> Internet host name
hostaddr --> IPv4位置
service --> /etc/service中的 service name (可以不只一个)
port --> 埠号 (可以不只一个)

  # lsof -i tcp@xp001

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
telnetd 26862 root0u inet 0x0c349000 0t0 TCP xpp3:telnet->xp001:3807 (ESTABLISHED)
telnetd 26862 root1u inet 0x0c349000 0t0 TCP xpp3:telnet->xp001:3807 (ESTABLISHED)
telnetd 26862 root2u inet 0x0c349000 0t0 TCP xpp3:telnet->xp001:3807 (ESTABLISHED)
telnetd 26986 root0u inet 0x1ab27100 0t0 TCP xpp3:telnet->xp001:3988 (ESTABLISHED)
telnetd 26986 root1u inet 0x1ab27100 0t0 TCP xpp3:telnet->xp001:3988 (ESTABLISHED)
telnetd 26986 root2u inet 0x1ab27100 0t0 TCP xpp3:telnet->xp001:3988 (ESTABLISHED)

  -l此参数禁止将user ID转换为登入名称。(预设显示登入名称)

  # lsof -l|more
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
kernel0 0 cwd VDIR8,02560 2 /
init 1 0 cwd VDIR8,02560 2 /
init 1 0 txt VREG8,0 286720 16015 / (/dev/rz0a)
kloadsrv 3 0 cwd VDIR8,02560 2 /
kloadsrv 3 0 txt VREG8,0 221184 16041 /sbin/kloadsrv
kloadsrv 3 0 0r VCHR0,0 0t0 9608 /dev/console
kloadsrv 3 0 1w VCHR0,0 0t0 9608 /dev/console
kloadsrv 3 0 2w VCHR0,0 0t0 9608 /dev/console

  +|-L [l] +或-表示正在打开或取消显示文件连结数. 若只有单纯的+L,后面没有任何数字,则表示显示全部。若其后有加上数字,只有文件连结数少于该数字的会被列出。

  -n不将IP位址转换成hostname,预设是不加上-n参数。
举例: lsof -i
tcp@xp001 -n
(您可以和上两张图比较一下,原先的hostname便回ip位置了)
# lsof -i
tcp@xp001 -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
telnetd 26862 root0u inet 0x0c349000 0t0 TCP 10.65.69.147:telnet->10.65.69.131:3807 (ESTABLISHED)
telnetd 26862 root1u inet 0x0c349000 0t0 TCP 10.65.69.147:telnet->10.65.69.131:3807 (ESTABLISHED)
telnetd 26862 root2u inet 0x0c349000 0t0 TCP 10.65.69.147:telnet->10.65.69.131:3807 (ESTABLISHED)
telnetd 26986 root0u inet 0x1ab27100 0t0 TCP 10.65.69.147:telnet->10.65.69.131:3988 (ESTABLISHED)
telnetd 26986 root1u inet 0x1ab27100 0t0 TCP 10.65.69.147:telnet->10.65.69.131:3988 (ESTABLISHED)
telnetd 26986 root2u inet 0x1ab27100 0t0 TCP 10.65.69.147:telnet->10.65.69.131:3988 (ESTABLISHED)
# lsof -i
tcp@xp001
  COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
telnetd 26862 root0u inet 0x0c349000 0t0 TCP xpp3:telnet->xp001:3807 (ESTABLISHED)
telnetd 26862 root1u inet 0x0c349000 0t0 TCP xpp3:telnet->xp001:3807 (ESTABLISHED)
telnetd 26862 root2u inet 0x0c349000 0t0 TCP xpp3:telnet->xp001:3807 (ESTABLISHED)
telnetd 26986 root0u inet 0x1ab27100 0t0 TCP xpp3:telnet->xp001:3988 (ESTABLISHED)
telnetd 26986 root1u inet 0x1ab27100 0t0 TCP xpp3:telnet->xp001:3988 (ESTABLISHED)
telnetd 26986 root2u inet 0x1ab27100 0t0 TCP xpp3:telnet->xp001:3988 (ESTABLISHED)

  -s列出文件的大小,若该文件没有大小,则留下空白。

# lsof -s
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
kernel0 root cwd VDIR8,0 2560 2 /
init 1 root cwd VDIR8,0 2560 2 /
init 1 root txt VREG8,0 286720 16015 / (/dev/rz0a)
kloadsrv 3 root cwd VDIR8,0 2560 2 /
kloadsrv 3 root txt VREG8,0 221184 16041 /sbin/kloadsrv
kloadsrv 3 root0r VCHR0,09608 /dev/console
kloadsrv 3 root1w VCHR0,09608 /dev/console
kloadsrv 3 root2w VCHR0,09608 /dev/console

  -u s 以login name(登入名称)或UID,列出所正在打开文件。

# lsof -u tongxl
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
csh 26939 tongxl cwd VDIR8,6 1024 243236 /usr -- tongxl
csh 26939 tongxl txt VREG8,6 253952 12856 /usr (/dev/rz0g)
csh 26939 tongxl txt VREG8,0 139264 16016 /sbin/loader
csh 26939 tongxl txt VREG8,0 1663104 38402 /shlib/libc.so
csh 26939 tongxl0r VCHR1,0 0t0 9612 /dev/tty
csh 26939 tongxl 15u VCHR6,20t328 9618 /dev/pts/2
csh 26939 tongxl 16u VCHR6,20t328 9618 /dev/pts/2
csh 26939 tongxl 17u VCHR6,20t328 9618 /dev/pts/2
csh 26939 tongxl 18u VCHR6,20t328 9618 /dev/pts/2
csh 26939 tongxl 19u VCHR6,20t328 9618 /dev/pts/2
csh 26990 tongxl cwd VDIR8,6 1024 243236 /usr -- tongxl
csh 26990 tongxl txt VREG8,6 253952 12856 /usr (/dev/rz0g)
csh 26990 tongxl txt VREG8,0 139264 16016 /sbin/loader
csh 26990 tongxl txt VREG8,0 1663104 38402 /shlib/libc.so
csh 26990 tongxl0r VCHR1,0 0t0 9612 /dev/tty
csh 26990 tongxl 15u VCHR6,1 0t147797 9616 /dev/pts/1
csh 26990 tongxl 16u VCHR6,1 0t147797 9616 /dev/pts/1
csh 26990 tongxl 17u VCHR6,1 0t147797 9616 /dev/pts/1
csh 26990 tongxl 18u VCHR6,1 0t147797 9616 /dev/pts/1
csh 26990 tongxl 19u VCHR6,1 0t147797 9616 /dev/pts/1

提示“无法卸载卷(分区)”时的对策

背景:
在Linux下,有时会遇到(莫名奇妙的)无法正常卸载文件系统的问题,比如U盘。相对Windows下的束手无策或者使用第三方软件,Linux下使用一个命令即可解决问题。下面介绍怎样安全卸载文件系统,假设出现了下面的异常(黑体表示要输入的指令,下同):
sudo umount /media/disk
umount: /media/disk: device is busy

方法1:使用fuser
可以使用fuser命令寻找挂载在/media/disk的文件系统所关联的进程:
/sbin/fuser -m /media/disk
/media/music: 2650c 2720c
返回值表示有两个进程在访问此挂载点,PID分别为2650、2720,并且访问方式都是将此目录当作进程的当前工作目录。

此时,可以查看第一个进程是什么(在此只是示例,gnome-session才不会访问那么奇怪的地方呢^_^):
ps -e |grep 2650
2650 ? 00:00:01 gnome-session
可以使用pkill gnome-session或者kill 2650来结束此进程,另外一个进程也可以如法炮制。
到此,就可以再次尝试使用umount命令卸载/media/disk了!

fuser还提供了一个便捷的参数,使用下面命令可以立即杀死文件系统关联的所有进程:
/sbin/fuser -k /media/disk

方法2:使用lsof
fuser返回的PID虽然在末尾有个状态指示符,但对于了解进程到底正在做什么远远不够。这时可以使用lsof命令,返回在指定文件系统上有打开文件的进程的详细信息:

/usr/sbin/lsof /DATA
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
gnome-ses 2650 youran cwd DIR 8,5 4096 26771457 /DATA/youran
python 2803 youran cwd DIR 8,5 4096 26771457 /DATA/youran
escd 2810 youran 3w REG 8,5 1254 557183 /DATA/youran/.redhat/esc/esc.log
pam-panel 2811 youran cwd DIR 8,5 4096 26771457 /DATA/youran
evolution 2822 youran 23u REG 8,5 12288 2885286 /DATA/youran/.evolution/addressbook/local/system/addressbook.db
evolution 2822 youran 24r REG 8,5 118 2885287 /DATA/youran/.evolution/addressbook/local/system/addressbook.db.summary
scim-pane 2859 youran mem REG 8,5 10044356 2885529 /DATA/youran/.fonts/simhei.ttf


上面显示了当前在访问/DATA文件系统的进程信息。输出因太多,被截短。这时,可以方便地使用grep命令找出是什么进程在阻碍文件系统的卸载,并且能看到它现在在干什么。例如:

/usr/sbin/lsof /DATA |grep /DATA/youran/.evolution/
evolution 2822 youran 23u REG 8,5 12288 2885286 /DATA/youran/.evolution/addressbook/local/system/addressbook.db
evolution 2822 youran 24r REG 8,5 118 2885287 /DATA/youran/.evolution/addressbook/local/system/addressbook.db.summary

上面的输出显示当前正在访问/DATA/youran/.evolution子目录的进程,以及打开的文件。同样可以使用pkill或者kill结束这些进程。

方法3:umount -l
新版本的umount提供了-l参数,以“懒惰”的方式立即卸载文件系统,然后试图清除进程对文件系统的引用:
umount -l /media/disk
可以一试。
来源:
http://tonykorn97.itpub.net/post/6414/130087
http://bbs.unixtech.cn/read.php?tid=1454&page=e&fpage=1

查看磁盘与目录的容量:ls df du

谁占用了我的空间

有的时候磁盘告急,需要马上清理出一块空间,但是怎么知道,是哪些文件占用了我的空间呢?

ls -sSh

ls -sSh 可以将当前目录下的文件按照大小排序显示出来,最大的放在前面,当前目录下的最大文件立马现形。

参数中的 S 即是按照大小排序,s 为顺带打印出文件大小,h 把大小显示为 xx K xx M 这样的易读格式,如果你只需要排序结果,那么 ls -S 就可以

仅适合文件夹下没有子文件夹的情况

du -s ./* | sort -rn

ls 只会列出文件,并不能计算目录大小,这时候就要靠 du 了。

du 的 -s 参数会告诉 du 只打印出每个文件或目录的总大小,而不要递归的把目录下所有文件的大小打印出来。然后再传给 sort,-n 为按照数字排序,-r 为逆序显示,这样最大的文件或者目录就列在前面了

命令介绍:

df
查看整个磁盘容量的使用状况
-a 列出所有的文件系统,包括系统特有的/proc等文件系统
-k 以KB为单位显示
-m 以MB为单位显示
-h 以KB, MB, GB等格式列出,意思是human readable

比较特别是,若df后跟某个特定的文件夹时,会自动分析该目录或文件所在的分区,并将该分区的容量显示出来,不信试试:

df /boot

du
 查看文件夹下容量的使用状况
-k 以KB为单位显示
-m 以MB为单位显示
-h 以KB, MB, GB等格式列出,意思是human readable
-s 列出子目录的总容量,而不递归显示

参考:

http://www.linuxgem.org/posts/5484.html