unix限制

        UNIX系统实现定义了很多幻数和常量,其中有很多已被硬编码到程序中,或用特定的技术确定。由于大量标准化工作的努力,已有若干种可移植的方法用以确定这些幻数和具体实现定义的限制。这非常有助于改善UNIX环境下软件的可移植性。
        以下两种类型的限制是必需的:
        1、编译时限制(例如,短整型的最大值是什么?)
        2、运行时限制(例如,文件名有多少个字符?)
        编译时限制可在头文件中定义,程序在编译时可以包含这些头文件。但是,运行时限制则要求进程调用一个函数获得限制值。
        另外,某些限制在一个给定的实现中可能是固定的(因此可以静态地定义在一个头文件中),而在另一个实现中则可能是变动的(需要有一个运行时函数调用)。这种类型限制的一个例子是文件名的最大字符数。为了解决这类问题,提供了以下3种限制:
        1、编译时限制(头文件)。
        2、与文件或目录无关的运行时限制(sysconf 函数)。
        3、与文件或目录有关的运行时限制(pathconf 和 fpathconf 函数)。
        如果一个特定的运行时限制在一个给定的系统中并不改变,则可将其静态地定义在一个头文件中。但是,如果没有将其定义在头文件中,应用程序就必须调用3个conf函数中的一个,以确定其运行时限制。
        要如何才能找到一个特定系统实际支持的限制值呢?运行时限制可调用下面三个函数之一获得:
#include <unistd.h>

long sysconf(int name);
long pathconf(const char *pathname, int name);   // 用路径名作为参数
long fpathconf(int fd, int name);                // 用文件描述符作为参数
           /* 所有函数返回值:若成功,返回相应值;若出错,返回 -1 */

        sysconf函数的name参数用来标识系统限制,以 _SC_ 开始的常量用作标识运行时限制的syscon参数。下表是sysconf函数所使用的name参数:
限制名 说明 name参数
ARG_MAX exec函数的参数最大长度(字节) _SC_ARG_MAX
ATEXIT_MAX 可用atexit函数登记的最大函数个数 _SC_ATEXIT_MAX
CHILD_MAX 每个实际用户ID的最大进程数 _SC_CHILD_MAX
时钟滴答/秒 每秒时钟滴答数 _SC_CLK_TCK
COLL_WEIGHTS_MAX 本地定义文件中可赋予LC_COLLATE顺序关键字项的最大权重数 _SC_COLL_WEIGHTS_MAX
DELAYTIMER_MAX 定时器最大超限运行次数 _SC_DELAYTIMER_MAX
HOST_NAME_MAX gethostname函数返回的主机名最大长度 _SC_HOST_NAME_MAX
IOV_MAX readv或writev函数可使用的最多iovec结构的个数 _SC_IOV_MAX
LINE_MAX 实用程序输入行的最大长度 _SC_LINE_MAX
LOGIN_NAME_MAX 登录名的最大长度 _SC_LOGIN_NAME_MAX
NGROUPS_MAX 每个进程同时添加的最大进程组ID数 _SC_NGROUPS_MAX
OPEN_MAX 每个进程最大打开文件数 _SC_OPEN_MAX
PAGESIZE 系统存储页长度(字节) _SC_PAGESIZE
PAGE_SIZE 系统存储页长度(字节) _SC_PAGE_SIZE
RE_DUP_MAX 使用间隔表示法\{m,n\}时,函数regexec和regcomp允许的基本正则表达式重复发生次数 _SC_RE_DUP_MAX
RTSIG_MAX 为应用程序预留的实时信号的最大个数 _SC_RTSIG_MAX
SEM_NSEMS_MAX 一个进程可使用的信号量最大个数 _SC_SEM_NSEMS_MAX
SEM_VALUE_MAX 信号量的最大值 _SC_SEM_VALUE_MAX
SIGQUEUE_MAX 一个进程可排队信号的最大个数 _SC_SIGQUEUE_MAX
STREAM_MAX 一个_SC_STREAM_MAX进程在任意给定时刻标准I/O流的最大个数。如果定义,必须与FOPEN_MAX有相同值 _SC_STREAM_MAX
SYMLOOP_MAX 在解析路径名时,可遍历的符号链接数 _SC_SYMLOOP_MAX
TIMER_MAX 每个进程的最大定时器个数 _SC_TIMER_MAX
TTY_NAME_MAX 终端设备名长度,包括终止null字节 _SC_TTY_NAME_MAX
TZNAME_MAX 时区名中的最大字节数 _SC_TZNAME_MAX

        pathconf和fpathconf函数为标识系统限制所使用的name参数如下表:
限制名 说明 name参数
FILESISEBITS 以带符号整型值表示在指定目录中允许的普通文件最大长度所需的最小位数 _PC_FILESISEBITS
LINK_MAX 文件链接计数的最大值 _PC_LINE_MAX
MAX_CANON 终端规范输入队列的最大字节数 _PC_MAX_CANON
MAX_INPUT 终端输入队列可用空间的字节数 _PC_MAX_INPUT
NAME_MAX 文件名的最大字节数(不包括终止null字节) _PC_NAME_MAX
PATH_MAX 相对路径名的最大字节数,包括终止null字节 _PC_PATH_MAX
PIPE_BUF 能原子地写到管道的最大字节数 _PC_PIPE_BUF
_POSIX_TIMESTAMP_RESOLUTION 文件时间戳的纳秒精度 _PC_TIMESTAMP_RESOLUTION
SYMLINK_MAX 符号链接的字节数 _PC_SYMLINK_MAX

        现在再来详细地讨论一下这3个函数不同的返回值。
        1、若name参数不是一个合适的常量,这3个函数都返回-1,并把errno置为EINVAL。
        2、有些name会返回一个变量值(>=0)或者提示该值是不确定的。不确定的值通过返回-1来体现,而不改变errno的值。
        3、_SC_CLK_TCK的返回值是每秒的时钟滴答数,用于times函数的返回值。
        对于pathconf的参数pathname和fpathconf的参数fd有很多限制。如果不满足以下其中任何一个限制,则结果是未定义的:
        1、_PC_MAX_CANON和_PC_MAX_INPUT引用的文件必须是终端文件。
        2、_PC_LINK_MAX和_PC_TIMESTAMP_RESOLUTION引用的文件可以是文件或目录。如果是目录,则返回值用于目录本身,而不用于目录内的文件名项。
        3、_PC_FILESIZEBITS和_PC_NAME_MAX引用的文件必须是目录,返回值用于该目录中的文件名。
        4、_PC_PATH_MAX引用的文件必须是目录。但所指定的目录是工作目录时,返回值是相当路径名的最大长度。
        5、_PC_PIPE_BUF引用的文件必须是管道、FIFO或目录。在管道或FIFO情况下,返回值是对所引用的管道或FIFO的限制值。对于目录,返回值是对在该目录中创建的任一FIFO的限制值。
        6、_PC_SYMLINK_MAX引用的文件必须是目录。返回值是该目录中符号链接可包含字符串的最大长度。
        下面这个程序可用来打印这些限制:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>

static void pr_sysconf(char *, int);
static void pr_pathconf(char *, char *, int);

int main(int argc, char **argv){
	if(argc != 2){
		printf("usage: %s <dirname>", argv[0]);
		exit(0);
	}

#ifdef ARG_MAX
	printf("ARG_MAX defined to be %ld\n", (long)ARG_MAX+0);
#else
	printf("no symbol for ARG_MAX\n");
#endif
#ifdef _SC_ARG_MAX
	pr_sysconf("ARG_MAX =", _SC_ARG_MAX);
#else
	printf("no symbol for _SC_ARG_MAX\n");
#endif

	/* similar processing for all the rest of the sysconf symbols ... */

#ifdef MAX_CANON
	printf("MAX_CNAON defined to be %ld\n", (long)MAX_CANON+0);
#else
	printf("no symbol for MAX_CANON\n");
#endif
#ifdef _PC_MAX_CANON
	pr_pathconf("MAX_CANON =", argv[1], _PC_MAX_CANON);
#else
	printf("no symbol for _PC_MAX_CANON\n");
#endif

	/* similar processing for all the rest of the pathconf symbols ... */

	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){
			if(errno == EINVAL)
				fputs(" (not supported)\n", stdout);	
			else
				printf("sysconf error\n");
		}else{
			fputs(" (no limit)\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){
			if(errno == EINVAL)	
				fputs(" (not supported)\n", stdout);
			else
				printf("pathconf error, path = %s\n", path);
		}else{
			fputs(" (no limit)\n", stdout);
		}
	}else{
		printf(" %ld\n", val);	
	}
}


参考书籍:《UNIX环境高级编程》第二章:UNIX标准及实现。

猜你喜欢

转载自aisxyz.iteye.com/blog/2367287