AUPE学习第二章------UNIX标准化及实现1

下面的这些程序打印一些限制,并处理一个限制未被定义的情况。打印所有可能的sysconfi和pathconfig值。

syspathconf.c:

#include        <errno.h>
#include        "ourhdr.h"
#include        "error.c"
static void     pr_sysconf(char *, int);
static void     pr_pathconf(char *, char *, int);

int main(int argc, char *argv[])
{
        if (argc != 2)
                err_quit("usage: a.out <dirname>");

        pr_sysconf("ARG_MAX            =", _SC_ARG_MAX);
        pr_sysconf("CHILD_MAX          =", _SC_CHILD_MAX);
        pr_sysconf("clock ticks/second =", _SC_CLK_TCK);
        pr_sysconf("NGROUPS_MAX        =", _SC_NGROUPS_MAX);
        pr_sysconf("OPEN_MAX           =", _SC_OPEN_MAX);
        #ifdef  _SC_STREAM_MAX
        pr_sysconf("STREAM_MAX         =", _SC_STREAM_MAX);
        #endif
        #ifdef  _SC_TZNAME_MAX
        pr_sysconf("TZNAME_MAX         =", _SC_TZNAME_MAX);
        #endif
        pr_sysconf("_POSIX_JOB_CONTROL =", _SC_JOB_CONTROL);
        pr_sysconf("_POSIX_SAVED_IDS   =", _SC_SAVED_IDS);
        pr_sysconf("_POSIX_VERSION     =", _SC_VERSION);
        pr_pathconf("MAX_CANON       =", "/dev/tty", _PC_MAX_CANON);
        pr_pathconf("MAX_INPUT       =", "/dev/tty", _PC_MAX_INPUT);
        pr_pathconf("_POSIX_VDISABLE =", "/dev/tty", _PC_VDISABLE);
        pr_pathconf("LINK_MAX        =", argv[1], _PC_LINK_MAX);
        pr_pathconf("NAME_MAX        =", argv[1], _PC_NAME_MAX);
        pr_pathconf("PATH_MAX        =", argv[1], _PC_PATH_MAX);
        pr_pathconf("PIPE_BUF        =", argv[1], _PC_PIPE_BUF);
        pr_pathconf("_POSIX_NO_TRUNC =", argv[1], _PC_NO_TRUNC);
        pr_pathconf("_POSIX_CHOWN_RESTRICTED =",argv[1], _PC_CHOWN_RESTRICTED);
        exit(0);
}

static void pr_sysconf(char *mesg, int name)
{
        long    val;

        fputs(mesg, stdout);
        errno = 0;
        if ( (val = sysconf(name)) < 0) {
                if (errno != 0)
                        err_sys("sysconf error");
                fputs(" (not defined)\n", stdout);
        } else
                printf(" %ld\n", val);
}

static void pr_pathconf(char *mesg, char *path, int name)
{
        long    val;

        fputs(mesg, stdout);
        errno = 0;
        if ( (val = pathconf(path, name)) < 0) {
                if (errno != 0)
                        err_sys("pathconf error, path = %s", path);
                fputs(" (no limit)\n", stdout);
        } else
                printf(" %ld\n", val);
}
所有的限制在我的系统中都已经定义了。哈哈。。o(∩_∩)o 哈哈

执行结果如下:

[root@localhost apue]# gcc -o syspathconf.out syspathconf.c 
[root@localhost apue]# ./syspathconf.out 
usage: a.out <dirname>
[root@localhost apue]# ./syspathconf.out /
ARG_MAX            = 131072
CHILD_MAX          = 999
clock ticks/second = 100
NGROUPS_MAX        = 65536
OPEN_MAX           = 1024
STREAM_MAX         = 16
TZNAME_MAX         = 6
_POSIX_JOB_CONTROL = 1
_POSIX_SAVED_IDS   = 1
_POSIX_VERSION     = 200112
MAX_CANON       = 255
MAX_INPUT       = 255
_POSIX_VDISABLE = 0
LINK_MAX        = 32000
NAME_MAX        = 255
PATH_MAX        = 4096
PIPE_BUF        = 4096
_POSIX_NO_TRUNC = 1
_POSIX_CHOWN_RESTRICTED = 1

2.5.5FIPS 151-1要求

F I P S的含义是联邦信息处理标准(Federal Information Processing Standard),这些标准是由
美国政府出版的,并由美国政府用于计算机系统的采购。F I P S 1 5 1 - 1(1 9 8 9年4月)基于I E E E
S t d . 1 0 0 3 . 1 - 1 9 8 8及ANSI C标准草案。FIPS 151-1要求某些在P O S I X . 1中可选的功能。这种F I P S
有时称为POSIX.1 FIPS。2 . 5 . 5节列出了F I P S所要求的P O S I X . 1的选择项。
POSIX.1 FIPS的影响是:它要求任一希望向美国政府销售P O S I X . 1依从的计算机系统的厂
商应支持P O S I X . 1的某些可选功能。我们将不把POSIX.1 FIPS视作为另一个标准,因为实际上
它只是一个更加严格的P O S I X . 1标准。

FIPS 151-1标准(我们已在2 . 2 . 4节中提及)由于要求下列功能,所以它比P O S I X . 1标准更严:
• 要求下列P O S I X . 1可选功能:_POSIX_JOB_CONTROL, _POSIX_SAVED_IDS, _POSIX_
NO_TRUNC, _POSIX_CHOWN_RESTRICTED和_ P O S I X V D I S A B L E。
• NGROUPS_MAX的最小值是8。
• 新创建的文件或目录的组I D应设置为它所在目录的组I D(4 . 6节将说明此功能)。
• 已传输了一些数据后,若r e a d或w r i t e被一个捕捉到的信号所中断,则这些函数应返回已
被传输的字节数(1 0 . 5节将讨论被中断的系统调用)。
• 登录s h e l l应定义环境变量H O M E和L O G N A M E。
因为美国政府购买了很多计算机系统,所以大多数P O S I X的制造商都将支持这些增加的
F I P S要求。

2.5.6限制总结:

我们已说明了很多限制和幻常数,其中某些必须包含在头文件中,某些可选地包含在头文
件中,其他则可在运行时决定。表2 - 7以字母顺序总结了所有这些常数以及得到它们值的各种
方法。以_ S C _开始的运行时间名字是s y s c o n f函数的参数,以_ P C _开始的名字是p a t h c o n f和
f p a t h c o n f函数的参数,如果它有最小值,则也将其列于其中。

表2-7 编译时间和运行时间限制总结
               编译时间     

常数名   头文件 要求否                     运行时间名               最小值

A R G M A X < l i m i t s . h > 可选_ S C A R G M A X _ P O S I X A R G M A X=4 0 9 6
C H A R B I T < l i m i t s . h > 要求8
C H A R M A X < l i m i t s . h > 要求1 2 7
C H A R M I N < l i m i t s . h > 要求0
C H I L D M A X < l i m i t s . h > 可选_ S C C H I L D M A X _ P O S I X C H I L D M A X =6
每秒时钟滴答_ S C C L K T C K
F O P E N M A X < s t d i o . h > 要求8
I N T M A X < l i m i t s . h > 要求32 767
I N T M I N < l i m i t s . h > 要求-32 767
L I N K M A X < l i m i t s . h > 可选_ P C L I N K M A X _ P O S I X L I N K M A X=8
L O N G M A X < l i m i t s . h > 要求2 147 483 647
L O N G M I N < l i m i t s . h > 要求-2 147 483 647
M A X C A N O N < l i m i t s . h > 可选_ P C M A X C A N O N _ P O S I X M A X C A N O N =2 5 5
M A X I N P U T < l i m i t s . h > 可选_ P C M A X I N P U T _ P O S I X M A X I N P U T =2 5 5
M B L E N M A X < l i m i t s . h > 要求
N A M E M A X < l i m i t s . h > 可选_ P C N A M E M A X _ P O S I X N A M E M A X=1 4
N G R O U P S M A X < l i m i t s . h > 要求_SC_NGROUPS_MAX _ P O S I X N G R O U P S M A X =0
N L A R G M A X < l i m i t s . h > 要求9
N L L A N G M A X < l i m i t s . h > 要求1 4
N L M S G M A X < l i m i t s . h > 要求32 767
N L N M A X < l i m i t s . h > 要求
N L S E T M A X < l i m i t s . h > 要求2 5 5
N L T E X T M A X < l i m i t s . h > 要求2 5 5
N Z E R O < l i m i t s . h > 要求2 0
O P E N M A X < l i m i t s . h > 可选_ S C O P E N M A X _ P O S I X O P E N M A X=1 6
P A S S M A X < l i m i t s . h > 可选_ S C P A S S M A X 8
P A T H M A X < l i m i t s . h > 可选_ P C P A T H M A X _ P O S I X P A T H M A X=2 5 5
P I P E B U F < l i m i t s . h > 可选_ P C P I P E B U F _ P O S I X P I P E B U F =5 1 2
S C H A R M A X < l i m i t s . h > 要求1 2 7
S C H A R M I N < l i m i t s . h > 要求-1 2 7
S H R T M A X < l i m i t s . h > 要求32 767
S H R T M I N < l i m i t s . h > 要求-32 767
S S I Z E M A X < l i m i t s . h > 要求_ P O S I X S S I Z E M A X=3 2 , 7 6 7
S T R E A M M A X < l i m i t s . h > 可选_ S C S T R E A M M A X _ P O S I X S T R E A M M A X =8
T M P M A X < s t d i o . h > 要求1 0 , 0 0 0
T Z N A M E M A X < l i m i t s . h > 可选_SC_TZNAME_MAX _ P O S I X T Z N A M E MAX=3
U C H A R M A X < l i m i t s . h > 要求2 5 5
U I N T M A X < l i m i t s . h > 要求65 535
U L O N G M A X < l i m i t s . h > 要求4 294 967 295
U S H R T M A X < l i m i t s . h > 要求65 535
_ P O S I X C H O W N R E S T R I C T E D < u n i s t d . h > 可选_ P C C H O W N R E S T R I C T E D
_ P O S I X J O B C O N T R O L < u n i s t d . h > 可选_ S C J O B C O N T R O L
_ P O S I X N O T R U N C < u n i s t d . h > 可选_ P C N O T R U N C
_ P O S I X S A V E D I D S < u n i s t d . h > 可选_ S C S A V E D I D S
_ P O S I X V D I S A B L E < u n i s t d . h > 可选_ P C V D I S A B L E
_ P O S I X V E R S I O N < u n i s t d . h > 要求_ S C V E R S I O N
_ X O P E N V E R S I O N < u n i s t d . h > 要求_ S C X O P E N V E R S I O N

具体可以看AUPE书上的表格。

2.5.7未确定的运行时间限制

我们已提及表2 - 7中的某些值可能是未确定的,这些值在第三列中标记为可选的( o p t i o n a l ),
其名字中包含M A X,或P I P E B U F。我们遇到的问题是如果这些值没有在头文件< l i m i t s . h >中定
义,那么在编译时我们也就不能使用它们。但是,如果它们的值是未确定的,那么在运行时它
们可能也是未定义的。让我们观察两个特殊的例子—为一个路径名分配存储器,以及决定文
件描述符的数目。

1. 路径名
很多程序需要为路径名分配存储器,一般来说,在编译时就为其分配了存储器,而且使用
了各种幻数(其中很少是正确的)作为数组长度: 2 5 6,5 1 2,1 0 2 4或标准I / O常数B U F S I Z。
4 . 3 B S D头文件< s y s / p a r a m . h >中的常数M A X PAT H L E N是正确值,但是很多4 . 3 B S D应用程序并
未用它。
P O S I X . 1试图用PAT H M A X值来帮助我们,但是如果此值是不确定的,那么仍是毫无帮助
的。程序2 - 2是一个全书都将使用的为路径名动态地分配存储器的函数。
如若在< l i m i t s . h >中定义了常数PAT H M A X ,那么就没有任何问题,如果没有,则需调用
p a t h c o n f。因为p a t h c o n f的返回值是把第一个参数视为基于工作目录的相对路径名。所以指定根
为第一个参数,并将得到的返回值加1作为结果值。如果p a t h c o n f指明PAT H M A X是不确定的,
那么我们就只得猜测某个值。调用m a l l o c时的+ 1是为了在尾端加n u l l字符(PAT H M A X没有考
虑它)。

程序2-2 为路径名动态地分配空间

pathtest.c代码:

#include <errno.h>
#include <limits.h>
#include "ourhdr.h"
#include "error.c"

#ifdef PATH_MAX
static int pathmax = PATH_MAX;
#else
static int pathmax = 0;
#endif

#define PATH_MAX_GUESS 1024

char * path_alloc(int *size)
{
    char *ptr;
    if (pathmax == 0)
    {
        errno = 0;
        if ((pathmax = pathconf("/", _PC_PATH_MAX)) < 0)
        {
            if (errno == 0)
                pathmax = PATH_MAX_GUESS;
            else
                err_sys("pathconf error for _PC_PATH_MAX");
        }else
            pathmax++;
    }
    if ((ptr = malloc(pathmax + 1)) == NULL)
        err_sys("malloc error for pathname");
    if (size != NULL)
        *size = pathmax +1;
    return(ptr);
}

2 最大打开文件数

在精灵进程(是在后台运行,不与终端相连接的一种进程)中一个常见的代码序列是关闭所
有打开文件。某些程序中有下列形式的代码序列:
#include <sys/param.h>
for (i = 0; i < NOFILE; i++)
c l o s e ( i ) ;
程序假定在< s y s / p a r a m . h >头文件中定义了常数N O F I L E。另外一些程序则使用某些< s t d i o . h >版
本提供作为上限的常数_ N F I L E。某些程序则直接将其上限值定为2 0。
我们希望用P O S I X . 1的O P E N M A X确定此值以提高可移植性,但是如果此值是不确定的,
则仍然有问题,如果我们使用下列代码
#include <unistd.h>
for (i = 0; i < sysconf(_SC_OPEN_MAX); i++)
c l o s e ( i ) ;
而且如果O P E N M A X是不确定的,那么s y s c o n f将返回-1,于是,f o r循环根本不会执行。在这
种情况下,最好的选择就是关闭所有描述符直至某个任一的限制值(例如2 5 6 )。如同上面的路
径名一样,这并不能保证在所有情况下都能正确工作,但这却是我们所能选择的最好方法。

程序2-3 确定文件描述符数:

filetest.c:

#include <errno.h>
#include <limits.h>
#include "ourhdr.h"
#include "error.c"

#ifdef OPEN_MAX
static int openmax = OPEN_MAX;
#else
static int openmax = 0;
#endif

#define OPEN_MAX_GUESS 256

int open_max(void)
{
    if (openmax == 0)
    {
        errno = 0;
        if ((openmax = sysconf(_SC_OPEN_MAX)) < 0)
        {
            if (errno == 0)
                openmax = OPEN_MAX_GUESS;
            else
                err_sys("sysconf error for _SC_OPEN_MAX");
        }
    }
    return(openmax);
}

2.6功能测试宏

正如前述,在头文件中定义了很多P O S I X . 1和X P G 3的符号。但是除了P O S I X . 1和X P G 3定
义外,大多数实现在这些头文件中也加上了它们自己的定义。如果在编译一个程序时,希望它
只使用P O S I X定义而不使用任何实现定义的限制,那么就需定义常数_ P O S I X S O U R C E,所有
P O S I X . 1头文件中都使用此常数。当该常数定义时,就能排除任何实现专有的定义。
常数_ P O S I X S O U R C E及其对应的常数_ X O P E N S O U R C E被称之为功能测试宏( f e a t u r e
test macro)。所有功能测试宏都以下划线开始。当要使用它们时,通常在c c命令行中以下列方
式定义:
cc -D_POSIX_SOURCE file.c
这使得在C程序包括任何头文件之前,定义了功能测试宏。如果我们仅想使用P O S I X . 1定
义,那么也可将源文件的第一行设置为:
#define _POSIX_SOURCE 1
另一个功能测试宏是: _ _STDC_ _,它由符合ANSI C标准的编译程序自动定义。这样就
允许我们编写ANSI C编译程序和非ANSI C编译程序都能编译的程序。例如,一个头文件可能
会是:
#ifdef _ S T D C__
void *myfunc(const char *, int);
# e l s e
void *myfunc();
# e n d i f
这样就能发挥ANSI C原型功能的长处,要注意在开始和结束处的两个连续的下划线常常
打印成一个长下划线(如同上面一个样本源代码中一样)。

2.7 基本系统数据类型

历史上,某些U N I X变量已与某些C数据类型联系在一起,例如,历史上主、次设备号存放
在一个1 6位的短整型中, 8位表示主设备号,另外8位表示次设备号。但是,很多较大的系统需
要用多于2 5 6个值来表示其设备号,于是,就需要有一种不同的技术。(确实, S V R 4用3 2位表
示设备号:1 4位用于主设备号,1 8位用于次设备号。)
头文件< s y s / t y p e s . h >中定义了某些与实现有关的数据类型,它们被称之为基本系统数据类
型(primitive system data type)。有很多这种数据类型定义在其他头文件中。在头文件中这些
数据类型都是用C的t y p e d e f设施来定义的。它们绝大多数都以_t 结尾。表2 - 8中列出了本书将使
用的基本系统数据类型。
表2-8 基本系统数据类型
类型说明
c a d d r t 内存地址( 1 2 . 9节)
c l o c k t 时钟滴答计数器(进程时间)(1 . 1 0节)
c o m p t 压缩的时钟滴答(8 . 1 3节)
d e v t 设备号(主和次)(4 . 2 3节)
f d s e t 文件描述符集( 1 2 . 5 . 1节)
f p o s t 文件位置( 5 . 1 0节)
g i d t 数值组I D
i n o t i节点编号( 4 . 1 4节)
m o d e t 文件类型,文件创建方式( 4 . 5节)
n 1 i n k t 目录项的连接计数( 4 . 1 0节)
o f f t 文件长度和位移量(带符号的)(lseek, 3.6节)
p i d t 进程I D和进程组I D(带符号的)(8 . 2和9 . 4节)
p t r d i f f t 两个指针相减的结果(带符号的)
r 1 i m t 资源限制( 7 . 11节)
s i g a t o m i c t 能原子地存取的数据类型( 1 0 . 1 5节)
s i g s e t t 信号集(1 0 . 11节)
s i z e t 对象(例如字符串)长度(不带符号的)(3 . 7节)
s s i z e t 返回字节计数的函数(带符号的)(read, write, 3.7节)
t i m e t 日历时间的秒计数器( 1 . 1 0节)
u i d t 数值用户I D
w c h a r t 能表示所有不同的字符码
用这种方式定义了这些数据类型后,在编译时就不再需要考虑随系统不同而变的实施细节,
在本书中涉及到这些数据类型的地方,我们会说明为什么使用它们。

2.8标准之间的冲突

就整体而言,这些不同的标准之间配合得是相当好的。但是我们也很关注它们之间的差别,
特别是ANSI C标准和P O S I X . 1之间的差别。(因为X P G 3是一个较老的正在被修订的标准, F I P S
则是一个要求更严的P O S I X . 1。)
ANSI C定义了函数c l o c k,它返回进程使用的C P U时间,返回值是c l o c k t类型值。为了将
此值变换成以秒为单位,将其除以在< t i m e . h >头文件中定义的C L O C K S P E R S E C。P O S I X . 1定
义了函数t i m e s,它返回其调用者及其所有终止子进程的C P U时间以及时钟时间,所有这些值
都是c l o c k t类型值。IEEE Std.1003.1-1988将符号C L K T C K定义为每秒滴答数,上述c l o c k t值
都是以此度量的。而1990 POSIX.1标准中则说明不再使用, C L K T C K而使用s y s c o n f函数来获
得每秒滴答数,并将其用于t i m e s函数的返回值。术语是同一个,每秒滴答数,但ANSI C和
P O S I X . 1的定义却不同。这两个标准也用同一数据类型( c l o c k t )来保存这些不同的值,这种差
别可以在S V R 4中看到,其中c l o c k返回微秒数( C L O C K P E R S E C是一百万),而C L K T C K通常
是5 0、6 0或1 0 0 (与C P U类型有关)。

另一个可能产生冲突的区域是:在ANSI C标准说明函数时,ANSI C所说明的函数可能会
没有考虑到P O S I X . 1的某些要求。有些函数在P O S I X环境下可能要求有一个与C环境下不同的
实现,因为P O S I X环境中有多个进程,而C语言环境则很少会考虑宿主操作系统。尽管如此,
很多P O S I X依从的系统为了兼容性的关系也实现ANSI C函数,s i g n a l函数就是一个例子。如果
在不了解的情况下使用了S V R 4所提供的s i g n a l函数(希望编写可在ANSI C环境和较早U N I X系统
中运行的可兼容程序),那么它提供了与POSIX.1 sigaction函数不同的语义。第1 0章将对s i g n a l
函数作更多说明。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值