18.2 接口和LSB

现在我们将讨论比C语言代码高一个层次的由操作系统提供的接口(系统函数)。这一级别的标准化工作由下面两个组件构成:由函数库提供的函数和由底层的操作系统提供的系统调用。在这两个组件之中又分别包含两个层次的细节:提供的是哪一个接口和接口的定义。

在这一领域的针对Linux的权威性文档是LSB,你可以在http://www.linuxbase.org或http://www.linux-foundation.org/en/LSB上找到它。该标准已发布了多个版本,其工作还正在进行之中。

你可以在http://www.linux-foundation.org/en/products上找到通过验证的Linux发行版列表。Red Hat、SUSE和Ubuntu的各种版本都通过了验证,但请记住,一个发行版在发布之后需要经过一段时间的测试来通过验证。这个站点还列出了正处于测试中的发行版,以及需要进行一些更新才能通过验证测试的发行版。

Linux标准化规范(版本3.1)定义了3个需要遵守的领域。

❑ 核心:主要的函数库、工具和一些重要的文件系统位置。

❑ C++:C++函数库。

❑ 桌面:用于桌面安装的其他文件,主要是各种图形库。

我们感兴趣的主要领域是这个规范的核心部分。

LSB规范在其自身的文档中涵盖了许多领域,同时它还引用了一些针对特定接口定义的外部标准。其涵盖的领域包括:

❑ 可兼容二进制程序的对象格式;

❑ 动态链接标准;

❑ 标准函数库,包括基础函数库和X视窗系统函数库;

❑ shell和其他命令行程序;

❑ 执行环境,包括用户和组;

❑ 系统初始化和运行级别。

在本章中,我们只对标准函数库、用户和系统初始化感兴趣,所以这也是下面将要介绍的内容。

18.2.1 LSB标准函数库

LSB定义了必须以两种方式呈现的接口。对于那些主要是由GNU C函数库实现的或试图成为Linux专属标准的函数,它定义接口及其行为。对于主要来自UNIX系统的其他接口,规范只是说明必须存在一个特定接口,并且该接口的行为必须与其他标准定义的一样,这里所说的其他标准通常指的是公共应用环境(Common Application Environment,CAE)或更常见的单一UNIX规范(Single UNIX Specification)。后者的网址为http://www.opengroup.org,其中一部分内容可以通过http://www.unix.org/online.html(需要注册)访问。

但遗憾的是,Linux的底层标准,即UNIX标准的历史非常复杂,存在相当多的标准可供选择,虽然其中大部分标准的不同版本之间的兼容性都很好。

1.UNIX标准历史简介

UNIX诞生在20世纪60年代末的AT&T公司的贝尔实验室。最初,Ken Thompson和Dennis Ritchie只是处于个人使用的目的编写了一个操作系统并将其命名为Unics,不知何故这个名字后来又被更名为UNIX。AT&T公司允许大学获取该操作系统的源代码来进行研究,并且由于UNIX非常整洁的设计和强大的概念,它很快就变得非常流行。开放源代码也产生了非常重大的意义,因为它允许人们对其进行修改和实验。

BSD操作系统作为UNIX系统的一个分支,由加州大学伯克利分校开发,其中的许多工作主要集中在操作系统的网络功能上。

当AT&T公司在20世纪80年代中期开始将UNIX系统商业化时,它对其发布的UNIX系统进行了命名,其中最流行的一个版本是UNIX System V。

与此同时,也出现了许多其他的UNIX分支,数量太多,我们就不在这里一一列出了。这些UNIX分支都与UNIX基本的标准有些细微的区别并增加了一些功能,因为公司一般都会尝试通过私有扩展来增加操作系统的功能。

1994年,当AT&T决定退出UNIX产业并将它的UNIX系统实验室卖给Novell公司之后,情况开始变得真正复杂起来,UNIX商标的所有权变得有些混乱,并成为了各种诉讼案件的主题。1988年,IEEE(http://www.ieee.org)发表了一系列UNIX标准中的第一个标准POSIX(又被称为IEEE 1003标准),它试图成为权威性的针对计算机环境的可移植接口规范。虽然它是一个好的、定义明确的标准,但同时它也是一个非常核心的规范并且它所涵盖的范围也非常有限。

1994年,X/OPEN公司作为一个厂商中立的机构,发表了一组较大规模的规范X/OPEN CAE(又被称为公共应用环境),它是IEEE POSIX标准的一个超集并且从技术角度来说有很多领域与它相同。X/OPEN公司后来和OSF合并成立了Open Group,它的网址是http://www.opengroup.org/。CAE标准在2002年被更新并以单一UNIX规范版本3的形式由Open Group发表。

单一UNIX规范是Linux标准化规范最常参考的一个规范。

注意,“Linux”是一个由Linus Torvalds拥有的商标(见http://www.linuxmark.org/)。

2.针对函数库使用LSB标准

上一节的介绍对读者了解UNIX标准的历史已经足够,但这对那些希望自己编写的C语言(或C++语言)的程序可移植的程序员来说意味着什么呢?

首先,需要检查你所使用的库函数是否被列在了LSB规范中。如果它不在这个规范中,你所编写的程序就可能不会那么容易地被移植,这时就需要查找一种标准的方法来执行你想要完成的工作。你可能需要用Linux命令apropos来搜索在线手册页,以找到合适的帮助页面。

其次,也是更困难的一步,就是检查你所使用的函数行为是否是规范定义的行为,并且没有在程序中依赖系统特定的函数行为。如果函数的用法未在LSB中定义,你可能不得不参考单一UNIX规范来检查。

用于检查未定义或可能产生错误行为的函数的一个非常好的方法是使用Linux的在线手册。手册中的许多页面都包含一个BUGS(漏洞)小节,它是一个无价的信息来源。它可以告诉我们,Linux中的某个特定函数调用可能没有完全按照标准中的定义来实现,或者它在执行时有一些已知的漏洞或奇怪的行为。

18.2.2 LSB用户和组

规范中这一部分的内容非常简明且容易理解。下面是一些规范中的定义。

❑ 它告诉我们,一定不能直接读取如/etc/passwd这样的文件,而是应该总是使用如getpwent这样的标准库函数调用或者如passwd这样的标准工具来访问用户详细信息。

❑ 它告诉我们,在root组中必须有一个名为root的用户,这个root用户是一个拥有全部权限的管理员。同时还有一组可选的用户和组也绝对不能在标准应用程序中使用,它们由Linux发行版自身来使用。

❑ 它还告诉我们,用户ID小于100的账号是系统账号,用户ID在100到499之间的账号是由系统管理员和安装后脚本分配的,用户ID在500及其以上的账号用于普通用户。

一般来说,上面这些内容对大多数需要了解用户标准的Linux程序员来说已足够。

18.2.3 LSB系统初始化

至少对于我们来说,系统初始化方面的内容总是一件在不同Linux发行版之间有着细微区别的让人烦恼的事情。

Linux继承了类UNIX操作系统运行级别的思想,运行级别定义了在不同级别中允许启动的服务。对于Linux来说,常见的运行级别定义见表18-1。

表 18-1

18.2 接口和LSB - 图1

LSB列出了这些运行级别,但并不要求使用它们,但实际上它们是非常常见的。

与这些运行级别相伴的是一组用于启动、关闭和重启服务的初始化脚本。以前的Linux系统会将这些脚本放在/etc目录下的不同位置,一般是放在目录/etc/init.d或/etc/rc.d/init.d下。这种不确定性通常让用户困惑,因为当他们更换了Linux发行版后,他们就不能在期望的目录下找到初始化脚本了,而且在安装程序时,当你试图将初始化脚本放在一个错误的目录下时,也会导致安装程序失败。

LSB 3.1将这些初始化脚本放置的目录定义为/etc/init.d,但它也允许这个目录可以是对其他目录的一个连接。

在/etc/init.d目录中的每个脚本都有一个与其提供的服务相关联的名字。由于这是在Linux系统中所有服务必须共享的一个公用命名空间,所以保证名字的唯一性是非常重要的。例如,如果MySQL和PostgreSQL都决定将它们的脚本命名为database,那么情况就会变得比较复杂。为了避免发生这样的冲突,我们还有另外一组标准,它就是“Linux分配名字和数字机构”(Linux Assigned Names And Numbers Authority,简称为LANANA),它的网址为http://www.lanana.org/。幸运的是,你不需要对它了解太多,只需要知道它维护了一个已注册脚本和软件包名字列表,从而减轻了Linux系统用户的工作负担。

初始化脚本必须用一个参数来控制它的行为。已定义的参数见表18-2。

表 18-2

18.2 接口和LSB - 图2

所有的命令在成功时返回0,失败时返回表明错误原因的错误代码。使用status参数时,如果服务正在运行则返回0,否则返回表明服务没有运行原因的状态码。