内存管理
本章说明 Linux 的内存管理特征 即虚拟内存和磁盘缓存 描述系统管理员应该考虑的东西
工作和目的
什么是虚拟内存?
Linux 支持虚拟内存, 就是使用磁盘作为 RAM 的扩展 使可用内存相应地有效扩大
核心把当前不用的内存块存到硬盘 腾出内存给其他目的 当原来的内容又要使用时 再读
回内存 这对用户全透明 运行于 Linux 的程序只看到大量的可用内存而不甘心哪部分在磁
盘上 当然 读写硬盘比真的内存慢(慢千倍) 所以程序运行较慢 用做虚拟内存的这部分
硬盘叫 对换空间
Linux 可以使用文件系统中的普通文件或单独的分区作为对换空间 对换分区更快 但
对换文件更易于改变大小(无须对硬盘重分区) 如果知道要多少对换空间 应该用对换分区
31 如果不能确认 可以先用对换文件 用一段时间后再根据所需空间建立对换分区
Linux 允许同时使用多个对换分区和/或对换文件 即如果偶尔需要更多的对换空间 可
以随时建立一个额外的对换文件
产生对换空间
对换文件是普通文件 对核心没有什么特别的 唯一不同是它没有孔 用 mkswap 准
备 必须在本地盘上 不能在通过 NFS mount 的文件系统中
关于孔 是重要的 对换文件保留了磁盘空间 使核心能快速对换出一页 而不必经过
如文件的定位磁盘扇区的全部事情 核心只用分配给这个文件的所有扇区 由于文件中的孔
意味着没有为文件中这个位置分配磁盘扇区 这对核心使用不利
产生没有孔的对换文件的一个好办法是通过如下命令
$ dd if=/dev/zero of=/extra-swap bs=1024 count=1024
1024+0 records in
1024+0 records out
$
/extra-swap 是对换文件名 大小由 count=给出. 大小最好是 4 的倍数 因为核心写出
的内存页是 4KB 如果不是 4 的倍数 最后那几 KB 将不可用
对换分区也没什么特别 就象产生其他分区一样产生 唯一的不同是它作为原始分区使
用 即没有任何文件系统 最好将对换分区标记为类型 82(Linux swap) 虽然这对核心没
有影响 但这使分区列表更清晰
产生对换文件或对换分区后 需要写个标记起用它 这包括核心要用的一些管理信息
命令是 mkswap , 用法如下
$ mkswap /extra-swap 1024
Setting up swapspace, size = 1044480 bytes
$
注意对换空间现在还没用 它存在 但核心还没用它提供虚拟内存
请一定小心使用 mkswap , 因为它不检查文件或分区是否被其他东西使用 你可能用
mkswap 很容易地覆盖了重要文件和分区! 幸好 你只需在你安装系统时使用 mkswap
Linux 内存管理限制了每个对换空间约为 127MB(由于技术原因 实际限制是 127.6875
MB) 可以同时使用最多 16 个对换空间 总计差不多 2GB
使用对换空间
用 swapon 将一个初始化的对换空间可用 此命令告诉核心对换空间可以用了 对换
32 空间的路径作为参数 启动一个临时对换文件可以用如下命令
$ swapon /extra-swap
$
对换空间如果列入/etc/fstab 就可自动使用
/dev/hda8 none swap sw 0 0
/swapfile none swap sw 0 0
启动手稿运行命令 swapon -a, 它将启动/etc/fstab 中所列的所有对换空间 因此 swa
pon 命令只有在启动额外的对换空间时才使用
可以用 free 监视对换空间的使用 它将给出所有使用的对换空间
$ free
total used free shared buffers
Mem: 15152 14896 256 12404 2528
-/+ buffers: 12368 2784
Swap: 32452 6684 25768
$
前一行输出(Mem:)显示物理内存 Total 列不显示核心使用的物理内存(通常大约 1M
B) Used 列显示被使用的内存总额(第二行不计缓冲) Free 列显示全部没使用的内存 S
hared 列显示多个进程共享的内存总额 Buffers 列显示磁盘缓存的当前大小
后一行(Swap:)对对换空间 显示的信息类似上面 如果这行为全 0 那么没使用对换空间
通过 top 或使用 proc 文件系统的/proc/meminfo 文件可以得到相同的信息 得到某
个对换空间的使用信息目前还比较困难
可用 swapoff 取消对换空间 一般不必这样 除非是临时对换空间 对换空间中的要
用的页被换入(swap->RAM) 如果没有足够的物理内存 就被换出(RAM->swap 到其他对
换空间) 如果没有足够的虚拟内存放进所有页面 Linux 将开始震荡(thrash); 很长时间以
后应该能恢复 但此时系统不可用 取消一个对换空间前 应该检查(例如用 free )是否有
足够的物理内存
用 swapon -a 自动使用的所有对换空间可以用 swapoff -a 取消 它查看文件/etc/fstab
得知要取消什么 任何手工起用的对换空间将依然使用着
即使有许多空闲的物理内存 有时许多对换空间也被使用着 这种情况是由于在某个时
间需要对换 但后来一个占用大量物理内存的大进程终止并释放了内存 直到被换出的数据
要被使用之前它们并不自动换入 不必顾虑这种情况 但知道为什么会发生这种情况会更安
心
33 与其他操作系统共享对换空间
许多操作系统内置虚拟内存 由于他们只需在运行时使用 即 不会同时 那么除了当
前运行的 其他所有对换空间都浪费着 如果他们共享同一个对换空间将更有效 这是可能
的但需要一些 Hacking 工作 Tips-HOWTO 包含了一些如何完成这项任务的忠告
分配对换空间
也许有人告诉你 应该分配 2 倍于物理内存的对换空间 但这是个虚假的规律 下面
说明如何正确
估计你的全部内存需求 这是你可能需要的最大量 即你要同时运行的所有程序所需的
内存要求的总和 你可以同时运行你可能同时运行的所有程序试试
例如 如果你想运行 X 你得分配 8MB 给他 gcc 要求数 MB(有些文件偶尔可能需要
很大量 数十 MB 但一般 4MB 差不多) 等等 核心自己使用 1MB Shell 和一些小工具
可能需要几百 KB(或说 总共 1MB) 不必太精确 粗略估计就行 但可以较悲观地考虑
记得如果将有多人同时使用系统 他们将都消耗内存 如果 2 个人同时运行相同的程
序 总内存消耗一般并非加倍 因为代码页和共享库是单一的
free 和 ps 命令对估计内存需求很有用
第一步的估计加上一些安全量 因为对程序大小的估计很可能是错误的 因为你可能忘
了一些要运行的程序 并确定你有一些额外空间 应该有数 MB (分配太多对换空间比分
配太少好 但不必过分 因为不使用的对换空间是浪费 见后文 关于增加对换空间 ) Al
so,since it is nicer to deal with even numbers, you can round the value up to the
next full megabyte.
基于以上计算 你知道了你总共需要多少内存 减去你的实际物理内存 就是对换空间
(有些版本的 UNIX 中 你还需要分配物理内存的映象空间 所以第二布中计算的你所需的
空间就不能减)
如果你计算的对换空间比你的实际物理内存大得多(大于好几倍以上) 那么你也许需要
更多的物理内存 否则系统性能将太低
即使计算显示你无须对换空间 最好还是至少有一些 Linux 有些侵略性地使用对换空
间 这样保持一定的空闲物理内存 即使内存还不为什么程序所需 Linux 也会换出一些不
用的内存页 这样在需要的时候就可以避免因对换的等待--即对换可以在硬盘空闲的时候提
早完成
对换空间可以分在几个硬盘中 这有时可以提高性能 依赖于这些盘的相对速度和存取
模式 你可以尝试几中方案 但要知道正确地尝试是很困难的 不要相信某种方案比其他方
案好的断定 因为它不会总是对的
34 高速缓存
与存取(真正的)内存相比 从磁盘读是很慢的 另外 在相对短的一端时间里 多次读
硬盘相同的部分是很常见的 例如 你可能先读了一封电子邮件 然后回复时又将它读入编
辑器 然后复制它到一个文件夹时又用邮件程序读它 或者 考虑命令 ls 可能被系统上的
很多用户多么频繁地使用 只从磁盘读一次信息 并保持在硬盘中 知道不再需要 除了第
一次读 其他都会较快 这就叫磁盘缓存 disk buffering 用于此目的的内存叫 buffer cac
he
不幸的是 由于内存是有限且缺乏的资源 buffer cache 一般不会足够大(大到能够装
下所有人可能用到的数据) 当 cache 满时 最长时间不用的数据将被丢弃 内存释放给最
新的数据
磁盘缓冲也用于写操作 要写的数据经常马上又被读(例如一个源代码文件保存到文件
中后又被编译器读出) 所以将要写的数据放在缓冲里是个好主意 另外 只将数据放如 ca
che 而不马上写到磁盘 写操作的程序执行速度更快 写操作然后可以在后台完成 而不降
低其他程序的速度
许多操作系统有 buffer caches (即使名称不同),但并非都根据上述原理 有些是透写 w
rite-through: 数据马上写到磁盘(当然也同时写到 cache) 不马上写的 cache 叫回写 write-b
ack 回写比透写更有效 但也更容易出错 如果系统崩溃 或电源突然掉电 或软盘在 c
ache 回写前被取出 那么 cache 中改变的数据将丢失 这可能意味着文件系统 is not in f
ull working order, 可能由于未写数据包含了系统记录信息的重要的变化
因此 千万不要不经过正常的关闭过程直接关闭电源(见 6 章), 或没有 unmount 就取出
软盘(如果是 mount 的) 或什么程序还在用着软盘 或软盘灯还在闪 sync 命令刷新缓冲
即强制将所有未写数据写回磁盘 如果要确保所有数据安全回写 可以用它 传统的 UNIX
系统中 有个 update 程序在后台运行 它每 30 秒运行一次 sync 所以通常无须使用 sy
nc Linux 有一个另外的守侯程序 bdflush 它克服了 sync 有时因磁盘 I/O 负荷太重(因
为频繁的操作)而导致有时系统突然呆住的问题
Linux 下 bdflush 由 update 启动 一般无须考虑它 但如果 bdflush 偶尔因为什么
原因死了 核心会给出警告 此时应该手工启动它(/sbin/update )
cache 并不真正缓冲文件 而是块 就是磁盘 I/O 的最小单元(Linux 下 一般是 1kB)
这样 所有的目录 超级块 其他文件系统记录数据和无文件系统磁盘都可以被缓冲
cache 的效果决定于其大小 太小的 cache 几乎无用 它只能 cache 很少的数据 而
可能在被重用前就被清除了 大小有赖于有多少数据被读写 相同的数据的存取频度 唯一
的方法是实验
如果 cache 是固定大小 那么不应该太大 否则 会由于空闲内存空间太小而使用 sw
ap(也很慢) 为了最有效地使用真实内存 Linux 自动使用所有空闲内存作为 buffer cache
35 当程序需要更多内存时 自动减少 cache
Linux 下 对 cache 使用无须做任何工作 它完全是自动的 除了要正常关闭系统和取
出软盘 无须关心 cache
Linux 管理员手册(5)--引导和关机
本节说明当 Linux 系统引导和关机时发生了什么,应该任何正确完成. 如果没有遵循正
确的过程, 文件可能损坏或丢失.
引导和关机概述
开启计算机并导致其操作系统被加载的过程 叫引导. The name comes from an im
age of the computer pulling itself up from its bootstraps, but the act itself slightly
more realistic.
启动过程中,计算机首先加载了一小段叫 bootstrap loader 的程序,它依次加载和启动操作
系统, bootstrap loader 通常存储在硬盘或软盘的固定的位置. 这 2 步过程的理由是操作系
统大而复杂,而计算机加载的第一段代码很小(几百字节),以免使固件不必要地复杂化.
不同的计算机的 bootstrap 不同. 对于 PC, 计算机(它的 BIOS)读软盘或硬盘的第一个
扇区(叫 引导扇). bootstrap loader 包含在这个扇区中. 它加载位于磁盘(和其他)的其他地
方的操作系统.
Linux 加载后, 它创始化硬件和设备驱动, 然后运行 init . init 启动其他进程以允许用
户登录和做其他事情. 这部分的细节在下面讨论.
为了关闭一个Linux系统, 首先所有进程被告知结束(这使他们关闭所有文件, 完成必要
的其他事情, 使之整齐地结束), 然后 unmount 文件系统和对换区, 最后打印可以关掉电源
的信息到控制台. 如果没有遵循正确的过程, 可怕的事情可能发生. 最重要的, 文件系统缓
冲 cache 可能没有回写, 这意味着其中的所有数据将丢失, 磁盘上的文件系统不完整, 并可
能不可用.
近观引导过程
可以从软盘或硬盘引导 Linux. 安装和开始指南的安装一节 ([Wel]) 告诉你如何安装 Li
nux, 并按你希望的方式引导.
当PC引导后, BIOS做一些测试保证一切正常, 然后开始真正的引导. 它选择一个磁盘
(通常是第一个软驱, 如果有软盘的话, 否则就是第一个硬盘, 如果安装了的话; 顺序是可设
置的). 然后读第一个扇区, 这叫引导扇; 对于硬盘, 也叫主引导记录, 因为硬盘可以包含多
个分区, 每个分区都有自己的引导扇.
引导扇包含一个小程序(小到可以存入一个扇区), 它的责任是从磁盘读入真正的操作系
36 统并启动之. 从软盘启动 Linux 时, 引导扇包含的代码只读前数百个数据块(当然, 依赖于核
心的大小)到预定的内存位置. Linux 引导软盘上, 没有文件系统, 核心存在连续的扇区中,
因为这样简化了引导过程. 当然, 使用 LILO(LInux LOader)可以从文件系统引导.
从硬盘引导, 主引导记录的代码检查分区表(也在主引导记录扇区中), 确认活动分区
(标记为可引导的分区), 从该分区读引导扇区, 然后启动该引导扇区的代码. 该分区的引导
扇区的代码做与软盘所做的相同: 从该分区读入核心并启动. 但细节不同, 因为一般只给核
心映象做一个单独的分区是没什么用的, 所以分区引导扇中的代码不能只顺序地读磁盘,
它必须找到文件系统把它们放在哪些扇区中. 有几个方法解决这个问题, 但最通常的方法
是使用 LILO. (关于如何做的细节与这里的讨论无关; 更多的信息请看 LILO 文档, 它很全面)
用 LILO 引导时, 它读入并引导缺省核心. 也可以设置 LILO, 使之能引导若干个核心之
一, 甚至其他操作系统, 也可以在引导时让用户选择引导哪个核心或操作系统. LILO 可以
设置为如果有人在引导时按住 alt, shift, or ctrl 键 (LILO 启动时), LILO 将不立即引导缺省
的而问用户引导哪个. LILO 可以设置为带一个 timeout 选项并询问, 当超时时, 就引导缺省
核心.
META: 除了LILO还有其他的引导载入程序, 如loadlin, 它们的信息将在下一版本中给
出.
从软盘和硬盘启动各有优势, 但通常从硬盘启动更好, 因为这避免了关于软盘的争论.
而且快. 然而, 安装相同从硬盘启动可能有更多的麻烦, 因此很多人先用软盘引导, 然后当
相同工作很好后, 再安装 LILO 从硬盘引导.
Linux 核心被读入内存后, 才真正启动了, 概述如下:
Linux 核心是被压缩安装的, 所以它首先得解压自己. 核心映象开头包括一个解压的小
程序.
如果你有 Linux 可识别的 super-VGA 卡, 且支持一些特殊的文本模式(如 100 列 40 行),
Linux 会问你要用哪个模式. 编译核心时, 可能预定了一个视频模式, 就不会问了. 这也可
以用 LILO 或 rdev 完成.
然后, 核心检查还有什么其他硬件(硬盘, 软盘, 网卡...), 并配置适当的设备驱动; 同时, 输
出查找结果的信息. 例如, 我引导时, 得到类似如下信息:
LILO boot:
Loading linux.
Console: colour EGA+ 80x25, 8 virtual consoles
Serial driver version 3.94 with no serial options enabled
tty00 at 0x03f8 (irq = 4) is a 16450
tty01 at 0x02f8 (irq = 3) is a 16450
lp_init: lp1 exists (0), using polling driver
Memory: 7332k/8192k available (300k kernel code, 384k reserved, 176k data)
37 Floppy drive(s): fd0 is 1.44M, fd1 is 1.2M
Loopback device init
Warning WD8013 board not found at i/o = 280.
Math coprocessor using irq13 error reporting.
Partition check:
hda: hda1 hda2 hda3
VFS: Mounted root (ext filesystem).
Linux version 0.99.pl9-1 (root@haven) 05/01/93 14:12:20
精确的文本在不同系统上不同, 依赖硬件, Linux 版本, 及其配置.
然后核心试图 mount 根文件系统. 位置可在编译时设置, 或在任何时候使用 rdev 或 LILO.
文件系统类型自动检测. 如果根文件系统 mount 失败, 例如因为你忘了在核心中包含相关
的文件系统驱动, 核心将失败, 系统停止(此时没什么可做了).
根文件系统通常被只读 mount(这可用与位置相同的方法). 这可使文件系统在 mount 上
时检查; 检查一个可读写的已 mount 的文件系统可不是个好主意.
然后, 核心在后台启动程序 init (位于/sbin/init ) (它的进程号是 1). init 做许多启动工
作. 确切的事依赖于设置; 参见章了解更多信息. 它至少要启动一些必要的后台守候程序.
init 然后切换到多用户模式并启动 getty ,提供虚拟控制台和串行线. getty 是一个让用
户通过虚拟控制台和串行终端登录的程序. init 还可能启动一些其他程序, 基于设置.
至此, 引导完成, 系统启动并正常运行.
关于关机的更多信息
关闭 Linux 系统时 遵循正确的过程是很重要的 否则 文件系统可能成为废物 文件
可能变成杂乱的 这是因为 Linux 使用磁盘缓存 并不立即将数据写到磁盘 而是间歇地回
写 这极大地改善了性能 但同时也意味着如果你只是关闭电源 cache 可能保留着大量数
据 而磁盘上的数据可能不是一个全部的正在工作的文件系统(因为有些数据已经回写到硬
盘 而有些没有)
另一个不能直接关闭电源的原因是 在多任务系统中 后台可能运行着很多东西 关闭
电源可能损失惨重 使用正确的关机顺序 可以保证所有的后台进程得以保存他们的数据
正常关闭 Linux 系统的命令是 shutdown 它通常使用 2 种方法之一
如果系统只有你一个用户 使用 shutdown 的通常方法是退出所有运行程序 从所有虚
拟控制台注销 用 root 登录(如果你已经是 root 当然不必再注销 登录 但应该换到根目
录 以免由于 unmount 出现问题) 然后运行命令 shutdown -h now (虽然单用户时一般不
必要 但如果需要一个延时 用一个加号加一个表示分钟的数目代替 now)
如果系统是多用户 使用命令 shutdown -h +time message time 是到系统停止的
38 分钟数 message 是告知所有用户系统关机原因的短信息
# shutdown -h +10 'We will install a new disk. System should
> be back on-line in three hours.'
#
上面的命令警告所有用户 系统将在 10 分钟后关闭 他们最好保存信息 否则将丢失
警告将显示在所有登录的终端上 包括所有的 xterm 上:
Broadcast message from root (ttyp0) Wed Aug 2 01:03:25 1995...
We will install a new disk. System should
be back on-line in three hours.
The system is going DOWN for system halt in 10 minutes !!
警告在系统关闭前将自动重复数遍 随着时间流逝 间隔越来越短
当延时之后关闭系统真正开始时 所有文件系统(除了根)被 unmount 所有用户进程(如
果有人还未注销)被终止 守侯进程被关闭 所有东西都停下来 此后 init 打印出一条信
息告知你可以关掉电源了 此时 也只有在此时 你才可以关闭电源
有时(虽然在任何好的系统上极少) 系统可能不能正常关闭 例如 核心紊乱 崩溃等
不正常情况 可能无法键入任何命令 因此正常关机可能有些困难 这是只能直接关机 问
题可能没那么严重 比如 有人误动了你的键盘 核心和 update 程序还在正常运行 等待
一些时间可能是个好建议 这能使 update 有机会将缓冲 cache 中的数据回存硬盘 然后
再直接关机
有人喜欢用 sync 三遍来关闭系统 等到磁盘 I/O 停止 然后在关闭电源 如果没有什
么程序运行着 这和用 shutdown 等效 然而 它不 unmount 任何文件系统 可能导致 ex
t2fs 的"干净文件系统"标志出问题 这种 3 遍 sync 的方法是不推荐使用的
(In case you're wondering: the reason for three syncs is that in the early days of
UNIX, when the commands were typed separately, that usually gave sufficient time
for most disk I/O to be finished.)
重启动
重启动就是完全关闭系统 关掉电源 然后再打开 简单方法是用 shutdown 重启动系
统而不是仅停止系统 这要使用 shutdown 的 -r 选项 例如命令 shutdown -r now
许多 Linux 系统在按 ctrl-alt-del 键时运行 shutdown -r now 这是可设置的 比如在多
用户系统中设置一定的延时也许更好 如果是谁都能接触到的系统 那么最好设置为按 ctrl
-alt-del 什么也不干
39 单用户模式
shutdown 命令也可用于切换到单用户模式 这种模式谁也不能登录 只有 root 可以使
用控制台 这对系统一般运行时不能做的系统管理任务很有用 单用户模式将在章详细讨论
紧急引导(软)盘
并非总可以从硬盘引导 例如 LILO 设错了 系统可能就无法引导 这时 需要另一
个总能引导的方法 对于典型的 PC 可能是软驱
许多 Linux distributions 允许在安装时产生一张紧急引导盘 emergency boot floppy
应该做 然而 有些这样的引导盘只包含核心 and assume you will be using the prog
rams on the distribution's installation disks to fix whatever problem you have 有时这
些程序是不够的 例如你可能需要回存你的备份 而备份/回存软件在 Linux 安装盘里没有
因此 可能需要自己产生 root 盘 Graham Chapman 写的 Bootdisk HOWTO([Cha])
包含关于此的指导 当然 你必须记得使你的紧急引导盘和 root 盘最新
root 盘被 mount 上时 不能用软驱干其他任何事 因此如果你只有一个软驱可能不太
方便 然而 如果你有足够的内存 可以设置引导盘将 root 盘加载到 RAM 盘上(为此 引
导盘的核心需要特殊设置) 一旦 root 盘被加载到 RAM 盘中 软驱就可以用于 mount 其他
盘了
Linux 管理员手册(6)--登录和注销
说明当一个用户登录和注销时发生了什么 较详细地说明后台进程的各种交互 log 文
件 配置文件等
通过终端登录
首先 init 确认有一个 getty 程序提供给终端连接(或控制台) getty 侦听终端等候用
户告知它要登录 (这通常意味着用户必然键入些什么) 当它注意到一个用户 getty 输出一
个欢迎信息(存在/etc/issue 中) 并提示用户名 最后运行 login 程序 login 作为一个参
数得到用户名 并提示用户输入口令 如果正确 login 启动给此用户设置的 shell 否则退
出并终止进程 (可能在再给用户一个机会输入用户名和口令之后) init 注意到进程终止
就给这个终端启动一个新的 getty
注意唯一的新进程是由 init 产生的(用 fork 系统调用) getty 和 login 只是替代进程
运行的程序 (使用 exec 系统调用)
为注意用户 串行线需要一个单独的程序 因为终端活动时可以(传统上也是)变得复杂
getty 也适应连接的速度和其他设置 这对拨号连接特别重要 因为连接和连接的参数可
能不同
40 getty 和 init 有多个版本在使用 各有优缺点 学习你的系统的版本也了解其他版本是
个好主意(你可以用 Linux Software Map 来找 )如果你没有拨入 可能不必考虑 getty
但 init 仍然很重要
通过网络登录
一个网络中的 2 台计算机通常通过一个物理电缆连接 当他们通过网络通信是 参与
通信的每个计算机里的程序通过虚拟连接 virtual connection 通信 即一些虚构的电缆 虚
拟连接的每端的程序 独占自己的(虚拟)电缆 然而 因为这电缆不是真的 只是虚构的
所有计算机的操作系统可以在同一物理电缆上有多条虚拟连接 这样 只用一条电缆 多个
程序可以不必考虑其他通信而相互通信 使用同一电缆使多台计算机是可能的 2 台计算机
间存在的虚拟连接 其他计算机会忽略他们不参加的连接
那是一个复杂和抽象的真实描述 但可能足够理解网络登录与普通登录的不同的重要原
因 不同计算机上的 2 个程序要通信时 虚拟连接建立 由于理论上可能从网络上的任何
一台计算机登录到任何一台计算机 因此可能有极大数量的潜在的虚拟通讯 因此 为每个
潜在的 login 启动一个 getty 是不现实的
有一个进程 inetd(与 getty 协同)处理所有的网络登录 当它发现一个进来的网络登录
(即发现某台其他计算机来的新的虚拟连接), 它启动一个新进程来处理那个登录 原来的进
程继续侦听新的登录
更复杂的是 网络登录有多个通讯协议 2 个最重要的协议是 telnet 和 rlogin 除了
登录 还有许多其他虚拟连接可能建立(为 FTP Gopher HTTP 和其他网络服务) 为要侦
听的每种类型的连接提供一个进程不是很有效 因此 只用一个侦听器来识别连接的种类
能启动正确的程序来提供服务 这个侦听器叫 inetd 更多的信息请见 Linux 网络管理指
南
login 干了些什么
login 程序负责认证用户(确认用户名和口令相配) 并建立串行线 启动 shell 建立用
户的初始环境
部分初始化设置是输出文件/etc/motd (每天的短信息)的内容 并检查电子邮件 可以
在用户家目录中产生一个叫.hushlogin 的文件来是上面所述的失效
如果存在文件/etc/nologin 就不允许登录 这个文件一般由 shutdown 及其相关的东
西产生 login 检查这个文件 如果这个文件存在 就拒绝接受登录 如果这个文件确实
存在 login 就会在退出之前 将它的内容输出到终端
login 将所有失败的登录企图登记在系统 log 文件中 (通过 syslog ) 它也登记所有的 r
oot 的登录 这些都对跟踪入侵者有用
当前登录着的用户列在/var/run/utmp 中 这个文件直到系统下次启动或关机前有效
系统刚启动时它被清空 它列出了每个用户和用户使用的终端(或网络连接) 及一些有用的
41 信息 who w 及其他类似的命令查看 utmp 文件得到都有谁登录着
所有成功的登录记录在/var/log/wtmp 中 这个文件将无限制地增大 所以必须有规律
的清除 例如有个每周的 cron 任务来清除它 last 命令浏览 wtmp 文件
utmp 和 wtmp 都是二进制格式 (见 utmp 的 man 页) 不幸的是 没有特殊的程序无
法查看它们
X 和 xdm
META: X implements logins via xdm; also: xterm -ls
存取控制
用户数据库传统上包含在/etc/passwd 文件中 有些系统使用影子口令 shadow pass
words 并把口令移到 /etc/shadow 中 许多计算机的场所可以用 NIS 或其他存储用户数
据库的方法共享帐户 它们可能也自动从中心位置复制数据库到所有其他计算机
用户数据库不仅包含口令 还包括有用户的其他信息 比如其真实姓名 家目录 登录
shell 等 这其他信息需要公用 使所有人都能读 因此口令是加密保存的 这有缺点 任
何人取得加密的口令 可以用不同的加密方法猜试口令 而不用试着真正登录到计算机 影
子口令试图用把口令移动到其他文件的办法避免这种情况 只有 root 能读(口令还是加密保
存的) However, installing shadow passwords later onto a system that did not sup
port them can be difficult.
不管有没有口令 确认系统中的所有口令是好的是很重要的 即不易猜 crack 程序
可用于破解口令 任何可以精确地找到的口令都不是好的口令 同时 crack 可以为入侵者
运行 也可由系统管理员运行以避免坏的口令 好的口令也可以被 passwd 程序强制实现
这样对 CPU 周期来说很有效 因为破解口令需要许多计算
用户组数据库保存在/etc/group 文件中 有影子口令的系统 是/etc/shadow.group
root 通常不能通过更多的终端或网络登录 只能通过列在/etc/securetty 文件中的终端
登录 这使得必须能够物理存取这其中的一个终端 当然也可能通过任何终端用任何拥护登
录 然后使用 su 命令变成 root
Shell 启动
当一个交互的登录 shell 启动时 它自动执行一个或更多预定义的文件 不同的 shell
执行不同的文件 更多的信息见每个 shell 的文档
多数 shell 首先运行一些全局文件 例如 Bourne shell(/bin/sh ) 和它引出执行的/etc
/profile 另外 它们执行用户家目录中的.profile /etc/profile 允许系统管理员建立一个
公用的用户环境 特别是建立 PATH 以包括本地命令目录 另外 .profile 允许用户通过
42 覆盖按照自己的口味客户化环境 如果必要 使用确省环境
Linux 管理员手册(7)--管理用户帐户
本章解释如何产生新用户帐户 如何修改帐户的属性 如何删除帐户 不同的 Linux 系
统有不同的工具实现
什么是帐户?
当一台计算机为多人所用时 通常需要区分用户 例如 使个人文件保持个人化 即使
计算机同时只为一人所用 这也很重要 如多数微机 因此 每个用户给定一个单独的用
户名 这个名字被用于登录
用户除了名字还有更多 一个帐户是所有的文件 资源和属于这个用户的信息 这个属
于暗示是银行 在一个商业系统中 每个帐户通常与一些钱有关 且这些钱依赖于用户使用
系统的多少以不同的速度被花掉 例如 磁盘空间可能有个每 MB 每天的价格 处理时间也
可能有个每秒的价格
创建用户
Linux 核心自己只不过视用户为数字 每个用户用一个单一的整数识别 user id 或 ui
d 因为数字对计算机来说比文本名字处理更快更容易 核心之外的一个单独的数据库给每
个 user id 安排了文本的名字 即用户名 username 这个数据库还包含一些其他信息
要产生一个用户 需要给用户数据库增加关于用户的信息 并给他产生家目录 培训用
户 建立合适的初始化环境也是必要的
多数 Linux distributions 有产生帐号的程序 而且有多个 adduser 和 useradd 是其
中 2 个 可能还有 GUI 的工具 Whatever the program, the result is that there is littl
e if any manual work to be done. Even if the details are many and intricate, these
programs make everything seem trivial. However, section 8.2.4 describes how to d
o it by hand.
/etc/passwd 和其他信息文件
Unix 系统的基本用户数据库是文本文件 /etc/passwd (叫口令文件) 它列出所有有效
用户名及其相关信息 文件的每个用户一行 分为用:分隔的 7 个域
用户名
加密格式的口令
数字的 user id
数字的 group id
全名或帐户的其他说明
43 家目录
登录 shell(登录时运行的程序)
详细的格式说明在 passwd (5)中
系统中的任何用户可以读口令文件 因此他们可以得到其他用户的名字 即任何人也可
以得到口令(第二个域) 口令文件加密了口令 所以利润上说应该没有问题 但是 加密是
可破解的 尤其是口令比较简单时(例如太短 或能在词典中找到的) 因此 口令存在口令
文件中并不好
许多 Linux 系统有影子口令 shadow passwords 文件 这种方法将加密的口令存在另
一个文件/etc/shadow 中 而这个文件只有 root 能读 /etc/passwd 文件在第二个域只有
一个 special marker Any program that needs to verify a user is setuid,那么可以存
取影子口令文件 而只使用口令文件其他域的普通程序 不能得到口令
取得数字的用户和组 ID
多数系统不管数字的用户和组 ID 是什么 但如果使用网络文件系统(NFS) 所有系统
必须使用相同的 uid 和 gid 因为 NFS 也用 uid 认证用户 如果不使用 NFS 可以用帐户产
生工具自动取得的 uid
如果用 NFS 必须用一个机制来同步帐户信息 一个方法是使用 NIS 系统 (见[Kir])
初始环境 /etc/skel
当新用户的家目录产生时 用/etc/skel 目录的文件初始化 系统管理员可以产生/etc/s
kel 里的文件给用户提供一个好的缺省环境 例如 产生一个/etc/skel/.profile 设定 EDITO
R 环境变量 提供新用户一个友善的编辑器
然而 通常最好保持/etc/skel 尽量小 因为 it will be next to impossible to update
existing users' files. 例如 如果友善的编辑器的名字改变了 所有现存用户必须编辑他们
的.profile 系统管理员可以用一个 script 自动完成 但仍可能破坏某个用户的文件
只要可能 最好把全局设置放在全局文件中 如/etc/profile 这样可以升级 而避免
破坏用户自己的设置
手工创建用户
按以下步骤手工创建新用户
用 vipw (8)编辑/etc/passwd 为新用户增加一个新行 注意语法 不要用编辑器直
接编辑! vipw 锁定了这个文件 其他命令这时不能更新它 设定口令域为"*" 这样不能登
录
44 类似 如果要创建新组 用 vigr 编辑/etc/group
用 mkdir 产生用户的家目录
将/etc/skel 中的文件复制到新的家目录中
用 chown 和 chmod 修改所有者和权限 -R 选项是最有用的 The correct permis
sions vary a little from one site to another, but usually the following commands do
the right thing:
cd /home/newusername
chown -R username.group .
chmod -R go=u,go-w .
chmod go= .
用 passwd (1)设定口令
最后一步设定完口令 这个帐户就能用了 不应该在其他所有事做完之前设定口令 否
则这个用户可能不允许登录 while you're still copying the files.
有时需要产生不为任何人使用的虚假(dummy)帐户 例如 建立一个匿名 FTP 服务器(这
样任何人都可以从它下载文件 无须得到一个帐户) 必须产生一个叫 ftp 的帐户 这种情况
通常无须随后一步的口令设定 而且 最好不设 这样没有人可以使用这个帐户 除非先变
成 root 因为 root 可以变成任何用户
改变用户属性
有几个改变帐户不同属性的命令(即/etc/passwd 中的相关域)
chfn
改变全名域
chsh
改变登录 shell
passwd
改变口令
超级用户可以用这些口令改变任何帐户的属性 普通用户只能改变自己帐户的属性 有
时可能有必要使这些命令对普通用户不可用(用 chmod ) 例如在一个有许多新手的环境中
其他任务需要手工完成 例如改变用户名 需要编辑/etc/passwd (记住 用 vipw )
同样 要增加或删除用户 to more groups 需要编辑/etc/group (用 vigr ) 这种任务较少
需要小心从事 例如 改变了用户名 电子邮件就不能到达这个用户 除非你同时产生一个
邮件别名
45 删除用户
要删除用户 必须先删除他的所有文件 然后从/etc/passwd 和/etc/group 删除相关的
行 有些 Linux distributions 带特定的命令 看看有没有 deluser 或 userdel 然而 手工
删除也很简单
临时禁止一个用户
有时需要临时禁止一个用户 而不删除它 例如用户没有付费 或系统管理员怀疑黑客
得到了某个帐户的口令
禁止一个用户的最好方法是将它的 shell 变到一个特定的只打印出一条信息的程序 用
这种方法 任何想登录此帐户的人将无法登录 并得知原因 该信息可以告诉用户与系统管
理员联系 以处理任何问题
也可以改变用户名或口令 但这样用户不知道怎么回事 Confused users mean mo
re work.
产生上述特定程序的一个简单方法是写"tail scripts":
#!/usr/bin/tail +2
This account has been closed due to a security breach.
Please call 555-1234 and wait for the men in black to arrive.
前 2 个字符("#!")告诉核心本行的其他部分是解释本文件要运行的命令 这样 tail 命令将输
出处理第一行外的所有东西到标准输出
如果怀疑 billg 是个安全缺口 系统管理员可以这样做
# chsh -s /usr/local/lib/no-login/security billg
# su - tester
This account has been closed due to a security breach.
Please call 555-1234 and wait for the men in black to arrive.
#
su 的目的是此时改变是否工作
Tail scripts 应该放在一个分离的目录中 这样它们的名字不会干扰普通用户的命令
Linux 管理员手册(8)--备份
硬件不肯定是可靠的
软件肯定是不可靠的
人不肯定是不可靠的
而自然肯定是可靠的
本张说明为什么 如何 何时要做备份 及如何回存备份的东西
46 备份的重要
数据是有价值的 重新产生它需要你花费时间和努力 并且要花费金钱或至少伤心和眼
泪 有时甚至不可能重新产生 例如一些实验结果 由于数据是一种投资 你必须保护它
并采取措施避免丢失
丢失数据一般有 4 个原因 硬件失败 软件曲线 人为因素或自然灾害 虽然现代硬
件已经相当可靠 但仍可能自然损坏 存储数据最决定性的硬件是硬盘 它依赖微小的磁区
在充满电噪声的世界上保存数据 现代软件依然不可靠 一个真正可靠的程序是理想 罕见
的 而不是规律 人更不可靠 他们很容易犯错误 甚至为某种目的恶意地破坏数据 自然
可能不是邪恶的 但也可能造成破坏 一切的一切 希望什么都正常 完美几乎是不可能的
备份是保护数据投资的方法 有数据的多个拷贝 就不怕某个损坏(所需做的仅仅是从
备份中恢复丢失的数据)
正确的备份是很重要的 正如物理世界中任何东西都与其他相关 备份也迟早会失效
好的备份确保有效 你不希望你的备份无效 如果你的备份又坏了 这将雪上加霜 如果
你只有一个备份 它可能根本是坏的 只留下你和硬盘中冒烟的灰烬 或者当你恢复时
发现忘了备份一些重要的东西 比如 15000 个用户站点的用户数据库 Best of all, all y
our backups might be working perfectly, but the last known tape drive reading the
kind of tapes you used was the one that now has a bucketful of water in it.
When it comes to backups, paranoia is in the job description.
选择备份介质
备份所需的最重要的决定是选择备份介质 需要考虑成本 可靠性 速度 可得到 可
用性
成本是很重要的 因为你的数据可能需要多个存储 多个备份 便宜的介质可以用很多
可靠性是最重要的 因为坏的备份会雪上加霜 备份介质必须能存储数据多年而不损坏
作为备份介质 使用方法影响可靠性 硬盘一般是很可靠的 但作为备份介质并非很可靠
如果它和备份源在同一计算机里的话
速度通常不太重要 如果备份可以非交互地完成 备份花 2 个小时无所谓 无须监督
多长时间都没有关系 另一方面 if the backup can't be done when the computer wou
ld otherwise be idle, 那么速度也是个问题
可得到是明显必要的 因为你无法使用不存在的备份介质 不太明显的是要在将来还能
得到这种介质 并且能在其他计算机上使用 否则灾害之后 你可能无法恢复你的备份
可用性是决定备份周期的主要因素 备份越容易使用越好 备份介质不能难以使用
47 一般用软盘和磁带 软盘很便宜 还算可靠 不太快 很容易得到 但数据量大时不容
易使用 磁带也很便宜 还算可靠 还算快 很容易得到 而且 依赖于磁带的容量 使用
很轻松
还有其他选择 但通常可得性不好 但如果这不成问题 有时也不错 例如 磁光盘同
时具有软盘(随机存取 可以快速地恢复单个文件)和磁带(大容量)的优点
选择备份工具
备份有很多工具 传统的 UNIX 备份工具是 tar cpio 和 dump 另外 还可以使用
大量第三方软件包(包括 freeware 和商业版) 备份介质的选择可能影响工具的选择
tar 和 cpio 类似 从备份来看二者基本等效 都能将文件存到磁带并取出文件 都能
使用几乎所有介质 因为核心设备驱动处理低级设备操作 对用户级程序看来所有设备都差
不多 有写 Unix 版本的 tar 和 cpio 对不是普通文件可能有问题(符号连接 设备文件 极
长路径名的文件等等) 但 Linux 的能正确处理所有文件
dump 不同 它直接读文件系统 而不通过文件系统 It is also written specifically
for backups; tar 和 cpio are really for archiving files, although they work for backup
s as well.
直接读文件系统有些优点 它可能不考虑 time stamps 备份所有文件 对于 tar 和 cpi
o 必须先将文件系统只读安装 直接读文件系统更有效 如果所有东西都要备份 因为
它使磁头移动最少 它的主要缺点是每个文件系统种类需要特定的备份程序 Linux 的 du
mp 程序只理解 ext2 文件系统
dump 也直接支持备份级(下面讨论) 对 tar 和 cpio 这必须用其他工具实现
第三方备份工具的比较超出了本书的范围 Linux Software Map 列出了许多 freeware
的
简单备份
一个简单的备份方案是一次备份所有东西 然后备份上次备份后改变的所有东西 第一
个备份叫全备份 full backup 后来的叫 i 增量备份 ncremental backups 全备份比增量备
份费时费力 因为有更多的东西写到磁带 而且全备份可能不能放如一盘磁带中(更别说软
盘了) 回存增量备份比全备份可能要花更多的时间 备份可以这样优化 就是自上次全备
份以后 总用增量备份保存所有改过的文件 这样 备份可能需要多一些的工作 但你只需
回存一个全备份和一个增量备份
如果有 6 盘磁带想每天备份 可以用磁带 1 做第一个全备份(比如在星期五) 用磁带 2
-5 做增量备份(周一到周四) 然后用磁带 6 做新的全备份(第二个周五) 然后再用磁带 2-5
做增量备份 在做完新的全备份之前不要覆盖旧的全备份(磁带 1) 一面在做全备份的时候
出现问题 有了新的全备份磁带 6 以后 最好在另一个地方保存磁带 1 这样如果有一个全
48 备份磁带在火灾中损失了 还能有一个 当再做下一个全备份是 再用磁带 1 而保存磁带 6
如果你有多于 6 盘磁带 可以用多的做全备份 每次做全备份 应该使用最老的磁带
这样你会有最近几周的全备份 对你如果想找到一个现在已经删除的就文件 或一个文件的
旧版本很有用
用 tar 备份
一个全备份可以很容易地用 tar 实现
# tar -create -file /dev/ftape /usr/src
tar: Removing leading / from absolute path names in the archive
#
上面的例子使用 GNU 版本的 tar 及其长选项名 传统版本的 tar 只理解单字符选项
GNU 版还能处理一盘磁带或一张磁盘不能容纳的备份 及很长的路径名 这不是所有传统
的版本能作到的 (Linux 只使用 GNU tar )
如果你的备份一盘磁带不能容纳 你需要使用-multi-volume (-M)选项
# tar -cMf /dev/fd0H1440 /usr/src
tar: Removing leading / from absolute path names in the archive
Prepare volume #2 for /dev/fd0H1440 and hit return:
#
注意开始备份前要格式化所有软盘 或在 tar 需要新软盘时用另一个虚拟控制台或虚拟
终端格式化它
备份完后 应该检查它是否完好 用-compare (-d)选项
# tar -compare -verbose -f /dev/ftape
usr/src/
usr/src/linux
usr/src/linux-1.2.10-includes/
....
#
失败的备份检查意味着如果你丢失了原始数据 备份也无法恢复
增量备份可用带-newer (-N)选项的 tar 来实现
# tar -create -newer '8 Sep 1995' -file /dev/ftape /usr/src -verbose
tar: Removing leading / from absolute path names in the archive
usr/src/
usr/src/linux-1.2.10-includes/
49 usr/src/linux-1.2.10-includes/include/
usr/src/linux-1.2.10-includes/include/linux/
usr/src/linux-1.2.10-includes/include/linux/modules/
usr/src/linux-1.2.10-includes/include/asm-generic/
usr/src/linux-1.2.10-includes/include/asm-i386/
usr/src/linux-1.2.10-includes/include/asm-mips/
usr/src/linux-1.2.10-includes/include/asm-alpha/
usr/src/linux-1.2.10-includes/include/asm-m68k/
usr/src/linux-1.2.10-includes/include/asm-sparc/
usr/src/patch-1.2.11.gz
#
不幸的是 tar 不能知道一个文件的 i 节点信息变化 例如 文件的权限位变化 或文
件名变化 这可用 find 命令和比较当前文件系统状态和先前备份的文件列表 用于此的 Sc
ripts 和程序可以在 Linux FTP 站点上找到
用 tar 回存
tar 的-extract (-x)选项展开文件
# tar -extract -same-permissions -verbose -file /dev/fd0H1440
usr/src/
usr/src/linux
usr/src/linux-1.2.10-includes/
usr/src/linux-1.2.10-includes/include/
usr/src/linux-1.2.10-includes/include/linux/
usr/src/linux-1.2.10-includes/include/linux/hdreg.h
usr/src/linux-1.2.10-includes/include/linux/kernel.h
...
#
也可以用命令行只展开特定的文件和目录(及其中的文件和子目录)
# tar xpvf /dev/fd0H1440 usr/src/linux-1.2.10-includes/include/linux/hdreg.h
usr/src/linux-1.2.10-includes/include/linux/hdreg.h
#
用-list (-t)选项看一个备份卷中有什么文件
# tar -list -file /dev/fd0H1440
usr/src/
usr/src/linux
usr/src/linux-1.2.10-includes/
usr/src/linux-1.2.10-includes/include/
usr/src/linux-1.2.10-includes/include/linux/
usr/src/linux-1.2.10-includes/include/linux/hdreg.h
usr/src/linux-1.2.10-includes/include/linux/kernel.h
50 ...
#
注意 tar 永远是顺序读一个备份卷 因此大的卷会很慢 使用磁带机或其他顺序介质时
不可能使用随机存取数据库技术
tar 不处理删除文件属性 如果你需要从一个全备份和一个增量备份恢复一个文件系统 并
且 2 个备份之间你删除了一个文件 当你恢复完后 这个文件又存在了 如果这个文件包
含应该删除的敏感数据 这是个大问题
多级备份
上面的章节概述了简单备份的方法 对个人使用或小的站点使用 对于多数重负荷的使
用 多级备份更适用
简单备份有 2 个备份级 全备份和增量备份 通常可以有任意数量的备份级 全备份
是 0 级 不同级别的增量备份是 1 2 3...级 每个增量备份级备份同一或上一级别的上次
备份后改变的所有东西
这样多的目的是更便宜地允许更长的备份历史 backup history 在前面的例子中 备份
历史追溯到上一个全备份 可以增多磁带来扩展备份历史 但每个新磁带扩展一周 这样可
能太贵 更长的备份历史是有用的 因为删除或损坏的文件可能长时间未被发现 即使不是
一个文件的最新版本 也比没有好
多级备份可以更便宜地扩展备份历史 例如 如果你有 10 盘磁带 可用磁带 1 和 2 做
月备份(每月的第一个周五) 磁带 3-6 做周备份(其他周五 因为每月最多可能有 5 个周五
因此需要 4 盘磁带) 磁带 7-10 做日备份(周一到周四) 只增加了 4 盘磁带 就将 2 周的备
份历史扩展到 2 个月 诚然 我们无法恢复这 2 个月中每个文件的所有版本 但这样恢复
的经常是足够好了
备份级可使文件系统恢复用最少的时间 如果你有许多只是单调增长级别数的增量备
份 要恢复整个文件系统 你需要回存所有备份 而如果级别数不是单调增长 可以减少备
份和回存的数目
为了将回存需要的磁带数据减至最小 可以用小的级别做每个增量磁带 然而 这样做
每个增量备份的时间会增加(每个备份拷贝了上次全备份后改变的所有东西) 一个好的方案
建议在 dump man 页中给出 并在表 9.2 中说明 Use the following succession of ba
ckup levels: 3, 2, 5, 4, 7, 6, 9, 8, 9... 这使备份和回存所用的时间保持较少 The mo
st you have to backup is two day's worth of work. 恢复所需磁带数有赖于全备份的间
隔 但它比简单的方案少
一个好的方案降低了工作量 并能追寻更多的东西 You must decide if it is worth
it.
dump 对备份级有内置的支持 而 tar 和 cpio 则必须用 shell scripts 实现
51 备份什么?
你可能想尽多备份 主要的例外是容易重安装的软件 但即使是它们 也有配置文件
对备份很重要 以免对这些软件全部重新配置 另一个主要的例外是/proc 文件系统 因为
他们只包含通常由核心自动产生的数据 备份它们绝不是个好主意 特别是/proc/kcore 文
件更是不必要 因为它只是你当前物理内存的映象 而且很大
Gray areas include the news spool, log files, and many other things in /var .
你必须决定重点考虑什么
备份最明显的是用户文件(/home )和系统配置文件(/etc 但还可能有散落在文件系统
其他地方的其他东西
压缩备份
备份占用大量空间 要花费大量金钱 为了降低空间需求 备份可以压缩 有几种方法
有些程序内置支持压缩 例如 GNU tar 的-gzip (-z)选项 通过管道(pipe) 在写到备份介
质前 先用 gzip 压缩程序压缩
不幸的是 压缩备份可能导致问题 由于压缩工作的原理 如果一个 bit 错误 可能导
致所有其他压缩数据不可用 有些备份程序内置错误校正 但没有办法处理大量的错误 就
是说 如果用 GNU tar 压缩备份 一个单独的错误回导致整个备份丢失 备份必须可靠
这样的压缩方法不好
还有一个方法是单独压缩每个文件 这也回导致一个文件的丢失 但不会影响其他文件
丢失的文件可能已经因为什么原因损坏 因此这种情况比不使用压缩差不了多少 afio 程
序(cpio 的一个变种)可以这样
压缩需要时间 which may make the backup program unable to write data fast e
nough for a tape drive. 这可以靠输出缓冲来避免(如果备份程序足够智能 可以内置 否
则可以通过其他程序) but even that might not work well enough. 这只会在慢的计算
机上是个问题
Linux 管理员手册(9)--Keeping Time
本章说明 Linux 系统如何 keeps time 及需要做什么来避免发生问题 通常 你无须
对时间做什么 但理解它会更好
时区
时间测量基于最规则的自然现象 如地球转动导致的昼夜更替 昼夜总时间是恒定的
但昼夜分别的长度是变化的 一个简单的常数是正午
正午是白天太阳在最高点的时间 由于地球是圆的 不同地方正午发生在不同的时间
52 这引出了本地时 local time 的概念
硬件时钟和软件时钟
个人计算机有一个电池驱动的硬件时钟 电池保证始终在计算机没电的时候依然能工
作 硬件始终能从 BIOS 设置屏或操作系统的别的地方进行设置
Linux 核心独立于硬件始终跟踪时间 启动时 Linux 根据硬件时钟设置自己的时钟
此后 2 个始终相互独立运行 因为查看硬件始终慢而复杂 因此 Linux 管理自己的时钟
核心始终一直显示通用时间 这样 核心无须知道时区 高可靠的简单结果使更新时区
信息更简单 每个进程自己处理时区转换(使用时区包部分里的标准工具)
硬件始终可以是本地时间或通用时间 通常用通用时间更好 因为这样你无须在夏时制
开始或结束时改变硬件时钟 (UTC does not have DST) 不幸的是 有些 PC 操作系统
包括 MSDOS Windows OS/2 都假设硬件时钟是本地时间 Linux 可处理 2 种方式 但
如果硬件时钟显示本地时间 那么必须在夏时制开始或结束时(否则就不能显示本地时间)
显示和设置时钟
在 Debian 系统中 系统时区由符号连接/etc/localtime 决定 连接指向描述本地时区的
时区数据文件 时区数据文件存在/usr/lib/zoneinfo 中 其他 Linux distributions 可能不同
用户可以用设置 TZ 环境变量来改变他的私人时区 如果不设置 就假定是系统时区
TZ 变量的语法在 tzset (3)man 页中说明
date 命令显示当前日期和时间 例如
$ date
Sun Jul 14 21:53:41 EET DST 1996
$
That time is Sunday, 14th of July, 1996, at about ten before ten at the evening, in
the time zone called ``EET DST'' (which might be East European Daylight Savings
Time). date 也可用于显示通用时间
$ date -u
Sun Jul 14 18:53:42 UTC 1996
$
date 也可用于设置核心的软件始终
# date 07142157
Sun Jul 14 21:57:00 EET DST 1996
# date
Sun Jul 14 21:57:02 EET DST 1996
#
53 更详细的见 date man 页--syntax is a bit arcane. 只有 root 能设置时间 虽然每个用
户可以有自己的时区 但时钟对每个人都是一样的
date 只显示或设置软件时钟 clock 命令同步硬件和软件时钟 用于系统启动时读取
硬件时钟和设置软件时钟 如果两个时钟都需要设置 则先用 date 设置软件时钟 然后用
clock -w 设置硬件时钟
clock 的-u 告诉它硬件时钟是通用时间 必须正确使用-u 选项 否则计算机将困惑到
底是什么时间
时钟必须小心改变 Unix 系统的许多部分要求时钟工作正常 例如 cron 守侯程序
周期地运行命令 如果改变时钟 它可能迷惑它是否该运行命令 On one early Unix sy
stem, someone set the clock twenty years into the future, and cron wanted to run
all the periodic commands for twenty years all at once. 现在版本的 cron 可以正确处
理 但仍然要小心 大的前后跳跃比小的更危险
当时钟错误时
Linux 软件时钟不会始终精确 PC 硬件产生的时间中断周期地运行软件时钟 如果系
统运行了太多进程 服务于时间中断需要花费太多的时间 软件时钟启动靠后 硬件时钟独
立运行并通常更精确 如果你的系统经常启动(比如不是服务器的多数系统) 那么通常时间
很精确
如果需要调整硬件时钟 通常最简单的是重启动 进入 BIOS 设定屏幕 并在那里完成
这避免了改变系统时间可能导致的所有问题 如果不能通过 BIOS 用 date 和 clock 设定
新时间(以此顺序) 但如果系统有部分工作不正常 必须准备重启动
连网的计算机(即使是通过 modem)能通过与其他计算机时间比较来自动检查自己的时
钟 如果知道保持很精确时间的其他计算机 那么 2 台计算机都将保持精确的时间 这可
以使用 rdate 和 netdate 命令来完成 2 个命令都检查远程的计算机(netdate 可处理多台
远程计算机) 来同步本地计算机的时间 有规律地运行这样一个程序 你的计算机就可以
保持与远程计算机一样精确的时间
测量孔(Measuring Holes)
本附录包括用于测量文件系统中潜在的孔的程序的有趣的部分 The source distribut
ion of the book contains the full source code(sag/measure-holes/measure-holes.c).
int process(FILE *f, char *filename) {
static char *buf = NULL;
static long prev_block_size = -1;
long zeroes;
char *p;
if (buf == NULL || prev_block_size != block_size) {
54 free(buf);
buf = xmalloc(block_size + 1);
buf[block_size] = 1;
prev_block_size = block_size;
}
zeroes = 0;
while (fread(buf, block_size, 1, f) == 1) {
for (p = buf; *p == '\0'; )
++p;
if (p == buf+block_size)
zeroes += block_size;
}
if (zeroes > 0)
printf("%ld %s\n", zeroes, filename);
if (ferror(f)) {
errormsg(0, -1, "read failed for `%s'", filename);
return -1;
}
return 0;
}
相关栏目:
您当前位置:
返回顶部