--- title: 第 4 章 UNIX 基础 part: 部分 I. 起步 prev: books/handbook/install next: books/handbook/ports showBookMenu: true weight: 6 params: path: "/books/handbook/basics/" --- [[basics]] = UNIX 基础 :doctype: book :toc: macro :toclevels: 1 :icons: font :sectnums: :sectnumlevels: 6 :sectnumoffset: 4 :partnums: :source-highlighter: rouge :experimental: :images-path: books/handbook/basics/ ifdef::env-beastie[] ifdef::backend-html5[] :imagesdir: ../../../../images/{images-path} endif::[] ifndef::book[] include::shared/authors.adoc[] include::shared/mirrors.adoc[] include::shared/releases.adoc[] include::shared/attributes/attributes-{{% lang %}}.adoc[] include::shared/{{% lang %}}/teams.adoc[] include::shared/{{% lang %}}/mailing-lists.adoc[] include::shared/{{% lang %}}/urls.adoc[] toc::[] endif::[] ifdef::backend-pdf,backend-epub3[] include::../../../../../shared/asciidoctor.adoc[] endif::[] endif::[] ifndef::env-beastie[] toc::[] include::../../../../../shared/asciidoctor.adoc[] endif::[] [[basics-synopsis]] == 概述 下列章节的命令和功能适用于FreeBSD操作系统。 同时这里许多内容和一些 类-UNIX(R) 操作系统相关。 假如您已经熟悉这些内容可跳过不阅读。 假如您是FreeBSD新手, 那您应该认真详细地从头到尾读一遍这些章节。 读取这些内容,您将了解: * 怎样在FreeBSD使用 "虚拟控制台"。 * 在 UNIX(R) 中文件权限如何运作, 以及理解 FreeBSD 中的文件标志。 * FreeBSD 默认文件系统的架构。 * FreeBSD磁盘架构。 * 怎样挂接或卸下文件系统。 * 什么是进程、守护进程、信号。 * 什么是shell,应当怎样去改变登录进入的默认环境。 * 怎样使用基本的文本编辑器。 * 什么是设备,什么是设备节点。 * FreeBSD 下,使用的是什么可执行文件格式。 * 怎样使用 man 手册并取得更多资讯。 [[consoles]] == 虚拟控制台和终端 可以用多种不同的方式使用 FreeBSD, 在文本终端输入命令是其中之一。 通过使用这种方式, 您可以容易地使用 FreeBSD 来获得 UNIX(R) 操作系统的灵活而强大的功能。 这一节将介绍 "终端" 和 "控制台", 以及如何在 FreeBSD 中使用它们。 [[consoles-intro]] === 控制台 假如您没有设置 FreeBSD 在启动期间开启图形登录界面, 那么系统将在引导和启动脚本正确运行完成后,给您一个登录的提示。 您会看到类似这样的界面: [source,shell] .... Additional ABI support:. Local package initialization:. Additional TCP options:. Fri Sep 20 13:01:06 EEST 2002 FreeBSD/i386 (pc3.example.org) (ttyv0) login: .... 这些信息可能和您的系统稍微有点不同,但不会有很大差别。 最后两行是我们感兴趣的, 理解这一行: [.programlisting] .... FreeBSD/i386 (pc3.example.org) (ttyv0) .... 这一行是您刚才启动的系统信息其中一块, 您所看到的是一个"FreeBSD"控制台, 运行在一个Intel或兼容的x86体系架构上面。 这台计算机的名字 (每台 UNIX(R) 计算机都有自己的名字) 叫 `pc3.example.org`, 就是现在这个系统控制台-这个 [.filename]#ttyv0# 终端的样子。 在最后,最后一行一直保持这样: [.programlisting] .... login: .... 这里, 您将可以输入用户名 "username" 并登录到 FreeBSD 系统中。 接下来的一节, 将介绍如何登录系统。 [[consoles-login]] === 进入FreeBSD FreeBSD是一个多用户多任务的系统, 换句话来说就是一个系统中可以容纳许多不同的用户, 而这些用户都可以同时在这台机器中运行大量的程序。 每一个多用户系统都必须在某方面去区分 "user", 在 FreeBSD 里 (以及 类-UNIX(R) 操作系统), 完成这方面工作是有必要的, 因而, 每位使用者在运行程序之前都必须首先 "登录", 而每位用户都有与之对应的用户名 ("username") 和密码 ("password")。 FreeBSD 会在用户进入之前作出询问这两项信息。 当 FreeBSD 引导并运行完启动脚本之后, , 它会给出一个提示, 并要求输入有效的用户名: [source,shell] .... login: .... 举个例子更容易理解,我们假设您的用户名叫 `john`。 在提示符下输入 `john` 并按 kbd:[Enter], 此时您应该看到这个提示 "password": [source,shell] .... login: john Password: .... 现在输入 ``john``的密码并按下 kbd:[Enter]。 输入密码时是 _不回显的!_ 不必为此担心, 这样做是出于安全考虑。 假如您输入的密码是正确的, 这时你应该已进入 FreeBSD, 并可以开始尝试可用的命令了。 您应该看见 MOTD 或者出现一个命令提示符 (`#`、`$` 或 `%` 字符). 这表明您已成功登录进入FreeBSD。 [[consoles-virtual]] === 多个控制台 在一个控制台运行 UNIX(R) 命令虽说很好, 但 FreeBSD 具有一次运行 多个程序的能力。 仅使用一个控制台只会浪费 FreeBSD 同时运行多任务的能力。 而 "虚拟控制台" 在这方面发挥强大的功能。 FreeBSD 能配置出满足您不同需求的虚拟控制台, 在键盘上您用一组键就能从各个虚拟控制台之间切换。 各个控制台有自己的传输通道, 当您在各个控制台切换时 FreeBSD 会切换到合适的键盘传输通道和显示器传输通道。 FreeBSD 各个控制台之间可利用特殊组键切换并保留原有控制台 ,您可这样做: kbd:[Alt+F1], kbd:[Alt+F2], 一直到 kbd:[Alt+F8] 在FreeBSD里切换到其中一个虚拟控制台。 同样地, 您正在从其中某个控制台切换到另一个控制台的时候, FreeBSD 会保存正在使用和恢复将要使用屏幕传输通道。 这种结果形成一种 "错觉", 您拥有许多"虚拟"屏幕和键盘可以输入很多的命令。 这些程序需要在一个虚拟控制台不能停止运行而又不需要观察它, 它继续运行而您可以切换到其他的虚拟控制台。 [[consoles-ttys]] === [.filename]##/etc/ttys##文件 FreeBSD 虚拟控制台的默认配置为8个,但并不是硬性设置, 您可以很容易设置虚拟控制台的个数增多或减少。 虚拟控制台的的编号和设置在 [.filename]#/etc/ttys# 文件里。 您可以使用 [.filename]#/etc/ttys# 文件在 FreeBSD 下配置虚拟控制台。 文件里每一未加注释的行都能设置一个终端或虚拟控制台 (当行里含有 `#` 这个字符时不能使用) 。 FreeBSD 默认配置是配置出9个虚拟控制台而只能启动8个, 以下这些行是 `ttyv` 一起启动: [.programlisting] .... # name getty type status comments # ttyv0 "/usr/libexec/getty Pc" cons25 on secure # Virtual terminals ttyv1 "/usr/libexec/getty Pc" cons25 on secure ttyv2 "/usr/libexec/getty Pc" cons25 on secure ttyv3 "/usr/libexec/getty Pc" cons25 on secure ttyv4 "/usr/libexec/getty Pc" cons25 on secure ttyv5 "/usr/libexec/getty Pc" cons25 on secure ttyv6 "/usr/libexec/getty Pc" cons25 on secure ttyv7 "/usr/libexec/getty Pc" cons25 on secure ttyv8 "/usr/X11R6/bin/xdm -nodaemon" xterm off secure .... 如果要了解这个文件中每一列的详细介绍, 以及虚拟控制台上所能使用的配置, 请参考联机手册 man:ttys[5]。 [[consoles-singleuser]] === 单用户模式的控制台 关于 "单用户模式" 详细介绍在 crossref:boot[boot-singleuser,单用户模式] 这里可以找到。 当您运行单用户模式时只能使用一个控制台, 没有多个虚拟控制台可使用。 单用户模式的控制台同也可以在 [.filename]#/etc/ttys# 文件设置, 可在这行找到要启动的``控制台``: [.programlisting] .... # name getty type status comments # # If console is marked "insecure", then init will ask for the root password # when going to single-user mode. console none unknown off secure .... [NOTE] ==== 这个 `console` 已经注释掉, 您可编辑这行把 `secure` 改为 `insecure`。 这样, 当用单用户进入 FreeBSD 时, 它仍然要求提供 `root` 用户的密码。 _在把这个选项改为 ``insecure``_ 的时候一定要小心, 如果您忘记了 ``root``用户的密码, 进入单用户会有点麻烦。 尽管仍然能进入单用户模式, 但如果您不熟悉它就会非常令人头疼。 ==== [[consoles-vidcontrol]] === 改变控制台的显示模式 FreeBSD 控制台默认的显示模式可以被调整为 1024x768, 1280x1024, 或者任何你的显卡芯片和显示器所支持的其他尺寸。 要使用一个不同的显示模式, 你必须首先重新编译内核并包含以下2个选项: [.programlisting] .... options VESA options SC_PIXEL_MODE .... 在内核用这2个选项编译完成后,你就可以使用 man:vidcontrol[1] 工具来测定你的硬件支持何种显示模式了。 以 root 身份在控制台键入以下命令来获得一份所支持的显示模式列表。 [source,shell] .... # vidcontrol -i mode .... 这个命令的输出是一份你的硬件所支持的显示模式列表。 你可以在以 root 身份在控制台上键入 man:vidcontrol[1] 命令来改变显示模式: [source,shell] .... # vidcontrol MODE_279 .... 如果你对于新的显示模式满意,那么可以把它加入到 [.filename]#/etc/rc.conf# 使机器在每次启动的时候都能生效, 我们使用了上一个例子中的模式: [.programlisting] .... allscreens_flags="MODE_279" .... [[permissions]] == 权限 FreeBSD,是 BSD UNIX(R) 的延续, 并基于几个关键的 UNIX(R) 观念。 从一开始就多处提到 FreeBSD 是一个多用户的操作系统, 它能分别处理几个同时工作的用户所分配的毫无关联任务。 并负责为每位用户的硬件设备、 外设、 内存和 CPU 处理时间作出合理安排。 因为系统有能力支持多用户, 在每一方面系统都会作出谁能读、 写和执行的资源权力限制。 这点权限以三个八位元的方式储存着, 一个是表示文件所属者, 一个是表示文件所属群组, 一个是表示其他人。 这些数字以下列方式表示: [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | 数值 | 权限 | 目录列表 |0 |不能读,不能写,不能执行 |`---` |1 |不能读,不能写,可执行 |`--x` |2 |不能读,可写,不能执行 |`-w-` |3 |不能读,可写,可执行 |`-wx` |4 |可读,不能写,不能执行 |`r--` |5 |可读,不能写,可执行 |`r-x` |6 |可读,可写,不能执行 |`rw-` |7 |可读,可写,可执行 |`rwx` |=== 使用命令的 `-l` (man:ls[1]) 参数可以显示出文件的所属者、 所属组和其他人等属性。 请看以下的例子: [source,shell] .... % ls -l total 530 -rw-r--r-- 1 root wheel 512 Sep 5 12:31 myfile -rw-r--r-- 1 root wheel 512 Sep 5 12:31 otherfile -rw-r--r-- 1 root wheel 7680 Sep 5 12:31 email.txt ... .... 使用 `ls -l` 在每行的开始出现了: [source,shell] .... -rw-r--r-- .... 从左边起的第一个字,告诉我们这个文件是一怎样的文件: 普通文件?目录?特殊设备?socket?或是设备文件? 在这个例子, `-` 表示一个普通文件。 接下来三个字是 `rw-` 是文件拥有者的权限。 再接下来的三个字是 `r--` 是文件所属群组的权限。 最後三个字是 `r--` 是其他人的权限。 以这一个文件为例,他的权限设定是拥有者可以读写这个文件、群组可以读取、 其他使用者也能读取这个文件。 根据上面的表格, 用数字表示这个文件其三部分的权限应该是 `644`。 这样很好,但系统怎样对设备进行权限控制的? 事实上 FreeBSD 将大部份硬件设备当作一个文件看待, 用程序能打开、读取、写入数据就如其他的文件一样。 而设备文件放在 [.filename]#/dev# 目录。 目录也视为一种文件,也有读取、写入、执行的权限。 但目录的执行权限意义并不与普通文件相同, 实际上执行权限是进入权限。 当一个目录是被标示可以执行的时, 表示可以进入它, 或者换言之, 利用 "cd" (改变当前目录) 进入它。 此外, 这也表示有权进入目录的用户, 可以访问其下的已知名字的文件 (当然目录下的文件也受到访问限制)。 详细方面,想读取一个目录的列表就必须设为可读权限, 同时想删除一个已知的文件,就必须把目录下这个文件设为可写 _和_ 执行权限。 还有更多权限设定, 但是他们大多用在特殊状况下如一个setuid的执行文件和粘贴性目录, 如果想要得知有关文件权限和如何设定的更多资讯,请看手册man:chmod[1]。 === 权限的符号化表示 权限符号,某些时候就是指符号表达式, 使用八进制的字符给目录或文件分配权限。 权限符号的使用语法是 (谁) (作用) (权限)。 看看下列数值的在那些地方所起什么样的作用: [.informaltable] [cols="1,1,1", frame="none", options="header"] |=== | 选项 | 字母 | 介绍 |(谁) |u |用户 |(谁) |g |所属群体 |(谁) |o |其他人 |(谁) |a |所有人 ("全部") |(作用) |+ |增加权限 |(作用) |- |减少权限 |(作用) |= |确定权限 |(权限) |r |可读 |(权限) |w |可写 |(权限) |x |执行 |(权限) |t |粘贴位 |(权限) |s |设置 UID 或 GID |=== 这些数值 man:chmod[1] 以习惯标定的。 举个例子,用以下命令阻止其他人访问 __FILE__文件: [source,shell] .... % chmod go= FILE .... 如果需要对文件一次进行多项变动, 则可用逗号分开, 在下面的例子中, 将去掉 _FILE_ 文件的群体和 "全体其他用户" 可写权限, 并为所有人增加可执行权限: [source,shell] .... % chmod go-w,a+x FILE .... === FreeBSD 文件标志 在前面所介绍的文件权限的基础之上, FreeBSD 还支持使用 "文件标志"。 这些标志为文件提供了进一步的安全控制机制, 但这些控制并不适用于目录。 这些文件标志提供了针对文件的进一步控制, 帮助确保即使是 `root` 用户也无法删除或修改文件。 文件标志可以通过使用 man:chflags[1] 工具来修改, 其用户界面很简单。 例如, 要在文件 [.filename]#file1# 上应用系统禁删标志, 应使用下述命令: [source,shell] .... # chflags sunlink file1 .... 要禁用系统禁删标志, 只需在前述命令中的 `sunlink` 标志前加 "no"。 例如: [source,shell] .... # chflags nosunlink file1 .... 要显示文件上的标志, 应使用命令 man:ls[1] 的 `-lo` 参数: [source,shell] .... # ls -lo file1 .... 输出结果应类似于: [.programlisting] .... -rw-r--r-- 1 trhodes trhodes sunlnk 0 Mar 1 05:54 file1 .... 许多标志只可以由 `root` 用户来增加, 而另一些, 则可以由文件的所有者来增加。 建议管理员仔细阅读 man:chflags[1] 和 man:chflags[2] 联机手册, 以对其加深理解。 === setuid、 setgid 和 sticky 权限 除了前面已经讨论过的那些权限之外, 还有三个管理员应该知道的权限配置。 它们是 `setuid`、 `setgid` 和 `sticky`。 这些配置对于一些 UNIX(R) 操作而言很重要, 因为它们能提供一些一般情况下不会授予普通用户的功能。 为了便于理解, 我们首先介绍真实用户 ID (real user ID) 和生效用户 ID (effective user ID)。 真实用户 ID 是拥有或启动进程的用户 UID。 生效 UID 是进程以其身份运行的用户 ID。 举例来说, man:passwd[1] 工具通常是以发起修改密码的用户身份启动, 也就是说其进程的真实用户 ID 是那个用户的 ID; 但是, 由于需要修改密码数据库, 它会以 `root` 用户作为生效用户 ID 的身份运行。 这样, 普通的非特权用户就可以修改口令, 而不是看到 `Permission Denied` 错误了。 [NOTE] ==== man:mount[8] 的 `nosuid` 选项可以令系统在不给出任何错误提示的情况下不执行这些程序。 另一方面, 这个选项并不是万无一失的, 正如 man:mount[8] 联机手册所提到的那样, 如果系统中安装了绕过 `nosuid` 的封装程序, 那么这种保护就可以被绕过了。 ==== setuid 权限可以通过在普通权限前面加上一个数字四 (4) 来设置, 如下面的例子所示: [source,shell] .... # chmod 4755 suidexample.sh .... 这样一来, [.filename]#suidexample.sh# 的权限应该如下面这样: [.programlisting] .... -rwsr-xr-x 1 trhodes trhodes 63 Aug 29 06:36 suidexample.sh .... 您会注意到, 在原先的属主执行权限的位置变成了 `s`。 这样, 需要提升特权的可执行文件, 例如 `passwd` 就可以正常运行了。 可以打开两个终端来观察这一情形。 在其中一个终端里面, 以普通用户身份启动 `passwd` 进程。 在它等待输入新口令时, 在另一个终端中查看进程表中关于 `passwd` 命令的信息。 在终端 A 中: [source,shell] .... Changing local password for trhodes Old Password: .... 在终端 B 中: [source,shell] .... # ps aux | grep passwd .... [source,shell] .... trhodes 5232 0.0 0.2 3420 1608 0 R+ 2:10AM 0:00.00 grep passwd root 5211 0.0 0.2 3620 1724 2 I+ 2:09AM 0:00.01 passwd .... 正如前面所说的那样, `passwd` 是以普通用户的身份启动的, 但其生效 UID 是 `root`。 与此对应, `setgid` 权限的作用, 与 `setuid` 权限类似, 只是当应用程序配合这一设定运行时, 它会被授予拥有文件的那个组的权限。 如果需要在文件上配置 `setgid` 权限, 可以在权限数值前面增加数字二 (2) 来运行 `chmod` 命令, 如下面的例子所示: [source,shell] .... # chmod 2755 sgidexample.sh .... 可以用与前面类似的方法来检视新设定的生效情况, 在组权限的地方的 `s` 表示这一配置已经生效: [source,shell] .... -rwxr-sr-x 1 trhodes trhodes 44 Aug 31 01:49 sgidexample.sh .... [NOTE] ==== 在这些例子中, 尽管 shell 脚本也属于可执行文件的一种, 但它们不会以您配置的 EUID 或生效用户 ID 的身份运行。 这是因为 shell 脚本可能无法直接呼叫 man:setuid[2] 调用。 ==== 我们已经讨论了两个特殊权限位 (`setuid` 和 `setgid` 权限位), 它们让用户在使用程序时能够用到更高的权限, 有时这会削弱系统的安全性。 除了这两个之外, 还有第三个特殊权限位: `sticky bit`, 它能够增强安全性。 当在目录上设置了 `sticky bit` 之后, 其下的文件就只能由文件的所有者删除了。 这个权限设置能够防止用户删除类似 [.filename]#/tmp# 这样的公共目录中不属于他们的文件。 要应用这种权限, 可以在权限设置前面加上数字一 (1)。 例如: [source,shell] .... # chmod 1777 /tmp .... 现在, 可以用 `ls` 命令来查看效果: [source,shell] .... # ls -al / | grep tmp .... [source,shell] .... drwxrwxrwt 10 root wheel 512 Aug 31 01:49 tmp .... 这里的结尾的 `t` 表示了 `sticky bit` 权限。 [[dirstructure]] == 目录架构 理解 FreeBSD 的目录层次结构对于建立对系统整体的理解十分重要的基础。 其中, 最重要的概念是根目录, "/"。 这个目录是系统引导时挂接的第一个目录, 它包含了用以准备多用户操作所需的操作系统基础组件。 根目录中也包含了用于在启动时转换到多用户模式之前挂接其他文件系统所需的挂接点。 挂接点 (mount point) 是新增的文件系统在接入现有系统时的起点位置 (通常是根目录)。 在 <> 对此进行了详细的阐述。 标准的挂接点包括 [.filename]#/usr#、 [.filename]#/var#、 [.filename]#/tmp#、 [.filename]#/mnt#, 以及 [.filename]#/cdrom#。 这些目录通常会在 [.filename]#/etc/fstab# 文件中提及。 [.filename]#/etc/fstab# 是一张包含系统中各个文件系统及挂接点的表。 在 [.filename]#/etc/fstab# 中的绝大多数文件系统都会在启动时由 man:rc[8] 脚本自动挂接, 除非特别指定了 `noauto` 选项。 更多细节请参考 <>。 您可以通过 man:hier[7] 来了解完整的文件系统层次说明。 现在, 让我们先来看一看绝大多数的常见的目录以供参考。 [.informaltable] [cols="1,1", frame="none", options="header"] |=== | 目录 | 介绍 |[.filename]#/# |文件系统的根目录。 |[.filename]#/bin/# |在单个用户和多用户环境下的基本工具目录。 |[.filename]#/boot/# |在操作系统在启动加载期间所用的程序和配置。 |[.filename]#/boot/defaults/# |默认每步引导启动的配置内容,请查阅man:loader.conf[5]。 |[.filename]#/dev/# |设备节点,请查阅 man:intro[4]。 |[.filename]#/etc/# |系统启动的配置和脚本。 |[.filename]#/etc/defaults/# |系统默认的启动配置和脚本,请参考 man:rc[8] 。 |[.filename]#/etc/mail/# |关系到邮件系统运作的配置, 请参考 man:sendmail[8]。 |[.filename]#/etc/namedb/# |`named` 配置文件,请参考 man:named[8]。 |[.filename]#/etc/periodic/# |每天、每星期和每月周期性地运行的脚本, 请通过 man:cron[8]查阅 man:periodic[8]。 |[.filename]#/etc/ppp/# |``ppp``配置文件,请查阅man:ppp[8]。 |[.filename]#/mnt/# |由管理员习惯使用挂接点的临时空目录。 |[.filename]#/proc/# |运行中的文件系统,请参阅 man:procfs[5] 和 man:mount_procfs[8]。 |[.filename]#/rescue/# |用于紧急恢复的一组静态联编的程序; 参见 man:rescue[8]。 |[.filename]#/root/# |``root``用户的Home(主)目录。 |[.filename]#/sbin/# |在单个用户和多用户环境下的存放系统程序和管理所需的基本实用目录。 |[.filename]#/tmp/# |临时文件。 [.filename]#/tmp# 目录中的内容, 一般不会在系统重新启动之后保留。 通常会将基于内存的文件系统挂在 [.filename]#/tmp# 上。 这一工作可以用一系列 tmpmfs 相关的 man:rc.conf[5] 变量来自动完成。 (或者, 也可以在 [.filename]#/etc/fstab# 增加对应项; 参见 man:mdmfs[8])。 |[.filename]#/usr/# |存放大多数用户的应用软件。 |[.filename]#/usr/bin/# |存放实用命令,程序设计工具,和应用软件。 |[.filename]#/usr/include/# |存放标准 C include 文件. |[.filename]#/usr/lib/# |存放库文件。 |[.filename]#/usr/libdata/# |存放各种实用工具的数据文件。 |[.filename]#/usr/libexec/# |存放系统实用或后台程序 (从另外的程序启动执行)。 |[.filename]#/usr/local/# |存放本地执行文件, 库文件等等, 同时也是 FreeBSD ports 安装的默认安装目录。 [.filename]#/usr/local# 在 [.filename]#/usr# 中的目录布局大体相同, 请查阅 man:hier[7]。 但 man 目录例外, 它们是直接放在 [.filename]#/usr/local# 而不是 [.filename]#/usr/local/share# 下的, 而 ports 说明文档在 [.filename]#share/doc/port#。 |[.filename]#/usr/obj/# |通过联编 [.filename]#/usr/src# 得到的目标文件。 |[.filename]#/usr/ports/# |存放 FreeBSD 的 Ports Collection (可选)。 |[.filename]#/usr/sbin/# |存放系统后台程序 和 系统工具 (由用户执行)。 |[.filename]#/usr/shared/# |存放架构独立的文件。 |[.filename]#/usr/src/# |存放 BSD 或者本地源码文件。 |[.filename]#/usr/X11R6/# |存放 X11R6 可执行文件、 库文件、 配置文件等的目录(可选)。 |[.filename]#/var/# |多用途日志、 临时或短期存放的, 以及打印假脱机系统文件。 有时会将基于内存的文件系统挂在 [.filename]#/var# 上。 这一工作可以通过在 man:rc.conf[5] 中设置一系列 varmfs 变量 (或在 [.filename]#/etc/fstab# 中加入一行配置; 参见 man:mdmfs[8]) 来完成。 |[.filename]#/var/log/# |存放各种的系统记录文件。 |[.filename]#/var/mail/# |存放用户mailbox(一种邮件存放格式)文件。 |[.filename]#/var/spool/# |各种打印机和邮件系统spooling(回环)的目录。 |[.filename]#/var/tmp/# |临时文件。 这些文件在系统重新启动时通常会保留, 除非 [.filename]#/var# 是一个内存中的文件系统。 |[.filename]#/var/yp/# |NIS 映射。 |=== [[disk-organization]] == 磁盘组织 FreeBSD 查找文件的最小单位是文件名。 而文件名区分大小写,这就意味着 [.filename]#readme.txt# 和 [.filename]#README.TXT# 是两个不相同的文件。 FreeBSD 不凭文件扩展名 ([.filename]#.txt#) 去识别这个文件是 程序、 文档, 或是其他格式的数据。 各种文件存放在目录里。 一个目录可以为空, 也可以含有多个的文件。一个目录同样可以包含其他的目录, 允许您在一个目录里建立多个不同层次的目录。 这将帮助您轻松地组织您的数据。 文件或目录是由文件名或目录名,加上斜线符号 `/`, 再根据需要在目录名后面加上其他目录的名称。 如果您有一个名为 [.filename]#foo# 的目录, 它包含另一个目录 [.filename]#bar#, 后者包括一个叫 [.filename]#readme.txt# 的文件, 则全名, 或者说到文件的 _路径_ 就是 [.filename]#foo/bar/readme.txt#。 在文件系统里目录和文件的作用是存储数据。 每一个文件系统都有且只有一个顶级目录 _根目录_, 这个根目录则可以容纳其他目录。 您也许在其他的一些操作系统碰到类似这里的情况, 当然也有不同的情况。 举些例子, MS-DOS(R) 是用 `\` 分隔文件名或目录名, 而 Mac OS(R) 则使用``:``。 FreeBSD在路径方面不使用驱动器名符号或驱动器名称, 在FreeBSD里您不能这样使用: [.filename]#c:/foo/bar/readme.txt#。 为了代替(驱动器名符号), 一个文件系统会指定 _根 文件系统_, 根文件系统的根目录是 `/`。 其他每一个文件系统 __挂接在__根文件系统下。 无论有多少磁盘在FreeBSD 系统里, 每个磁盘都会以目录的方式加上。 假设您有三个文件系统, 名为 `A`、 `B` 和 `C`。 每个文件系统有一个根目录, 而各自含有两个其他的目录, 名为 `A1`, `A2` ( `B1`, `B2` 和 `C1`, `C2`)。 看看 `A` 这个根文件系统。 假如您用 `ls` 命令来查看这个目录您会见到两个子目录: `A1` 和 `A2`。 这个目录树是这个样子: image::example-dir1.png[] 一个文件系统必须挂到另一个文件系统的某一目录, 所以现在假设把 `B` 文件系统挂到 ``A1``目录, 那 `B` 根目录因此代替 了 `A1`,而显示出 `B` 目录(的内容): image::example-dir2.png[] 无论``B1`` 或 `B2` 目录在那里而延伸出来的路径必须为 [.filename]#/A1/B1# 或 [.filename]#/A1/B2#。 而在 [.filename]#/A1# 里原有的文件会临时隐藏。 想这些文件再出现把 `B` 从 A _挂接释放_。 所有在``B1`` 或 `B2` 目录里的文件都可以通过 [.filename]#/A1/B1# 或 [.filename]#/A1/B2# 访问。而在 [.filename]#/A1# 中原有的文件会被临时隐藏,直到 `B` 从 A 上被__卸载__ (unmout) 为止。 把 `B` 挂接在 `A2` 那图表的样子就是这样子: image::example-dir3.png[] 这个路径分别是 [.filename]#/A2/B1# 和 [.filename]#/A2/B2# 。 文件系统能把顶部挂接在另一个文件系统上。 继续这个例子, 把 `C` 文件系统挂接在 `B` 文件系统里的 `B1` 目录, 排列如下: image::example-dir4.png[] 或者把 `C` 文件系统挂接在 `A` 文件系统里的``A1``目录: image::example-dir5.png[] 假如您熟悉 MS-DOS(R) 并知道 `join` 命令, 尽管不相同,其实功能是相似的。 这方面不是普通知识而且涉及到您自己所关心的, 当您安装FreeBSD并在以后添加新磁盘时, 您必须知到该如何新建文件系统和挂接上。 (FreeBSD系统)它有一个主要的根文件系统, 不需要另外新建立, 但当需要手工处理时,这是一个有用的知识。 .多个文件系统的益处 * 不同的文件系统可用不同的 _挂接参数_。 举些例子, 仔细想一下, 根文件系统能用只读的方式挂接上, 防止不经意删除或编辑到一个危险的文件。 把各用户能写入的文件系统分开, 像[.filename]##/home##这样, 由另外的文件系统分别用 _nosuid_ 参数挂接,这个参数防止 _suid_/_guid_ 在执行这个文件系统中的文件时生效, 从而缓解了一些安全问题。 * FreeBSD 能根据一个文件系统使用的情况自动优化 这个文件系统上的文件布局。 所以对一个存储了大量小文件并会被频繁写入文件系统的优化与一个存储了少量大文件的优化是不同的。 而在一个大的单一文件系统上则无法体现这样的优化。 * FreeBSD 的文件系统能够在断电时尽可能避免损失。 然而, 在关键点时的电源失效仍然可能会破坏文件系统的结构。 将您的文件系统分成多个有助于分散风险, 并方便备份和恢复。 .单一文件系统的益处 * 文件系统是固定大小的。 当安装FreeBSD时新建一个文件系统并设定一个大小, 您会在稍后发觉到必须去建一个大的分区。 如果配置不当, 则需要备份、 重新创建文件系统, 然后再恢复数据。 + [IMPORTANT] ==== FreeBSD 提供了 man:growfs[8] 命令。 这使得能够实时地调整文件系统的大小, 因而不再受其限制。 ==== 文件系统是和分区一一对应的。 这里的分区和常用的术语分区 (例如, MS-DOS(R) 分区) 的意思并不一样, 这是由于 FreeBSD 的 UNIX(R) 传统造成的。 每一个分区使用一个从 `a` 到 `h` 的字母来表示。 每个分区只能包含一个文件系统, 这意味着文件系统通常可以由它们在文件系统目录结构中的挂接点, 或对应的分区字母来表示。 FreeBSD 的 _交换分区_ 也需要使用磁盘空间。 交换分区是给 FreeBSD 作 _虚拟内存_ 使用的, 这样能令您的计算机有更多的内存可使用, 当FreeBSD在运行而内存不够的时候, 它会把其他一些可转移的数据转移到交换分区, 空出内存的位置以供使用。 某些 partitions 的用途是确定的。 [.informaltable] [cols="1,1", frame="none", options="header"] |=== | 分区 | 约定 |`a` |通常指定为根文件系统 |`b` |通常指定为交换分区 |`c` |通常它和所在的 slice 大小相同。 `c` 分区上工作时必定会影响到事整个 slice (举个例子,坏块扫描器)。 您通常不愿意在这个partition建立文件系统。 |`d` |分区 `d` 曾经有特殊的含义, 不过这种意义在现时的系统上已不再适用, 因此 `d` 可以和任何其它普通的分区一样使用了。 |=== 每一个包含了文件系统的分区被保存在 FreeBSD 称为 _slice_ 的部分上。 Slice 是一个 FreeBSD 术语, 通常被叫做分区, 再次强调, 这是由于 FreeBSD 的 UNIX(R) 背景。 Slices 有其编号, 从1到4。 Slice 编号在设备名后面, 并有一个 `s` 前缀, 从 1 开始。 因此 "da0__s1__" 是第一个 SCSI 驱动器的第一个 slice。 每个磁盘上只能有四个物理的 slices, 但您可以在物理 slice 中使用适当的类型来创建逻辑 slice。 这些扩展 slice 编号从 5 开始, 因此 "ad0__s5__" 是第一个 IDE 磁盘中的第一个 扩展 slice。 文件系统所使用的设备应该占满 slice。 Slices, "专用指定" 物理驱动器, 和其他驱动器都包含 _partitions_, 那几个的 partitions 都是用字母从 `a` 到 `h` 来标定的, 而这些字母都在驱动器名字之后,所以 "da0__a__" 是指首个da设备的 a partition, 而那个就是 "专项指定"。 "ad1s3__e__" 是指IDE磁盘上第三个slice的第五个partition。 最终,每个磁盘都被系统识别。 一个磁盘名字是用磁盘类型代码和编号来标识的, 它不像slices,磁盘的编号是由0开始的。 对应代码请看这里所列出的<>。 当在 FreeBSD 中指定 partition 名字时, 必须同时包含这个分区的 slice 和磁盘的名字; 类似地, 在指定 slice 时, 也应该给出包含该 slice 的磁盘名字。 可这样列出: 磁盘名称,`s`,slice 编号,和partition标定字母。 例子请看 <>。 <> 这里显示了一个磁盘的布局,有更清楚的帮助。 在安装FreeBSD时,您首先要配置好磁盘slices, 然后在FreeBSD使用的slice上建立partitions。 并在每个partition上建立一个文件系统(或交换分区), 和指定文件系统的挂接位置。 [[basics-dev-codes]] .磁盘设备的代码 [cols="1,1", frame="none", options="header"] |=== | 代码 | 说明 |[.filename]#ad# |ATAPI (IDE) 磁盘 |[.filename]#da# |SCSI 直接存取磁盘 |[.filename]#acd# |ATAPI (IDE) 光驱 |[.filename]#cd# |SCSI 光驱 |[.filename]#fd# |软驱 |=== [[basics-disk-slice-part]] .样例磁盘, Slice, 和 Partition 它们的命名 [example] ==== [.informaltable] [cols="1,1", frame="none", options="header"] |=== | 命名 | 说明 |`ad0s1a` |在首个IDE磁盘(`ad0`)上的 第一个slice (`s1`)里的 第一个partition (`a`)。 |`da1s2e` |在第二个SCSI磁盘(`da1`)上的 第二个slice(`s2`)里的 第五个partition(`e`)。 |=== ==== [[basics-concept-disk-model]] .一个磁盘的布局 [example] ==== 从在系统里的首个IDE磁盘图表可以显示出FreeBSD的见解。 假设磁盘大小为4 GB,它里面包含了两个2 GB 大小的slices (但在MS-DOS(R)叫partitions)。 首个slice是一个MS-DOS(R)磁盘叫[.filename]##C:##, 而第二个slice是FreeBSD配置好的slice。 FreeBSD配置好的slice有三个partitions和另一个交换分区。 这三个partitions各自控制一个文件系统。 partition``a`` 用于根文件系统, partition``e`` 用于 [.filename]#/var# 目录层, partition``f`` 用于 [.filename]#/usr# 目录层。 image::disk-layout.png[] ==== [[mount-unmount]] == 文件系统的挂接和卸下 这种文件系统就像一棵树那样用[.filename]##/##确立根部, 是比较理想的文件系统。 而[.filename]##/dev##、 [.filename]##/usr## 和其他目录就是根目录的分枝, 另外这些目录可以再分枝,例如[.filename]##/usr/local##。 应该考虑给某些目录一些空间从而分散文件系统。 [.filename]#/var# 之下包含目录 [.filename]#log/#,目录[.filename]##spool/##, 和不同类型的临时文件,很可能把它塞满。 把什么都塞进根文件系统不是一个好主意, 好的做法是应该把 [.filename]#/var# 从 [.filename]##/##分离出去。 另一个要考虑的是,给物理设备或虚拟磁盘这些自带空间的文件系统确定目录结构树。 例如 crossref:network-servers[network-nfs,网络文件系统] 或光驱的挂接。 [[disks-fstab]] === [.filename]#fstab# 文件 在 crossref:boot[boot,引导过程] 期间, 自动挂上[.filename]##/etc/fstab##所列出的文件系统。 (除非他们注明为``noauto`` 选项)。 [.filename]#/etc/fstab# 文件包含的各行的列表格式如下: [.programlisting] .... device /mount-point fstype options dumpfreq passno .... `device`:: 设备名称(设备必须存在), 说明在 crossref:disks[disks-naming,设备命名]. `mount-point`:: 目录 (目录必须存在), 用在那个挂接上的文件系统上。 `fstype`:: 文件系统类型,请通过man:mount[8]查阅。 默认的FreeBSD文件系统类型是``ufs``。 `options`:: 设为可读写文件系统的``rw``选项, 或设为只读文件系统的``ro``选项, 或其他一些选项,可随意选一个。 一个常用的选项 ``noauto`` 用在不需在引导过程期间挂接的文件系统。 其他的选项在 man:mount[8] 手册里列出。 `dumpfreq`:: man:dump[8] 使用这项去决定那个文件系统必须移贮。 假如缺少这项,默认的数值为0。 `passno`:: 这一项决定文件系统的检查顺序, 文件系统想跳过检查应将``passno``设为0。 根文件系统(那个是在每方面开始之前必须检查的) 应该将它的 `passno` 设为1, 其他文件系统的 `passno` 必须把数值设到大于1。假如多个文件系统的``passno``的值相同, 那么 man:fsck[8] 在允许的情况下将尝试并行地去检查文件系统。 请参阅 man:fstab[5] 联机手册, 以获得关于 [.filename]#/etc/fstab# 文件格式, 以及其中所包含的选项的进一步信息。 [[disks-mount]] === `mount` 命令 这个 man:mount[8] 命令是挂接文件系统的基本运用。 使用最多的基本格式: [example] ==== [source,shell] .... # mount device mountpoint .... ==== 它的选项非常多,而man:mount[8] 手册同样提及, 但常用的都在这里: .挂接的各种选项 `-a`:: 挂接[.filename]##/etc/fstab##里所有列出的文件系统。 除非标记为 "noauto" 或作了排除在外的 `-t` 类型标记,或者在这之前已挂上。 `-d`:: 除了实际上系统调用以外,可以完成任何事情,这个选项是和 ``-v``参数一起连在一块使用,可以决定man:mount[8]所做的事情。 `-f`:: 强制去挂接一个未知的文件系统(会有危险), 或当把一个文件系统挂接状态由可读写降为只读时,强制撤消可写通道。 `-r`:: 以只读方式挂接文件系统。 这和在指定了 `-o` 选项配合 `ro` 参数的效果是一样的。 `-t` _fstype_:: 根据给出的文件系统类型挂接文件系统, 假如给于``-a``选项,仅挂接这个类型的文件系统。 + "ufs" 是默认的文件系统类型。 `-u`:: 在文件系统上修改挂接选项。 `-v`:: 版本模式。 `-w`:: 以可读写方式挂接文件系统。 The `-o` 选项采用一个逗号分开以下多个选项: noexec:: 不允许文件系统上的二进制程序执行。这也是一个有用的安全选项。 nosuid:: 不允许文件系统上的 setuid 或 setgid 标记生效。这也是一个有用的安全选项。 [[disks-umount]] === `umount` 命令 man:umount[8] 命令同样采用一个参数、一个挂接点、一个设备名。 或采用``-a``选项,又或采用``-A``选项。 所有格式都可采用 `-f` 去强行卸下, 或采用``-v`` 用那适当的版本。 但警告,采用 ``-f``并不是一个好主意, 强行卸下文件系统可能损坏计算机或破坏文件系统上的数据。 `-a` 和 `-A` 会卸下所有已挂接的文件系, 可能通过``-t``后面列出的文件系统进行修改, 但无论如何,``-A``都不会尝试去卸下根文件系统。 [[basics-processes]] == 进程 FreeBSD 是一个多任务操作系统。 这就意味着好像一次可以运行一个以上的程序。 每个占用一定时间运行的程序就叫 _进程_ (process)。 你运行的每一个命令会至少启动一个新进程,还有很多一直运行着的系统进程, 用以维持系统的正常运作。 每个进程用来标识的一个编号就叫 _进程 ID_, 或叫 _PID_。 而且,就像文件那样,每个进程也有所属用户和所属群体。 所属用户和所属群体使用在这方面:确定这个进程可以打开那些文件和那些设备, 从而在初期使用文件的权限。 多数的进程都有一个父进程, 而进程是依靠父进程来启动的。 例如,假如您把命令输入到shell里那shell是一个进程,而您运行的各个命令同样是进程, 那么,shell就是您各个运行进程的父进程。 而这方面有一个例外的进程就叫man:init[8]。 ``init``始终是首个进程,,所以他的PID始终是1, 而``init``在FreeBSD起动时由内核自动启动。 在系统上,有两个命令对进程观察非常有用:man:ps[1] 和 man:top[1]。 这个``ps``命令作用是观察当前运行进程的状态, 显示他们的PID,使用了多少内存,它们启动的命令行。 而``top``命令则是显示所有运行进程,并在以秒计的短时内更新数据。 您能交互式的观察您计算机的工作。 默认情况下, ``ps``仅显示出您自己所运行的命令。 例如: [source,shell] .... % ps PID TT STAT TIME COMMAND 298 p0 Ss 0:01.10 tcsh 7078 p0 S 2:40.88 xemacs mdoc.xsl (xemacs-21.1.14) 37393 p0 I 0:03.11 xemacs freebsd.dsl (xemacs-21.1.14) 48630 p0 S 2:50.89 /usr/local/lib/netscape-linux/navigator-linux-4.77.bi 48730 p0 IW 0:00.00 (dns helper) (navigator-linux-) 72210 p0 R+ 0:00.00 ps 390 p1 Is 0:01.14 tcsh 7059 p2 Is+ 1:36.18 /usr/local/bin/mutt -y 6688 p3 IWs 0:00.00 tcsh 10735 p4 IWs 0:00.00 tcsh 20256 p5 IWs 0:00.00 tcsh 262 v0 IWs 0:00.00 -tcsh (tcsh) 270 v0 IW+ 0:00.00 /bin/sh /usr/X11R6/bin/startx -- -bpp 16 280 v0 IW+ 0:00.00 xinit /home/nik/.xinitrc -- -bpp 16 284 v0 IW 0:00.00 /bin/sh /home/nik/.xinitrc 285 v0 S 0:38.45 /usr/X11R6/bin/sawfish .... 在这个例子里您可看到,从 man:ps[1] 输出的每一列是有规律的。 `PID` 就是进程ID,这个较早前已讨论过了。 PID号的分配由 1一直上升直到99999, 当您运行到超过限制时,这些编号会回转分配 (仍在使用中的 PID 不会分配给其他进程)。 ``TT``这一列显示了程序运行所在的终端, 目前可以安全地忽略。 `STAT` 显示程序的状态,也可以安全地被忽略。 ``TIME``是程序在CPU处理时间-运行的时间量, 并不是指您程序启动到现在的所用的时间。 许多程序碰巧遇到某方面在他们之前要花费大量CPU处理时间时,他们就必须等候。 最后, `COMMAND` 是运行程序时使所用的命令行。 man:ps[1]支持使用各种选项去改变显示出来的内容, 最有用的一个就是``auxww``。 ``a``选项显示出所有运行进程的内容, 而不仅仅是您的进程。 ``u``选项显示出进程所归属的用户名字以及内存使用, `x` 选项显示出后台进程。 而 `ww` 选项表示为 man:ps[1] 把每个进程的整个命令行全部显示完, 而不是由于命令行过长就把它从屏幕上截去。 下面和从man:top[1]输出是类似的,一个示例式对话就象这样子: [source,shell] .... % top last pid: 72257; load averages: 0.13, 0.09, 0.03 up 0+13:38:33 22:39:10 47 processes: 1 running, 46 sleeping CPU states: 12.6% user, 0.0% nice, 7.8% system, 0.0% interrupt, 79.7% idle Mem: 36M Active, 5256K Inact, 13M Wired, 6312K Cache, 15M Buf, 408K Free Swap: 256M Total, 38M Used, 217M Free, 15% Inuse PID USERNAME PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND 72257 nik 28 0 1960K 1044K RUN 0:00 14.86% 1.42% top 7078 nik 2 0 15280K 10960K select 2:54 0.88% 0.88% xemacs-21.1.14 281 nik 2 0 18636K 7112K select 5:36 0.73% 0.73% XF86_SVGA 296 nik 2 0 3240K 1644K select 0:12 0.05% 0.05% xterm 48630 nik 2 0 29816K 9148K select 3:18 0.00% 0.00% navigator-linu 175 root 2 0 924K 252K select 1:41 0.00% 0.00% syslogd 7059 nik 2 0 7260K 4644K poll 1:38 0.00% 0.00% mutt ... .... 这个输出分成两部份。 前面部份(起始前五行) 显示了:运行于最后进程的PID、 系统负载均衡 (那个是指系统繁忙时的调节方式)、 系统正常运行时间 ( 指从启动算起所用的时间) 和当前时间。 前面部份另外的图表 涉及:多少进程在运行(这个情况是47), 多少内存和多少交换分区在使用, 和在不同CPU状态里系统消耗多少时间。 在那下面一连串的纵列和从man:ps[1]输出的的内存是相似的。 如以前man:ps[1]一样,您能见到:PID、用户名、CPU处理时间合计、运行的命令。 man:top[1]默认是显示您的进程所用内存空间的合计。 内存空间这里分成两列,一列为总体大小,另一列是必须请求驻留大小是多少内存-总体大小。 而驻留大小实际上是瞬间使用的多少。 在以上那个例子,您会看到那man:getenv[3]总计需要30 MB内存, 但实际只用了9 MB。 man:top[1] 每两秒自动刷新一次,您可以用``s``改变刷新的秒数。 [[basics-daemons]] == 守护进程,信号和杀死进程 当您运行一个编辑器时它是很容易控制的,告诉它去加载文件它就加载。 您之所以能这样做,是因为编辑器提供这样便利去这样做,和因为有编辑器去附上的__终端__。 一些程序在运行中不需要连续的用户输入,一有机会就从终端里分离到后台去。 例如,一个web系统整天都在作web请求的响应,他不需要您输入任何东西就能完成, 这个类别的另一个例子就是把email的传送。 我们把那些程序叫 _守护进程_。 守护神是希腊神话中的一些人物,非正非邪,他们是些守护小精灵, 大体上为人类作出贡献。 许多类似web服务或mail服务的系统对于今天仍有用途, 这就是为什么在那么长的时间里,BSD的吉祥物保持为一双鞋加一把钢叉的守护神模样。 守护进程的程序命名通常在最后加一个 "d"。 BIND 是伯克利互联网域名服务 (而实际执行的程序名称则是 `named`), Apache web系统的程序就叫 `httpd`, 在行式打印机上的打印守护进程就是 `lpd`。 这只是一种惯例,不是标准或硬性规定。 例如,为Sendmail而应用的主要mail守护进程就叫``sendmail``, 却不叫``maild``,这和您推测的一样。 有时可能会需要与守护进程进行通讯。 而 _信号_ 则是其中的一种通讯机制。 可以发送信号给守护进程 (或相关的另一些进程) 来与它进行通信, 不同的信号都有自己的数字编号-其中一些有特殊的含义, 其它的则可以被应用程序自己进行解释, 而一般来说, 应用程序的文档会告诉哪些信号会被如何处理。 您只能给所属于您的进程发信号,假如您给其他人的进程发信号, 进程就会用man:kill[1] 或 man:kill[2]权限进行拒绝。 当然,`root` 用户会例外,它能把各种信号发送给每个进程。 在某些情况下,FreeBSD也会向应用软件发送信号。 假如一个应用软件含有恶意写入并试图去访问内存,那是不可想象的,FreeBSD会向那个进程发送 _段式违规_ 信号 (`SIGSEGV`)。 假如一个应用软件使用man:alarm[3]系统去进行周期性调用闹钟功能,每当达到时间时, FreeBSD会向应用软件发送闹钟信号(`SIGALRM`)。 有两个信号可以停止进程:``SIGTERM`` 和 `SIGKILL`。 ``SIGTERM``比较友好,进程能__捕捉__这个信号, 根据您的需要来关闭程序。在关闭程序之前,您可以结束打开的记录文件和完成正在做的任务。 在某些情况下, 假如进程正在进行作业而且不能中断,那么进程可以忽略这个 ``SIGTERM``信号。 对于``SIGKILL``信号,进程是不能忽略的。 这是一个 '"我不管您在做什么,立刻停止"'的信号。 假如您发送``SIGKILL``信号给进程, FreeBSD就将进程停止在那里。. 您可能会去使用 `SIGHUP`、 `SIGUSR1` 和 ``SIGUSR2``信号。 这都是些通用的信号,各种应用程序都可以应用 在各方面的信号发送。 假如您改变了web系统的配置文件-并想web系统去重读它的配置, 您可以停止然后再启动``httpd``。但这样做web系统会导致一个短暂 的中断周期,那样是不受欢迎的。几乎所有的守护进程在编写时,都会指定对``SIGHUP`` 信号进行响应从而重读配置文件。 所以, 最好的方法, 就不是杀死并重启 `httpd`, 而是发一个 `SIGHUP` 信号给它。 因为在这方面没有一个标准,不同的守护进程有不同的用法,所以不了解时应读一下守护进程的文档。 发送信号可用man:kill[1] 命令, 请参考man:kill[1]所列出的例子。 [.procedure] ==== *Procedure: 发送一个信号给进程* 这个例子显示了怎样去发一个信号给man:inetd[8]。 ``inetd``配置文件是[.filename]##/etc/inetd.conf##, 如果想``inetd`` 去重读文件系统的话,可以给它发一个``SIGHUP`` 信号。 . 寻找您要发送信号的进程ID,可以用man:ps[1] 加 man:grep[1]来完成。 man:grep[1]命令被用在搜索输出方面,搜索您指定的字符串。 这命令是由普通用户来执行的,而man:inetd[8]是``root``用户运行的, 所以必须给man:ps[1]带上``ax``选项。 + [source,shell] .... % ps -ax | grep inetd 198 ?? IWs 0:00.00 inetd -wW .... + 得出 man:inetd[8] PID号是198。 有时 `grep inetd` 命令也出现在输出中, 这是因为在这方面 man:ps[1] 也是寻找列表中运行进程。 . 使用 man:kill[1] 去发送信号。 因为 man:inetd[8] 是由 ``root``启动的, 您必须使用 man:su[1] 去 变为 `root` 用户。 + [source,shell] .... % su Password: # /bin/kill -s HUP 198 .... + 和大多数 UNIX(R) 命令一样, man:kill[1] 如果完成了任务, 就不会给出任何消息。 假如您发送信号给一个不属于您的进程, 您会看到 `kill: _PID_: Operation not permitted`. 假如输错了PID号,把信号发送到其他进程,那是坏事。 或者您侥幸,把信号发送到不存在的进程, 您会看见 `kill: _PID_: No such process`. + [NOTE] .为什么使用 `/bin/kill`? ====== 许多shell提供了内建 `kill` 命令, 这样, shell就能直接发送信号,而不是运行 [.filename]#/bin/kill#。 这点非常有用, 但不同shell有不同的语法来指定发送信号的名字, 与其试图把它们学完倒不如简单地直接使用 `/bin/kill ...`。 ====== ==== 发送其他的信号也很相似, 只要在命令行替换 `TERM` 或 `KILL` 就行了。 [IMPORTANT] ==== 在系统上随意杀死进程是个坏主意,特别是man:init[8], 它的进程ID是1,它非常特殊。可以运行 `/bin/kill -s KILL 1` 命令来让系统迅速关机。 当您按下 kbd:[Return] (回车)键之前, _一定要_ 详细检查您运行 man:kill[1] 时所指定的参数。 ==== [[shells]] == Shells 在FreeBSD里,每日有一大堆工作是在命令行的界面完成的,那就叫做shell。 一个shell的主要功能就是从输入取得命令然后去执行他。 许多的shell同样能帮我们完成内建的每日功能,例如:文件管理、文件寻找、命令行编辑、 宏指令和环境变量。FreeBSD内含了一些shell,例如:``sh``、Bourne Shell、 ``tcsh``和改良过的C-shell。 另外也有些shell也可在FreeBSD的Ports得到,例如:``zsh``和``bash``。 您想使用哪一种shell取决于您的喜好, 假如您是C程序设计师,您可能选择一个C-like shell例如``tcsh``。 假如您是从Linux过来的或是一个命令行的新手,您可能会试一下``bash``。 这一点告诉我们每一个shell都有各自的特性,可能适用于您的工作环境,也可能不适用于您的工作环境。 每个shell都有一个共通点就是文件名补全。 输入命令或文件名的前几个字,然后按kbd:[Tab]键,就能靠shell的自动补全功能得出 命令或文件名。这里有一个例子,假设您有两个文件叫 [.filename]#foobar# 和[.filename]##foo.bar##,而您想删除 [.filename]#foo.bar#, 可这样在键盘上输入 ``rm fo[Tab].[Tab]``。 那么shell就会输出 `rm foo[BEEP].bar`。 这个[BEEP] 是这控制台铃声, 那个是告诉我们它不能完成文件名补全,因为有多个文件名符合。 [.filename]#foobar# 和 [.filename]#foo.bar# 都是以 ``fo``开头, 它只可以补全到 `foo`。 输入 ``.``并再按一次 kbd:[Tab],shell才把其余的文件名全部显示出来。 另一个特点就是shell利用环境变量运行。环境变量是贮存在shell环境空间上相对应的键和可变值, 这个空间能够补程序从shell里读出,而且包含了许多程序的配置。 这个一个常用环境变量列和其含义的列表: [.informaltable] [cols="1,1", frame="none", options="header"] |=== | 变量 | 说明 |`USER` |当前登录进入的用户名。 |`PATH` |搜索程序路径,以两点的冒号分隔开。 |`DISPLAY` |假如有这个变量的话,就是X11显示器的网络名称。 |`SHELL` |当前所用的shell。 |`TERM` |用户终端的名字,通常用在确定终端的能力。 |`TERMCAP` |各种终端功能所用终端分离编码的基本数据项目。 |`OSTYPE` |操作系统类型,默认是FreeBSD。 |`MACHTYPE` |是指系统上运行的CPU体系结构。 |`EDITOR` |用户首选的文本编辑器。 |`PAGER` |用户首选的文本页面调度程序 。 |`MANPATH` |搜索联机手册路径,以两点的冒号分隔开。 |=== 不同的shell设置环境变量也不相同。举个例子, 在如``tcsh`` 和 ``csh``这样的C-Style shell, 您必须使用``setenv``去设置环境变量。 而在如``sh``和``bash``这样的Bourne shell, 您必须使用``export``去设置当前环境变量。 再举个例子,要去设置或改变``EDITOR``环境变量, 在``csh``或``tcsh``下将``EDITOR``设为 [.filename]#/usr/local/bin/emacs#: [source,shell] .... % setenv EDITOR /usr/local/bin/emacs .... 而在Bourne shell下,则是: [source,shell] .... % export EDITOR="/usr/local/bin/emacs" .... 您也可以在命令行上加一个``$``字符在变量之前从而取得环境变量。 举个例子,用``echo $TERM`` 就会显示出``$TERM``的设定值, 其实就是shell取得``$TERM``并传给``echo``来显示的。 shell里有许多特别的字符代表着特别的资料,我们把叫做meta-characters。 最常用的就是``\*``字符,它可代表文件名的任何字符。 这些特别字符应用到文件名全域方面。假如,输入 ``echo *``和输入 ``ls``的效果是相同的,其实就是 shell 取得了全部符合 ``*``的文件名,并传给 `echo` 在命令行下显示出来。 为了防止shell去分析这些特别字符, 我们可在它之前加一个 ``\``字符去说明它只是普通字符。 ``echo $TERM``就会显示出您的终端情况, 而 ``echo \$TERM`` 就会显示出 `$TERM` 这几个字。 [[changing-shells]] === 改变您用的Shell 改变您的Shell的最简单方法是使用 `chsh` 命令。 执行 `chsh` 将根据您设定的``EDITOR`` 环境变量进入到那个编辑器,假如没有设定,就会进入``vi``编辑器。 请改变"Shell:"这行对应值。 您可使用``chsh`` 的``-s``选项, 这样就能设置您的shell却又不用编辑器。假如您想把shell改为``bash`` 可用下面的技巧。 [source,shell] .... % chsh -s /usr/local/bin/bash .... [NOTE] ==== 您使用的shells__必须__ 在[.filename]##/etc/shells## 文件里列出。 假如您从 crossref:ports[ports,ports]里装一个shell, 那就不用做这步了。 假如您手工装一个shell,那就要手工添加进去。 举个例了子,假如您手工把 ``bash``装到 [.filename]##/usr/local/bin##里,您还要进行这一步: [source,shell] .... # echo "/usr/local/bin/bash" >> /etc/shells .... 然后运行``chsh``。 ==== [[editors]] == 文本编辑器 FreeBSD 的很多配置都可以通过编辑文本文件来完成。 因此, 最好能熟悉某种文本编辑器。 FreeBSD 基本系统中提供了一些, 您也可以从 Ports Collection 安装其它编辑器。 最容易学的而又简单的编辑器是 ee编辑器, 是个标准的简易编辑器。 要启动 ee,首先就要在命令行输入 `ee filename`, _filename_ 是一个要编辑的文件名。 例如,要编辑 [.filename]##/etc/rc.conf##就要输入 `ee /etc/rc.conf`,在 ``ee``的控制内, 编辑器所有功能的操作方法都显示在最上方。 这个``^`` 字符代表 键盘上的kbd:[Ctrl] 键, 所以``^e`` 就是 kbd:[Ctrl+e]组合键。 假如想离开ee, 按kbd:[Esc]键,就可选择离开编辑器。 当您修改了内容的时候,编辑器会提示您保存。 FreeBSD本身也带许可多有强大功能的文本编辑器, 例如 vi。还有其他在FreeBSD Ports里几种, 像 emacs 和 vim。 这些编辑器有着强大的功能,但同时学习起来比较复杂。 不管怎样,假如您从事文字编辑方面的工作, 学习如vim 或 emacs 这些有强大功能的编辑器用法, 在长时间工作里会帮您节省不少的时间。 很多需要修改文件或打字输入的应用程序都会自动打开一个文本编辑器。 更改默认使用的编辑器, 请设置 ``EDITOR`` 环境变量。 参阅 <> 以获取更多详细信息。 [[basics-devices]] == 设备和设备节点 在一个系统里,硬件描述通常用法就是一个设备对应一个术语,包括磁盘、打印机、显卡和键盘。 当 FreeBSD 启动过程中,大多数的设备都能探测到并显示出来, 您也可以查阅[.filename]##/var/run/dmesg.boot##, 引导时所有信息都在里面。 例如, [.filename]#acd0# 就是 首个 IDE 光盘设备, 而 [.filename]#kbd0# 则代表键盘。 在UNIX(R)操作系统里,大多数设备存在的特殊访问文件就是叫做设备节点, 他们都定位在[.filename]##/dev##目录里。 === 建立设备节点 当在系统中添加新设备或将附加设备的支持编译进内核之后, 都必须为其建立设备节点。 ==== `DEVFS` (DEVice 文件系统) 这个设备文件系统, 或叫 `DEVFS`, 为内核的设备命名在整体文件系统命名里提供通道, 并不是建立或更改设备节点, ``DEVFS``只是为您的特别文件系统进行维护。 请参见 man:devfs[5] 联机手册以了解更多细节。 [[binary-formats]] == 二进制文件格式 要理解为什么 FreeBSD 使用 man:elf[5] 格式, 您必须首先了解一些 UNIX(R) 系统中的 三种 "主要" 可执行文件格式的有关知识: * man:a.out[5] + 是最古老和"经典的" UNIX(R) 目标文件格式, 这种格式在其文件的开始处有一个短小而又紧凑的首部, 该首部带有一个魔幻数字,用来标识具体的格式(更多详情参见man:a.out[5])。 这种格式包含3个要装载入内存的段:.text, .data, 和 .bss,以及 一个符号表和一个字符串表。 * COFF + SVR3目标文件格式。其文件头现在包括一个区段表(section table), 因此除了.text,.data,和.bss区段以外,您还可以包含其它的区段。 * man:elf[5] + COFF 的后继, 其特点是可以有多个区段, 并可以使用32位或64位的值。 它有一个主要的缺点: ELF 在其设计时假设每个系统体系结构只有一种 ABI。 这种假设事实上相当错误, 甚至在商业化的SYSV世界中都是错误的 (它们至少有三种ABI: SVR4, Solaris, SCO)。 + FreeBSD试图在某种程度上解决这个问题,它提供一个工具,可以 对一个已知的ELF可执行文件 __标识__它所遵从的ABI的信息。 更多这方面的知识可以参见手册页man:brandelf[1] FreeBSD从"经典"阵营中来,因此使用了man:a.out[5]格式, 众多BSD版本的发行(直到3.X分支的开始)也证明了这种格式的有效性。 虽然在那以前的某段时间,在FreeBSD系统上创建和运行ELF格式 的二进制可执行文件(和内核)也是可能的,但FreeBSD一开始并不积极"进步" 到使用ELF作为其缺省的格式。为什么?噢,当Linux阵营完成了 转换到ELF格式的痛苦历程后,却发现并不足以由此而放弃 [.filename]##a.out##可执行文件格式,因为正是由于它们不灵活的, 基于跳转表的共享库机制,使得销售商和开发者们构建共享库非常困难。 直到已有的ELF工具提供了一种解决共享库问题的办法, 并被普遍认为是"前进方向"以后,迁徙的代价在FreeBSD界才被接受, 并由此完成了迁徙。FreeBSD的共享库机制其基础更类似于Sun SunOS(TM)的共享库机制, 并且正因为此,其易用性很好。 那么,为什么会有这么多不同的格式呢? 回溯到蒙昧和黑暗的过去,那时只有简单的硬件。这种简单的硬件支撑了一个简单 和小型的系统。在这样的简单系统上(PDP-11)[.filename]##a.out##格式 足以胜任表达二进制文件的任务。当人们将UNIX(R)从这种简单的系统中移植出来的时候, [.filename]##a.out##格式被保留了下来,因为对于早期将UNIX(R)移植到 Motorola 68k,VAXen等系统来说,它还是足够可用的。 然后,一些聪明的硬件工程师认为,如果可以让软件完成一些简单的聪明操作, 那么他们就可以在硬件设计中减少若干门电路,并可以让CPU核心运行得更快。 当[.filename]##a.out##格式用于这种新型的硬件系统时(现在我们叫它 RISC),显得并不合适。因此,人们设计了许多新的格式 以便在这样的硬件系统上能获得比简单的[.filename]##a.out##格式更优越 的性能。诸如COFF,ECOFF,还有其它 一些晦涩难懂的格式正是在这个阶段被发明出来的,人们也研究了这些格式的局限性, 慢慢地最终落实到ELF格式。 同时,程序的大小变得越来越大,磁盘空间(以及物理内存)相对来说却仍然较小, 因此共享库的概念便产生了。VM系统也变得越来越复杂了。当所有这些进步都建立在 [.filename]##a.out##格式的基础上的时候,它的可用性随着每个新特性 的产生就受到了严重考验。并且,人们还希望可以在运行时动态装载某些东西,或者 在初始化代码运行以后可以丢弃部分程序代码,以便节约主存储器和交换区。编程语言 也变得越来越复杂,人们希望可以在main()函数执行之前自动执行某些代码。为了实现 所有这些功能,人们对[.filename]##a.out##格式作了很多改动(hack), 他们在某个阶段里基本也是可行的。随着时间的推移,[.filename]##a.out##格式 不得不增加大量的代码和复杂度来满足这些需求。虽然ELF格式 解决了许多这样的问题,但是从一个可用的系统迁移到另一个系统却是痛苦的。因此 直到继续保留[.filename]##a.out##格式的代价比迁移到ELF格式 的代价还大的时候,人们才会最终转换到ELF格式。 然而,随着时间的推移,FreeBSD系统本身的编译工具(特别是汇编器和装载器) 赖以派生的编译工具,其发展却形成了两个平行的分支。FreeBSD这个分支增加了共享库, 并修改了一些错误。而原先编写了这些工具的GNU人则重写了这些工具,并对交叉编译提供了 更简化的支持,还随意插入了不同格式的支持,等等。虽然很多人希望创建针对FreeBSD的 交叉编译器,但他们却并未如愿以偿,因为FreeBSD的as 和ld的源代码更为老旧,所以无法完成这个任务。 新的GNU工具链(binutils)则确实支持交叉编译,ELF 格式,共享库,C++扩展,等等。并且,由于很多供应商都发布ELF格式的 二进制文件,因而让FreeBSD能够运行它们将是一个很好的事情。 ELF格式比[.filename]##a.out##格式开销要大些,同时也 允许基础系统有更好的扩展性。ELF格式的有关工具有着更好的维护, 并且提供交叉编译支持,这对许多人来说是很重要的。ELF格式可能会稍微 慢一些,但很难测量出来。另外,在这两者之间,有许多细节也是不同的,比如它们映射页面的方式, 处理初始化代码的方式,等等。所有这些都不太重要,但这也确实是不同之处。在将来的适当时候, [.filename]##GENERIC##内核将不再支持[.filename]##a.out##格式,并且, 当不再需要运行遗留的[.filename]##a.out##格式程序时,内核也将不再提供对其的支持。 [[basics-more-information]] == 取得更多的资讯 [[basics-man]] === 联机手册 最详细的使用说明文档莫过于 FreeBSD 里的联机手册了。 几乎每一个程序都会附上一份简短说明, 以介绍这个程序的的基本功能以及参数的用法。 我们能通过 `man` 命令来阅读这些说明, 而使用 `man` 命令却是简单的事情: [source,shell] .... % man command .... `command` 就是您要了解的命令命称。 举个例子,想了解 `ls` 命令就输入: [source,shell] .... % man ls .... 这些在线手册分下列章节: . 用户命令。 . 系统调用以及错误代码。 . C 库文件里的函数说明。 . 设备驱动程序。 . 文件格式。 . 游戏以及其他娱乐。 . 各种资讯。 . 系统维护以及命令。 . 内核开发情况。 在某些情况下,同样的主题也会出现在在线手册的不同章节。 举个例子,系统里有``chmod``这个用户命令,而又有个 `chmod()` 系统调用。 在这种情形下,您应当向 `man` 命令指定需要的内容: [source,shell] .... % man 1 chmod .... 这样就会显示出手册里的用户 `chmod` 命令。 传统上,我们在写入文档时把特定详细参考内容在在线手册括号里注明。 所以 man:chmod[1] 是指 `chmod` 用户命令, 而 man:chmod[2] 是指系统调用。 如果您已经知道命令的名字,只是不知道要怎样使用的话,那就比较好办。 但您连名字都不知道呢?这个时候您就可以利用 `man` 的搜寻功能, 它会在手册的介绍部份找寻您要搜寻的关键字,它的选项是 `-k`: [source,shell] .... % man -k mail .... 当您使用这个命令的时候,man会把介绍里含有"mail"关键字 的命令列出来,实际上这和``apropos``命令的功能是相同的。 有时您会看到[.filename]##/usr/bin## 下有许多命令但不知他们的用途, 您只需这样做: [source,shell] .... % cd /usr/bin % man -f * .... 或者这样做 [source,shell] .... % cd /usr/bin % whatis * .... 两个命令是一样的。 [[basics-info]] === GNU Info 文件 FreeBSD许多应用软件以及实用工具来自Free软件基金会(FSF)。 作为手册的扩充,这些程序提供了一种更具有活力的超文档说明``info``, 您可用``info``命令来阅读他们。 假如您装上emacs,也能利用emacs 的info模式来阅读。 使用 man:info[1] 这个命令只需简单地输入: [source,shell] .... % info .... 想得到简单介绍, 请按 `h`。 想快速得到的命令说明, 请按 `?`。