11. 进程操作篇
11.1 atexit(设置程序正常结束前调用的函数)
相关函数 _exit,exit,on_exit
表头文件 #include<stdlib.h>
定义函数 int atexit (void (*function)(void));
函数说明 atexit()用来设置一个程序正常结束前调用的函数。当程序通过调用exit()或从main中返回时,
参数function所指定的函数会先被调用,然后才真正由exit()结束程序。
返回值 如果执行成功则返回0,否则返回-1,失败原因存于errno中。
范例 #include<stdlib.h>
void my_exit(void)
{
printf(“before exit () !/n”);
}
main()
{
atexit (my_exit);
exit(0);
}
执行 before exit()!
11.2 execl(执行文件)
相关函数 fork,execle,execlp,execv,execve,execvp
表头文件 #include<unistd.h>
定义函数 int execl(const char * path,const char * arg,....);
函数说明 execl()用来执行参数path字符串所代表的文件路径,接下来的参数代表执行该文件时传递过
去的argv(0)、argv[1]……,最后一个参数必须用空指针(NULL)作结束。
返回值 如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。
范例 #include<unistd.h>
main()
{
execl(“/bin/ls”,”ls”,”-al”,”/etc/passwd”,(char * )0);
}
执行 /*执行/bin/ls -al /etc/passwd */
-rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
11.3 execlp(从PATH 环境变量中查找文件并执行)
相关函数 fork,execl,execle,execv,execve,execvp
表头文件 #include<unistd.h>
定义函数 int execlp(const char * file,const char * arg,……);
函数说明 execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件
,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作
结束。
返回值 如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。
错误代码 参考execve()。
范例 /* 执行ls -al /etc/passwd execlp()会依PATH 变量中的/bin找到/bin/ls */
#include<unistd.h>
main()
{
execlp(“ls”,”ls”,”-al”,”/etc/passwd”,(char *)0);
}
执行 -rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
11.4 execv(执行文件)
相关函数 fork,execl,execle,execlp,execve,execvp
表头文件 #include<unistd.h>
定义函数 int execv (const char * path, char * const argv[ ]);
函数说明 execv()用来执行参数path字符串所代表的文件路径,与execl()不同的地方在于execve()只需
两个参数,第二个参数利用数组指针来传递给执行文件。
返回值 如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。
错误代码 请参考execve()。
范例 /* 执行/bin/ls -al /etc/passwd */
#include<unistd.h>
main()
{
char * argv[ ]={“ls”,”-al”,”/etc/passwd”,(char*) }};
execv(“/bin/ls”,argv);
}
执行 -rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
11.5 execve(执行文件)
相关函数 fork,execl,execle,execlp,execv,execvp
表头文件 #include<unistd.h>
定义函数 int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
函数说明 execve()用来执行参数filename字符串所代表的文件路径,第二个参数系利用数组指针来传递
给执行文件,最后一个参数则为传递给执行文件的新环境变量数组
返回值 如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。
错误代码 EACCES
1. 欲执行的文件不具有用户可执行的权限。
2. 欲执行的文件所属的文件系统是以noexec 方式挂上。
3.欲执行的文件或script翻译器非一般文件。
EPERM
1.进程处于被追踪模式,执行者并不具有root权限,欲执行的文件具有SUID 或SGID 位。
2.欲执行的文件所属的文件系统是以nosuid方式挂上,欲执行的文件具有SUID 或SGID 位元,但执行者
并不具有root权限。
E2BIG 参数数组过大
ENOEXEC 无法判断欲执行文件的执行文件格式,有可能是格式错误或无法在此平台执行。
EFAULT 参数filename所指的字符串地址超出可存取空间范围。
ENAMETOOLONG 参数filename所指的字符串太长。
ENOENT 参数filename字符串所指定的文件不存在。
ENOMEM 核心内存不足
ENOTDIR 参数filename字符串所包含的目录路径并非有效目录
EACCES 参数filename字符串所包含的目录路径无法存取,权限不足
ELOOP 过多的符号连接
ETXTBUSY 欲执行的文件已被其他进程打开而且正把数据写入该文件中
EIO I/O 存取错误
ENFILE 已达到系统所允许的打开文件总数。
EMFILE 已达到系统所允许单一进程所能打开的文件总数。
EINVAL 欲执行文件的ELF执行格式不只一个PT_INTERP节区
EISDIR ELF翻译器为一目录
ELIBBAD ELF翻译器有问题。
范例 #include<unistd.h>
main()
{
char * argv[ ]={“ls”,”-al”,”/etc/passwd”,(char *)0};
char * envp[ ]={“PATH=/bin”,0}
execve(“/bin/ls”,argv,envp);
}
执行 -rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
11.6 execvp(执行文件)
相关函数 fork,execl,execle,execlp,execv,execve
表头文件 #include<unistd.h>
定义函数 int execvp(const char *file ,char * const argv []);
函数说明 execvp()会从PATH 环境变量所指的目录中查找符合参数file 的文件名,找到后便执行该文件
,然后将第二个参数argv传给该欲执行的文件。
返回值 如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。
错误代码 请参考execve()。
范例 /*请与execlp()范例对照*/
#include<unistd.h>
main()
{
char * argv[ ] ={ “ls”,”-al”,”/etc/passwd”,0};
execvp(“ls”,argv);
}
执行 -rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
11.7 exit(正常结束进程)
相关函数 _exit,atexit,on_exit
表头文件 #include<stdlib.h>
定义函数 void exit(int status);
函数说明 exit()用来正常终结目前进程的执行,并把参数status返回给父进程,而进程所有的缓冲区数
据会自动写回并关闭未关闭的文件。
返回值
范例 参考wait()
11.8 exit(结束进程执行)
相关函数 exit,wait,abort
表头文件 #include<unistd.h>
定义函数 void _exit(int status);
函数说明 _exit()用来立刻结束目前进程的执行,并把参数status返回给父进程,并关闭未关闭的文件。
此函数调用后不会返回,并且会传递SIGCHLD信号给父进程,父进程可以由wait函数取得子进程结束
状态。
返回值
附加说明 _exit()不会处理标准I/O 缓冲区,如要更新缓冲区请使用exit()。
11.9 vfork(建立一个新的进程)
相关函数 wait,execve
表头文件 #include<unistd.h>
定义函数 pid_t vfork(void);
函数说明 vfork()会产生一个新的子进程,其子进程会复制父进程的数据与堆栈空间,并继承父进程的
用户代码,组代码,环境变量、已打开的文件代码、工作目录和资源限制等。Linux 使用copy-on-write
(COW)技术,只有当其中一进程试图修改欲复制的空间时才会做真正的复制动作,由于这些继承的信
息是复制而来,并非指相同的内存空间,因此子进程对这些变量的修改和父进程并不会同步。此外,
子进程不会继承父进程的文件锁定和未处理的信号。注意,Linux不保证子进程会比父进程先执行或晚
执行,因此编写程序时要留意死锁或竞争条件的发生。
返回值 如果vfork()成功则在父进程会返回新建立的子进程代码(PID),而在新建立的子进程中则返回0
。如果vfork 失败则直接返回-1,失败原因存于errno中。
错误代码 EAGAIN 内存不足。ENOMEM 内存不足,无法配置核心所需的数据结构空间。
范例 #include<unistd.h>
main()
{
if(vfork() = =0)
{
printf(“This is the child process/n”);
}else{
printf(“This is the parent process/n”);
}
}
执行 this is the parent process
this is the child process
11.10 getpgid(取得进程组识别码)
相关函数 setpgid,setpgrp,getpgrp
表头文件 #include<unistd.h>
定义函数 pid_t getpgid( pid_t pid);
函数说明 getpgid()用来取得参数pid 指定进程所属的组识别码。如果参数pid为0,则会取得目前进程
的组识别码。
返回值 执行成功则返回组识别码,如果有错误则返回-1,错误原因存于errno中。
错误代码 ESRCH 找不到符合参数pid 指定的进程。
范例 /*取得init 进程(pid=1)的组识别码*/
#include<unistd.h>
mian()
{
printf(“init gid = %d/n”,getpgid(1));
}
执行 init gid = 0
11.11 getpgrp(取得进程组识别码)
相关函数 setpgid,getpgid,getpgrp
表头文件 #include<unistd.h>
定义函数 pid_t getpgrp(void);
函数说明 getpgrp()用来取得目前进程所属的组识别码。此函数相当于调用getpgid(0);
返回值 返回目前进程所属的组识别码。
范例 #include<unistd.h>
main()
{
printf(“my gid =%d/n”,getpgrp());
}
执行 my gid =29546
11.12 getpid(取得进程识别码)
相关函数 fork,kill,getpid
表头文件 #include<unistd.h>
定义函数 pid_t getpid(void);
函数说明 getpid()用来取得目前进程的进程识别码,许多程序利用取到的此值来建立临时文件,以
避免临时文件相同带来的问题。
返回值 目前进程的进程识别码
范例 #include<unistd.h>
main()
{
printf(“pid=%d/n”,getpid());
}
执行 pid=1494 /*每次执行结果都不一定相同*/
11.13 getppid(取得父进程的进程识别码)
相关函数 fork,kill,getpid
表头文件 #include<unistd.h>
定义函数 pid_t getppid(void);
函数说明 getppid()用来取得目前进程的父进程识别码
返回值 目前进程的父进程识别码。
范例 #include<unistd.h>
main()
{
printf(“My parent ‘pid =%d/n”,getppid());
}
执行 My parent pid =463
11.14 getpriority(取得程序进程执行优先权)
相关函数 setpriority,nice
表头文件 #include<sys/time.h>
#include<sys/resource.h>
定义函数 int getpriority(int which,int who);
函数说明 getpriority()可用来取得进程、进程组和用户的进程执行优先权。
参数 which有三种数值,参数who 则依which值有不同定义
which who 代表的意义
PRIO_PROCESS who 为进程识别码
PRIO_PGRP who 为进程的组识别码
PRIO_USER who 为用户识别码
此函数返回的数值介于-20 至20之间,代表进程执行优先权,数值越低代表有较高的优先次序,执行会
较频繁。
返回值 返回进程执行优先权,如有错误发生返回值则为-1 且错误原因存于errno。
附加说明 由于返回值有可能是-1,因此要同时检查errno是否存有错误原因。最好在调用次函数前先清
除errno变量。
错误代码 ESRCH 参数which或who 可能有错,而找不到符合的进程。EINVAL 参数which 值错误。
11.15 nice(改变进程优先顺序)
相关函数 setpriority,getpriority
表头文件 #include<unistd.h>
定义函数 int nice(int inc);
函数说明 nice()用来改变进程的进程执行优先顺序。参数inc数值越大则优先顺序排在越后面,即表示
进程执行会越慢。只有超级用户才能使用负的inc 值,代表优先顺序排在前面,进程执行会较快
返回值 如果执行成功则返回0,否则返回-1,失败原因存于errno中。
错误代码 EPERM 一般用户企图转用负的参数inc值改变进程优先顺序。
11.16 on_exit(设置程序正常结束前调用的函数)
相关函数 _exit,atexit,exit
表头文件 #include<stdlib.h>
定义函数 int on_exit(void (* function)(int, void*),void *arg);
函数说明 on_exit()用来设置一个程序正常结束前调用的函数。当程序通过调用exit()或从main中返回时
,参数function所指定的函数会先被调用,然后才真正由exit()结束程序。参数arg指针会传给参数
function函数,详细情况请见范例。
返回值 如果执行成功则返回0,否则返回-1,失败原因存于errno中。
附加说明
范例 #include<stdlib.h>
void my_exit(int status,void *arg)
{
printf(“before exit()!/n”);
printf(“exit (%d)/n”,status);
printf(“arg = %s/n”,(char*)arg);
}
main()
{
char * str=”test”;
on_exit(my_exit,(void *)str);
exit(1234);
}
执行 before exit()!
exit (1234)
arg = test
11.17 setpgid(设置进程组识别码)
相关函数 getpgid,setpgrp,getpgrp
表头文件 #include<unistd.h>
定义函数 int setpgid(pid_t pid,pid_t pgid);
函数说明 setpgid()将参数pid 指定进程所属的组识别码设为参数pgid 指定的组识别码。如果参数pid 为
0,则会用来设置目前进程的组识别码,如果参数pgid为0,则会以目前进程的进程识别码来取代。
返回值 执行成功则返回组识别码,如果有错误则返回-1,错误原因存于errno中。
错误代码 EINVAL 参数pgid小于0。
EPERM 进程权限不足,无法完成调用。
ESRCH 找不到符合参数pid指定的进程。
11.18 setpgrp(设置进程组识别码)
相关函数 getpgid,setpgid,getpgrp
表头文件 #include<unistd.h>
定义函数 int setpgrp(void);
函数说明 setpgrp()将目前进程所属的组识别码设为目前进程的进程识别码。此函数相当于调用
setpgid(0,0)。
返回值 执行成功则返回组识别码,如果有错误则返回-1,错误原因存于errno中。
11.19 setpriority(设置程序进程执行优先权)
相关函数 getpriority,nice
表头文件 #include<sys/time.h>
#include<sys/resource.h>
定义函数 int setpriority(int which,int who, int prio);
函数说明 setpriority()可用来设置进程、进程组和用户的进程执行优先权。参数which有三种数值,参数
who 则依which值有不同定义
which who 代表的意义
PRIO_PROCESS who为进程识别码
PRIO_PGRP who 为进程的组识别码
PRIO_USER who为用户识别码
参数prio介于-20 至20 之间。代表进程执行优先权,数值越低代表有较高的优先次序,执行会较频繁。
此优先权默认是0,而只有超级用户(root)允许降低此值。
返回值 执行成功则返回0,如果有错误发生返回值则为-1,错误原因存于errno。
ESRCH 参数which或who 可能有错,而找不到符合的进程
EINVAL 参数which值错误。
EPERM 权限不够,无法完成设置
EACCES 一般用户无法降低优先权
11.20 system(执行shell 命令)
相关函数 fork,execve,waitpid,popen
表头文件 #include<stdlib.h>
定义函数 int system(const char * string);
函数说明 system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所
代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁
置,SIGINT和SIGQUIT 信号则会被忽略。
返回值 如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针
(NULL),则返回非零值。如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值
也有可能为system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。
附加说明 在编写具有SUID/SGID权限的程序时请勿使用system(),system()会继承环境变量,通过环境
变量可能会造成系统安全的问题。
范例 #include<stdlib.h>
main()
{
system(“ls -al /etc/passwd /etc/shadow”);
}
执行 -rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
-r--------- 1 root root 572 Sep 2 15 :34 /etc/shadow
11.21 wait(等待子进程中断或结束)
相关函数 waitpid,fork
表头文件 #include<sys/types.h>
#include<sys/wait.h>
定义函数 pid_t wait (int * status);
函数说明 wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进
程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子
进程的进程识别码也会一快返回。如果不在意结束状态值,则
参数 status可以设成NULL。子进程的结束状态值请参考waitpid()。
返回值 如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno中。
附加说明
范例 #include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
main()
{
pid_t pid;
int status,i;
if(fork()= =0){
printf(“This is the child process .pid =%d/n”,getpid());
exit(5);
}else{
sleep(1);
printf(“This is the parent process ,wait for child.../n”;
pid=wait(&status);
i=WEXITSTATUS(status);
printf(“child’s pid =%d .exit status=^d/n”,pid,i);
}
}
执行 This is the child process.pid=1501
This is the parent process .wait for child...
child’s pid =1501,exit status =5
11.22 waitpid(等待子进程中断或结束)
相关函数 wait,fork
表头文件 #include<sys/types.h>
#include<sys/wait.h>
定义函数 pid_t waitpid(pid_t pid,int * status,int options);
函数说明 waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子
进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status返回,而子
进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status可以设成NULL。参数pid为欲
等待的子进程识别码,其他数值意义如下:
pid<-1 等待进程组识别码为pid绝对值的任何子进程。
pid=-1 等待任何子进程,相当于wait()。
pid=0 等待进程组识别码与目前进程相同的任何子进程。
pid>0 等待任何子进程识别码为pid的子进程。
参数option可以为0 或下面的OR 组合
WNOHANG 如果没有任何已经结束的子进程则马上返回,不予以等待。
WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。
子进程的结束状态返回后存于status,底下有几个宏可判别结束情况
WIFEXITED(status)如果子进程正常结束则为非0值。
WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束
才能使用此宏。
WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真
WTERMSIG(status)取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用
此宏。
WIFSTOPPED(status)如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才
会有此情况。
WSTOPSIG(status)取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED 来判断后才使用此宏
。
返回值 如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno中。
范例 参考wait()。
11.23 fprintf(格式化输出数据至文件)
相关函数 printf,fscanf,vfprintf
表头文件 #include<stdio.h>
定义函数 int fprintf(FILE * stream, const char * format,.......);
函数说明 fprintf()会根据参数format字符串来转换并格式化数据,然后将结果输出到参数stream指定的
文件中,直到出现字符串结束('/0')为止。
返回值 关于参数format字符串的格式请参考printf()。成功则返回实际输出的字符数,失败则返回-1,错
误原因存于errno中。
范例 #include<stdio.h>
main()
{
int i = 150;
int j = -100;
double k = 3.14159;
fprintf(stdout,”%d %f %x /n”,j,k,i);
fprintf(stdout,”%2d %*d/n”,i,2,i);
}
执行 -100 3.141590 96
150 150
11.24 fscanf(格式化字符串输入)
相关函数 scanf,sscanf
表头文件 #include<stdio.h>
定义函数 int fscanf(FILE * stream ,const char *format,....);
函数说明 fscanf()会自参数stream的文件流中读取字符串,再根据参数format字符串来转换并格式化数
据。格式转换形式请参考scanf()。转换后的结构存于对应的参数内。
返回值 成功则返回参数数目,失败则返回-1,错误原因存于errno中。
附加说明
范例 #include<stdio.h>
main()
{
int i;
unsigned int j;
char s[5];
fscanf(stdin,”%d %x %5[a-z] %*s %f”,&i,&j,s,s);
printf(“%d %d %s /n”,i,j,s);
}
执行 10 0x1b aaaaaaaaa bbbbbbbbbb /*从键盘输入*/
10 27 aaaaa
11.25 printf(格式化输出数据)
相关函数 scanf,snprintf
表头文件 #include<stdio.h>
定义函数 int printf(const char * format,.............);
函数说明 printf()会根据参数format字符串来转换并格式化数据,然后将结果写出到标准输出设备,直
到出现字符串结束('/0')为止。参数format字符串可包含下列三种字符类型
1.一般文本,伴随直接输出。
2.ASCII控制字符,如/t、/n等。
3.格式转换字符。
格式转换为一个百分比符号(%)及其后的格式字符所组成。一般而言,每个%符号在其后都必需有一
printf()的参数与之相呼应(只有当%%转换字符出现时会直接输出%字符),而欲输出的数据类型必须
与其相对应的转换字符类型相同。
Printf()格式转换的一般形式如下
%(flags)(width)(.prec)type
以中括号括起来的参数为选择性参数,而%与type则是必要的。底下先介绍type的几种形式
整数
%d 整数的参数会被转成一有符号的十进制数字
%u 整数的参数会被转成一无符号的十进制数字
%o 整数的参数会被转成一无符号的八进制数字
%x 整数的参数会被转成一无符号的十六进制数字,并以小写abcdef表示
%X 整数的参数会被转成一无符号的十六进制数字,并以大写ABCDEF表示浮点型数
%f double 型的参数会被转成十进制数字,并取到小数点以下六位,四舍五入。
%e double型的参数以指数形式打印,有一个数字会在小数点前,六位数字在小数点后,而在指数部分
会以小写的e来表示。
%E 与%e作用相同,唯一区别是指数部分将以大写的E 来表示。
%g double 型的参数会自动选择以%f 或%e 的格式来打印,其标准是根据欲打印的数值及所设置的有
效位数来决定。
%G 与%g 作用相同,唯一区别在以指数形态打印时会选择%E 格式。
字符及字符串
%c 整型数的参数会被转成unsigned char型打印出。
%s 指向字符串的参数会被逐字输出,直到出现NULL字符为止
%p 如果是参数是“void *”型指针则使用十六进制格式显示。
prec 有几种情况
1. 正整数的最小位数。
2.在浮点型数中代表小数位数
3.在%g 格式代表有效位数的最大值。
4.在%s格式代表字符串的最大长度。
5.若为×符号则代表下个参数值为最大长度。
width为参数的最小长度,若此栏并非数值,而是*符号,则表示以下一个参数当做参数长度。
flags 有下列几种情况
#NAME?
+ 一般在打印负数时,printf()会加印一个负号,整数则不加任何负号。此旗标会使得在打印正数前多
一个正号(+)。
# 此旗标会根据其后转换字符的不同而有不同含义。当在类型为o 之前(如%#o),则会在打印八进制
数值前多印一个o。
而在类型为x 之前(%#x)则会在打印十六进制数前多印’0x’,在型态为e、E、f、g或G 之前则会强迫
数值打印小数点。在类型为g 或G之前时则同时保留小数点及小数位数末尾的零。
0 当有指定参数时,无数字的参数将补上0。默认是关闭此旗标,所以一般会打印出空白字符。
返回值 成功则返回实际输出的字符数,失败则返回-1,错误原因存于errno中。
范例 #include<stdio.h>
main()
{
int i = 150;
int j = -100;
double k = 3.14159;
printf(“%d %f %x/n”,j,k,i);
printf(“%2d %*d/n”,i,2,i); /*参数2 会代入格式*中,而与%2d同意义*/
}
执行 -100 3.14159 96
150 150
11.26 sacnf(格式化字符串输入)
相关函数 fscanf,snprintf
表头文件 #include<stdio.h>
定义函数 int scanf(const char * format,.......);
函数说明 scanf()会将输入的数据根据参数format字符串来转换并格式化数据。Scanf()格式转换的一般
形式如下
%[*][size][l][h]type
以中括号括起来的参数为选择性参数,而%与type则是必要的。
* 代表该对应的参数数据忽略不保存。
size 为允许参数输入的数据长度。
l 输入的数据数值以long int 或double型保存。
h 输入的数据数值以short int 型保存。
底下介绍type的几种形式
%d 输入的数据会被转成一有符号的十进制数字(int)。
%i 输入的数据会被转成一有符号的十进制数字,若输入数据以“0x”或“0X”开头代表转换十六进制数字
,若以“0”开头则转换八进制数字,其他情况代表十进制。
%0 输入的数据会被转换成一无符号的八进制数字。
%u 输入的数据会被转换成一无符号的正整数。
%x 输入的数据为无符号的十六进制数字,转换后存于unsigned int型变量。
%X 同%x
%f 输入的数据为有符号的浮点型数,转换后存于float型变量。
%e 同%f
%E 同%f
%g 同%f
%s 输入数据为以空格字符为终止的字符串。
%c 输入数据为单一字符。
[] 读取数据但只允许括号内的字符。如[a-z]。
[^] 读取数据但不允许中括号的^符号后的字符出现,如[^0-9].
返回值 成功则返回参数数目,失败则返回-1,错误原因存于errno中。
范例 #include <stdio.h>
main()
{
int i;
unsigned int j;
char s[5];
scanf(“%d %x %5[a-z] %*s %f”,&i,&j,s,s);
printf(“%d %d %s/n”,i,j,s);
}
执行 10 0x1b aaaaaaaaaa bbbbbbbbbb
10 27 aaaaa
11.27 sprintf(格式化字符串复制)
相关函数 printf,sprintf
表头文件 #include<stdio.h>
定义函数 int sprintf( char *str,const char * format,.........);
函数说明 sprintf()会根据参数format字符串来转换并格式化数据,然后将结果复制到参数str所指的字符
串数组,直到出现字符串结束(’/0’)为止。关于参数format字符串的格式请参考printf()。
返回值 成功则返回参数str字符串长度,失败则返回-1,错误原因存于errno中。
附加说明 使用此函数得留意堆栈溢出,或改用snprintf()。
范例 #include<stdio.h>
main()
{
char * a=”This is string A!”;
char buf[80];
sprintf(buf,”>>> %s<<</n”,a);
printf(“%s”.buf);
}
执行 >>>This is string A!<<<
11.28 sscanf(格式化字符串输入)
相关函数 scanf,fscanf
表头文件 #include<stdio.h>
定义函数 int sscanf (const char *str,const char * format,........);
函数说明 sscanf()会将参数str的字符串根据参数format字符串来转换并格式化数据。格式转换形式请参
考scanf()。转换后的结果存于对应的参数内。
返回值 成功则返回参数数目,失败则返回-1,错误原因存于errno中。
范例 #include<stdio.h>
main()
{
int i;
unsigned int j;
char input[ ]=”10 0x1b aaaaaaaa bbbbbbbb”;
char s[5];
sscanf(input,”%d %x %5[a-z] %*s %f”,&i,&j,s,s);
printf(“%d %d %s/n”,i,j,s);
}
执行 10 27 aaaaa
11.29 vfprintf(格式化输出数据至文件)
相关函数 printf,fscanf,fprintf
表头文件 #include<stdio.h>
#include<stdarg.h>
定义函数 int vfprintf(FILE *stream,const char * format,va_list ap);
函数说明 vfprintf()会根据参数format字符串来转换并格式化数据,然后将结果输出到参数stream指定的
文件中,直到出现字符串结束(’/0’)为止。关于参数format字符串的格式请参考printf()。va_list用法请参
考附录C或vprintf()范例。
返回值 成功则返回实际输出的字符数,失败则返回-1,错误原因存于errno中。
范例 参考fprintf()及vprintf()。
11.30 vfscanf(格式化字符串输入)
相关函数 scanf,sscanf,fscanf
表头文件 #include<stdio.h>
定义函数 int vfscanf(FILE * stream,const char * format ,va_list ap);
函数说明 vfscanf()会自参数stream 的文件流中读取字符串,再根据参数format字符串来转换并格式化
数据。格式转换形式请参考scanf()。转换后的结果存于对应的参数内。va_list用法请参考附录C 或
vprintf()。
返回值 成功则返回参数数目,失败则返回-1,错误原因存于errno中。
范例 参考fscanf()及vprintf()。
11.31 vprintf(格式化输出数据)
相关函数 printf,vfprintf,vsprintf
表头文件 #include<stdio.h>
#include<stdarg.h>
定义函数 int vprintf(const char * format,va_list ap);
函数说明 vprintf()作用和printf()相同,参数format格式也相同。va_list为不定个数的参数列,用法及范例
请参考附录C。
返回值 成功则返回实际输出的字符数,失败则返回-1,错误原因存于errno中。
范例 #include<stdio.h>
#include<stdarg.h>
int my_printf( const char *format,……)
{
va_list ap;
int retval;
va_start(ap,format);
printf(“my_printf( ):”);
retval = vprintf(format,ap);
va_end(ap);
return retval;
}
main()
{
int i = 150,j = -100;
double k = 3.14159;
my_printf(“%d %f %x/n”,j,k,i);
my_printf(“%2d %*d/n”,i,2,i);
}
执行 my_printf() : -100 3.14159 96
my_printf() : 150 150
11.32 vscanf(格式化字符串输入)
相关函数 vsscanf,vfscanf
表头文件 #include<stdio.h>
#include<stdarg.h>
定义函数 int vscanf( const char * format,va_list ap);
函数说明 vscanf()会将输入的数据根据参数format字符串来转换并格式化数据。格式转换形式请参考
scanf()。转换后的结果存于对应的参数内。va_list用法请参考附录C或vprintf()范例
返回值 成功则返回参数数目,失败则返回-1,错误原因存于errno中。
范例 请参考scanf()及vprintf()。
11.33 vsprintf(格式化字符串复制)
相关函数 vnsprintf,vprintf,snprintf
表头文件 #include<stdio.h>
定义函数 int vsprintf( char * str,const char * format,va_list ap);
函数说明 vsprintf()会根据参数format字符串来转换并格式化数据,然后将结果复制到参数str所指的字
符串数组,直到出现字符串结束(’/0’)为止。关于参数format字符串的格式请参考printf()。va_list用法请
参考附录C或vprintf()范例。
返回值 成功则返回参数str字符串长度,失败则返回-1,错误原因存于errno中。
范例 请参考vprintf()及vsprintf()。
11.34 vsscanf(格式化字符串输入)
相关函数 vscanf,vfscanf
表头文件 #include<stdio.h>
定义函数 int vsscanf(const char * str,const char * format,va_list ap);
函数说明 vsscanf()会将参数str的字符串根据参数format字符串来转换并格式化数据。格式转换形式请
参考附录C 或vprintf()范例。
返回值 成功则返回参数数目,失败则返回-1,错误原因存于errno中。
范例 请参考sscanf()及vprintf()。
12. 文件权限控制篇
12.1 access(判断是否具有存取文件的权限)
相关函数 stat,open,chmod,chown,setuid,setgid
表头文件 #include<unistd.h>
定义函数 int access(const char * pathname,int mode);
函数说明 access()会检查是否可以读/写某一已存在的文件。参数mode有几种情况组合,R_OK,
W_OK,X_OK 和F_OK。R_OK,W_OK与X_OK用来检查文件是否具有读取、写入和执行的权限。
F_OK则是用来判断该文件是否存在。由于access()只作权限的核查,并不理会文件形态或文件内容,
因此,如果一目录表示为“可写入”,表示可以在该目录中建立新文件等操作,而非意味此目录可以被当
做文件处理。例如,你会发现DOS的文件都具有“可执行”权限,但用execve()执行时则会失败。
返回值 若所有欲查核的权限都通过了检查则返回0值,表示成功,只要有一权限被禁止则返回-1。
错误代码 EACCESS 参数pathname 所指定的文件不符合所要求测试的权限。
EROFS 欲测试写入权限的文件存在于只读文件系统内。
EFAULT 参数pathname指针超出可存取内存空间。
EINVAL 参数mode 不正确。
ENAMETOOLONG 参数pathname太长。
ENOTDIR 参数pathname为一目录。
ENOMEM 核心内存不足
ELOOP 参数pathname有过多符号连接问题。
EIO I/O 存取错误。
附加说明 使用access()作用户认证方面的判断要特别小心,例如在access()后再做open()的空文件可能
会造成系统安全上的问题。
范例 /* 判断是否允许读取/etc/passwd */
#include<unistd.h>
int main()
{
if (access(“/etc/passwd”,R_OK) = =0)
printf(“/etc/passwd can be read/n”);
}
执行 /etc/passwd can be read
12.2 alphasort(依字母顺序排序目录结构)
相关函数 scandir,qsort
表头文件 #include<dirent.h>
定义函数 int alphasort(const struct dirent **a,const struct dirent **b);
函数说明 alphasort()为scandir()最后调用qsort()函数时传给qsort()作为判断的函数,详细说明请参考
scandir()及qsort()。
返回值 参考qsort()。
范例 /* 读取/目录下所有的目录结构,并依字母顺序排列*/
main()
{
struct dirent **namelist;
int i,total;
total = scandir(“/”,&namelist ,0,alphasort);
if(total <0)
perror(“scandir”);
else{
for(i=0;i<total;i++)
printf(“%s/n”,namelist[i]->d_name);
printf(“total = %d/n”,total);
}
}
执行 ..
.gnome
.gnome_private
ErrorLog
Weblog
bin
boot
dev
dosc
dosd
etc
home
lib
lost+found
misc
mnt
opt
proc
root
sbin
tmp
usr
var
total = 24
12.3 chdir(改变当前的工作(目录)
相关函数 getcwd,chroot
表头文件 #include<unistd.h>
定义函数 int chdir(const char * path);
函数说明 chdir()用来将当前的工作目录改变成以参数path所指的目录。
返回值 执行成功则返回0,失败返回-1,errno为错误代码。
范例 #include<unistd.h>
main()
{
chdir(“/tmp”);
printf(“current working directory: %s/n”,getcwd(NULL,NULL));
}
执行 current working directory :/tmp
12.4 chmod(改变文件的权限)
相关函数 fchmod,stat,open,chown
表头文件 #include<sys/types.h>
#include<sys/stat.h>
定义函数 int chmod(const char * path,mode_t mode);
函数说明 chmod()会依参数mode 权限来更改参数path 指定文件的权限。
参数 mode 有下列数种组合
S_ISUID 04000 文件的(set user-id on execution)位
S_ISGID 02000 文件的(set group-id on execution)位
S_ISVTX 01000 文件的sticky位
S_IRUSR(S_IREAD) 00400 文件所有者具可读取权限
S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限
S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限
S_IRGRP 00040 用户组具可读取权限
S_IWGRP 00020 用户组具可写入权限
S_IXGRP 00010 用户组具可执行权限
S_IROTH 00004 其他用户具可读取权限
S_IWOTH 00002 其他用户具可写入权限
S_IXOTH 00001 其他用户具可执行权限
只有该文件的所有者或有效用户识别码为0,才可以修改该文件权限。基于系统安全,如果欲将数据写
入一执行文件,而该执行文件具有S_ISUID 或S_ISGID 权限,则这两个位会被清除。如果一目录具有
S_ISUID 位权限,表示在此目录下只有该文件的所有者或root可以删除该文件。
返回值 权限改变成功返回0,失败返回-1,错误原因存于errno。
错误代码 EPERM 进程的有效用户识别码与欲修改权限的文件拥有者不同,而且也不具root权限。
EACCESS 参数path所指定的文件无法存取。
EROFS 欲写入权限的文件存在于只读文件系统内。
EFAULT 参数path指针超出可存取内存空间。
EINVAL 参数mode不正确
ENAMETOOLONG 参数path太长
ENOENT 指定的文件不存在
ENOTDIR 参数path路径并非一目录
ENOMEM 核心内存不足
ELOOP 参数path有过多符号连接问题。
EIO I/O 存取错误
范例 /* 将/etc/passwd 文件权限设成S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH */
#include<sys/types.h>
#include<sys/stat.h>
main()
{
chmod(“/etc/passwd”,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
}
12.5 chown(改变文件的所有者)
相关函数 fchown,lchown,chmod
表头文件 #include<sys/types.h>
#include<unistd.h>
定义函数 int chown(const char * path, uid_t owner,gid_t group);
函数说明 chown()会将参数path指定文件的所有者变更为参数owner代表的用户,而将该文件的组变更
为参数group组。如果参数owner或group为-1,对应的所有者或组不会有所改变。root与文件所有者皆
可改变文件组,但所有者必须是参数group组的成员。当root用chown()改变文件所有者或组时,该文件
若具有S_ISUID或S_ISGID权限,则会清除此权限位,此外如果具有S_ISGID权限但不具S_IXGRP位,
则该文件会被强制锁定,文件模式会保留。
返回值 成功则返回0,失败返回-1,错误原因存于errno。
错误代码 参考chmod()。
范例 /* 将/etc/passwd 的所有者和组都设为root */
#include<sys/types.h>
#include<unistd.h>
main()
{
chown(“/etc/passwd”,0,0);
}
12.6 chroot(改变根目录)
相关函数 chdir
表头文件 #include<unistd.h>
定义函数 int chroot(const char * path);
函数说明 chroot()用来改变根目录为参数path 所指定的目录。只有超级用户才允许改变根目录,子进程
将继承新的根目录。
返回值 调用成功则返回0,失败则返-1,错误代码存于errno。
错误代码 EPERM 权限不足,无法改变根目录。
EFAULT 参数path指针超出可存取内存空间。
ENAMETOOLONG 参数path太长。
ENOTDIR 路径中的目录存在但却非真正的目录。
EACCESS 存取目录时被拒绝
ENOMEM 核心内存不足。
ELOOP 参数path有过多符号连接问题。
EIO I/O 存取错误。
范例 /* 将根目录改为/tmp ,并将工作目录切换至/tmp */
#include<unistd.h>
main()
{
chroot(“/tmp”);
chdir(“/”);
}
12.7 closedir(关闭目录)
相关函数 opendir
表头文件 #include<sys/types.h>
#include<dirent.h>
定义函数 int closedir(DIR *dir);
函数说明 closedir()关闭参数dir所指的目录流。
返回值 关闭成功则返回0,失败返回-1,错误原因存于errno 中。
错误代码 EBADF 参数dir为无效的目录流
范例 参考readir()。
12.8 fchdir(改变当前的工作目录)
相关函数 getcwd,chroot
表头文件 #include<unistd.h>
定义函数 int fchdir(int fd);
函数说明 fchdir()用来将当前的工作目录改变成以参数fd 所指的文件描述词。
返回值执 行成功则返回0,失败返回-1,errno为错误代码。
附加说明
范例 #include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
main()
{
int fd;
fd = open(“/tmp”,O_RDONLY);
fchdir(fd);
printf(“current working directory : %s /n”,getcwd(NULL,NULL));
close(fd);
}
执行 current working directory : /tmp
12.9 fchmod(改变文件的权限)
相关函数 chmod,stat,open,chown
表头文件 #include<sys/types.h>
#include<sys/stat.h>
定义函数 int fchmod(int fildes,mode_t mode);
函数说明 fchmod()会依参数mode权限来更改参数fildes所指文件的权限。参数fildes为已打开文件的文
件描述词。参数mode请参考chmod()。
返回值 权限改变成功则返回0,失败返回-1,错误原因存于errno。
错误原因 EBADF 参数fildes为无效的文件描述词。
EPERM 进程的有效用户识别码与欲修改权限的文件所有者不同,而且也不具root权限。
EROFS 欲写入权限的文件存在于只读文件系统内。
EIO I/O 存取错误。
范例 #include<sys/stat.h>
#include<fcntl.h>
main()
{
int fd;
fd = open (“/etc/passwd”,O_RDONLY);
fchmod(fd,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
close(fd);
}
12.10 fchown(改变文件的所有者)
相关函数 chown,lchown,chmod
表头文件 #include<sys/types.h>
#include<unistd.h>
定义函数 int fchown(int fd,uid_t owner,gid_t group);
函数说明 fchown()会将参数fd指定文件的所有者变更为参数owner代表的用户,而将该文件的组变更为
参数group组。如果参数owner或group为-1,对映的所有者或组有所改变。参数fd 为已打开的文件描述
词。当root用fchown()改变文件所有者或组时,该文件若具S_ISUID或S_ISGID权限,则会清除此权限位
。
返回值 成功则返回0,失败则返回-1,错误原因存于errno。
错误代码 EBADF 参数fd文件描述词为无效的或该文件已关闭。
EPERM 进程的有效用户识别码与欲修改权限的文件所有者不同,而且也不具root权限,或是参数
owner、group不正确。
EROFS 欲写入的文件存在于只读文件系统内。
ENOENT 指定的文件不存在
EIO I/O存取错误
范例 #include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
main()
{
int fd;
fd = open (“/etc/passwd”,O_RDONLY);
chown(fd,0,0);
close(fd);
}
12.11 fstat(由文件描述词取得文件状态)
相关函数 stat,lstat,chmod,chown,readlink,utime
表头文件 #include<sys/stat.h>
#include<unistd.h>
定义函数 int fstat(int fildes,struct stat *buf);
函数说明 fstat()用来将参数fildes所指的文件状态,复制到参数buf所指的结构中(struct stat)。Fstat()与
stat()作用完全相同,不同处在于传入的参数为已打开的文件描述词。详细内容请参考stat()。
返回值 执行成功则返回0,失败返回-1,错误代码存于errno。
范例 #include<sys/stat.h>
#include<unistd.h>
#include<fcntk.h>
main()
{
struct stat buf;
int fd;
fd = open (“/etc/passwd”,O_RDONLY);
fstat(fd,&buf);
printf(“/etc/passwd file size +%d/n “,buf.st_size);
}
执行 /etc/passwd file size = 705
12.12 ftruncate(改变文件大小)
相关函数 open,truncate
表头文件 #include<unistd.h>
定义函数 int ftruncate(int fd,off_t length);
函数说明 ftruncate()会将参数fd指定的文件大小改为参数length指定的大小。参数fd为已打开的文件描
述词,而且必须是以写入模式打开的文件。如果原来的文件大小比参数length大,则超过的部分会被删
去。
返回值 执行成功则返回0,失败返回-1,错误原因存于errno。
错误代码 EBADF 参数fd文件描述词为无效的或该文件已关闭。
EINVAL 参数fd 为一socket 并非文件,或是该文件并非以写入模式打开。
12.13 getcwd(取得当前的工作目录)
相关函数 get_current_dir_name,getwd,chdir
表头文件 #include<unistd.h>
定义函数 char * getcwd(char * buf,size_t size);
函数说明 getcwd()会将当前的工作目录绝对路径复制到参数buf所指的内存空间,参数size为buf的空间
大小。在调用此函数时,buf所指的内存空间要足够大,若工作目录绝对路径的字符串长度超过参数
size大小,则回值NULL,errno的值则为ERANGE。倘若参数buf为NULL,getcwd()会依参数size的大
小自动配置内存(使用malloc()),如果参数size也为0,则getcwd()会依工作目录绝对路径的字符串程度
来决定所配置的内存大小,进程可以在使用完此字符串后利用free()来释放此空间。
返回值 执行成功则将结果复制到参数buf所指的内存空间,或是返回自动配置的字符串指针。失败返回
NULL,错误代码存于errno。
范例 #include<unistd.h>
main()
{
char buf[80];
getcwd(buf,sizeof(buf));
printf(“current working directory : %s/n”,buf);
}
执行 current working directory :/tmp
12.14 link(建立文件连接)
相关函数 symlink,unlink
表头文件 #include<unistd.h>
定义函数 int link (const char * oldpath,const char * newpath);
函数说明 link()以参数newpath指定的名称来建立一个新的连接(硬连接)到参数oldpath所指定的已存在
文件。如果参数newpath指定的名称为一已存在的文件则不会建立连接。
返回值 成功则返回0,失败返回-1,错误原因存于errno。
附加说明 link()所建立的硬连接无法跨越不同文件系统,如果需要请改用symlink()。
错误代码 EXDEV 参数oldpath与newpath不是建立在同一文件系统。
EPERM 参数oldpath与newpath所指的文件系统不支持硬连接
EROFS 文件存在于只读文件系统内
EFAULT 参数oldpath或newpath 指针超出可存取内存空间。
ENAMETOLLONG 参数oldpath或newpath太长
ENOMEM 核心内存不足
EEXIST 参数newpath所指的文件名已存在。
EMLINK 参数oldpath所指的文件已达最大连接数目。
ELOOP 参数pathname有过多符号连接问题
ENOSPC 文件系统的剩余空间不足。
EIO I/O 存取错误。
范例 /* 建立/etc/passwd 的硬连接为pass */
#include<unistd.h>
main()
{
link(“/etc/passwd”,”pass”);
}
12.15 lstat(由文件描述词取得文件状态)
相关函数 stat,fstat,chmod,chown,readlink,utime
表头文件 #include<sys/stat.h>
#include<unistd.h>
定义函数 int lstat (const char * file_name.struct stat * buf);
函数说明 lstat()与stat()作用完全相同,都是取得参数file_name所指的文件状态,其差别在于,当文件
为符号连接时,lstat()会返回该link本身的状态。详细内容请参考stat()。
返回值 执行成功则返回0,失败返回-1,错误代码存于errno。
范例 参考stat()。
12.16 opendir(打开目录)
相关函数 open,readdir,closedir,rewinddir,seekdir,telldir,scandir
表头文件 #include<sys/types.h>
#include<dirent.h>
定义函数 DIR * opendir(const char * name);
函数说明 opendir()用来打开参数name指定的目录,并返回DIR*形态的目录流,和open()类似,接下来
对目录的读取和搜索都要使用此返回值。
返回值 成功则返回DIR* 型态的目录流,打开失败则返回NULL。
错误代码 EACCESS 权限不足
EMFILE 已达到进程可同时打开的文件数上限。
ENFILE 已达到系统可同时打开的文件数上限。
ENOTDIR 参数name非真正的目录
ENOENT 参数name 指定的目录不存在,或是参数name 为一空字符串。
ENOMEM 核心内存不足。
12.17 readdir(读取目录)
相关函数 open,opendir,closedir,rewinddir,seekdir,telldir,scandir
表头文件 #include<sys/types.h>
#include<dirent.h>
定义函数 struct dirent * readdir(DIR * dir);
函数说明 readdir()返回参数dir目录流的下个目录进入点。
结构dirent定义如下
struct dirent
{
ino_t d_ino;
ff_t d_off;
signed short int d_reclen;
unsigned char d_type;
har d_name[256;
};
d_ino 此目录进入点的inode
d_off 目录文件开头至此目录进入点的位移
d_reclen _name的长度,不包含NULL字符
d_type d_name 所指的文件类型
d_name 文件名
返回值 成功则返回下个目录进入点。有错误发生或读取到目录文件尾则返回NULL。
附加说明 EBADF参数dir为无效的目录流。
范例 #include<sys/types.h>
#include<dirent.h>
#include<unistd.h>
main()
{
DIR * dir;
struct dirent * ptr;
int i;
dir =opendir(“/etc/rc.d”);
while((ptr = readdir(dir))!=NULL)
{
printf(“d_name: %s/n”,ptr->d_name);
}
closedir(dir);
}
执行 d_name:.
d_name:..
d_name:init.d
d_name:rc0.d
d_name:rc1.d
d_name:rc2.d
d_name:rc3.d
d_name:rc4.d
d_name:rc5.d
d_name:rc6.d
d_name:rc
d_name:rc.local
d_name:rc.sysinit
12.18 readlink(取得符号连接所指的文件)
相关函数 stat,lstat,symlink
表头文件 #include<unistd.h>
定义函数 int readlink(const char * path ,char * buf,size_t bufsiz);
函数说明 readlink()会将参数path的符号连接内容存到参数buf所指的内存空间,返回的内容不是以
NULL作字符串结尾,但会将字符串的字符数返回。若参数bufsiz小于符号连接的内容长度,过长的内
容会被截断。
返回值 执行成功则传符号连接所指的文件路径字符串,失败则返回-1,错误代码存于errno。
错误代码 EACCESS 取文件时被拒绝,权限不够
EINVAL 参数bufsiz 为负数
EIO I/O 存取错误。
ELOOP 欲打开的文件有过多符号连接问题。
ENAMETOOLONG 参数path的路径名称太长
ENOENT 参数path所指定的文件不存在
ENOMEM 核心内存不足
ENOTDIR 参数path路径中的目录存在但却非真正的目录。
12.19 remove(删除文件)
相关函数 link,rename,unlink
表头文件 #include<stdio.h>
定义函数 int remove(const char * pathname);
函数说明 remove()会删除参数pathname指定的文件。如果参数pathname为一文件,则调用unlink()处
理,若参数pathname为一目录,则调用rmdir()来处理。请参考unlink()与rmdir()。
返回值 成功则返回0,失败则返回-1,错误原因存于errno。
错误代码 EROFS 欲写入的文件存在于只读文件系统内
EFAULT 参数pathname指针超出可存取内存空间
ENAMETOOLONG 参数pathname太长
ENOMEM 核心内存不足
ELOOP 参数pathname有过多符号连接问题
EIO I/O 存取错误。
12.20 rename(更改文件名称或位置)
相关函数 link,unlink,symlink
表头文件 #include<stdio.h>
定义函数 int rename(const char * oldpath,const char * newpath);
函数说明 rename()会将参数oldpath 所指定的文件名称改为参数newpath所指的文件名称。若newpath
所指定的文件已存在,则会被删除。
返回值 执行成功则返回0,失败返回-1,错误原因存于errno
范例 /* 设计一个DOS下的rename指令rename 旧文件名新文件名*/
#include <stdio.h>
void main(int argc,char **argv)
{
if(argc<3){
printf(“Usage: %s old_name new_name/n”,argv[0]);
return;
}
printf(“%s=>%s”,argc[1],argv[2]);
if(rename(argv[1],argv[2]<0)
printf(“error!/n”);
else
printf(“ok!/n”);
}
12.21 rewinddir(重设读取目录的位置为开头位置)
相关函数 open,opendir,closedir,telldir,seekdir,readdir,scandir
表头文件 #include<sys/types.h>
#include<dirent.h>
定义函数 void rewinddir(DIR *dir);
函数说明 rewinddir()用来设置参数dir 目录流目前的读取位置为原来开头的读取位置。
返回值
错误代码 EBADF dir为无效的目录流
范例 #include<sys/types.h>
#include<dirent.h>
#include<unistd.h>
main()
{
DIR * dir;
struct dirent *ptr;
dir = opendir(“/etc/rc.d”);
while((ptr = readdir(dir))!=NULL)
{
printf(“d_name :%s/n”,ptr->d_name);
}
rewinddir(dir);
printf(“readdir again!/n”);
while((ptr = readdir(dir))!=NULL)
{
printf(“d_name: %s/n”,ptr->d_name);
}
closedir(dir);
}
执行 d_name:.
d_name:..
d_name:init.d
d_name:rc0.d
d_name:rc1.d
d_name:rc2.d
d_name:rc3.d
d_name:rc4.d
d_name:rc5.d
d_name:rc6.d
d_name:rc
d_name:rc.local
d_name:rc.sysinit
readdir again!
d_name:.
d_name:..
d_name:init.d
d_name:rc0.d
d_name:rc1.d
d_name:rc2.d
d_name:rc3.d
d_name:rc4.d
d_name:rc5.d
d_name:rc6.d
d_name:rc
d_name:rc.local
d_name:rc.sysinit
12.22 seekdir(设置下回读取目录的位置)
相关函数 open,opendir,closedir,rewinddir,telldir,readdir,scandir
表头文件 #include<dirent.h>
定义函数 void seekdir(DIR * dir,off_t offset);
函数说明 seekdir()用来设置参数dir目录流目前的读取位置,在调用readdir()时便从此新位置开始读取
。参数offset 代表距离目录文件开头的偏移量。
返回值
错误代码 EBADF 参数dir为无效的目录流
范例 #include<sys/types.h>
#include<dirent.h>
#include<unistd.h>
main()
{
DIR * dir;
struct dirent * ptr;
int offset,offset_5,i=0;
dir=opendir(“/etc/rc.d”);
while((ptr = readdir(dir))!=NULL)
{
offset = telldir(dir);
if(++i = =5) offset_5 =offset;
printf(“d_name :%s offset :%d /n”,ptr->d_name,offset);
}
seekdir(dir offset_5);
printf(“Readdir again!/n”);
while((ptr = readdir(dir))!=NULL)
{
offset = telldir(dir);
printf(“d_name :%s offset :%d/n”,ptr->d_name.offset);
}
closedir(dir);
}
执行 d_name : . offset :12
d_name : .. offset:24
d_name : init.d offset 40
d_name : rc0.d offset :56
d_name :rc1.d offset :72
d_name:rc2.d offset :88
d_name:rc3.d offset 104
d_name:rc4.d offset:120
d_name:rc5.d offset:136
d_name:rc6.d offset:152
d_name:rc offset 164
d_name:rc.local offset :180
d_name:rc.sysinit offset :4096
readdir again!
d_name:rc2.d offset :88
d_name:rc3.d offset 104
d_name:rc4.d offset:120
d_name:rc5.d offset:136
d_name:rc6.d offset:152
d_name:rc offset 164
d_name:rc.local offset :180
d_name:rc.sysinit offset :4096
12.23 stat(取得文件状态)
相关函数 fstat,lstat,chmod,chown,readlink,utime
表头文件 #include<sys/stat.h>
#include<unistd.h>
定义函数 int stat(const char * file_name,struct stat *buf);
函数说明 stat()用来将参数file_name所指的文件状态,复制到参数buf所指的结构中。
下面是struct stat内各参数的说明
struct stat
{
dev_t st_dev; /*device*/
ino_t st_ino; /*inode*/
mode_t st_mode; /*protection*/
nlink_t st_nlink; /*number of hard links */
uid_t st_uid; /*user ID of owner*/
gid_t st_gid; /*group ID of owner*/
dev_t st_rdev; /*device type */
off_t st_size; /*total size, in bytes*/
unsigned long st_blksize; /*blocksize for filesystem I/O */
unsigned long st_blocks; /*number of blocks allocated*/
time_t st_atime; /* time of lastaccess*/
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last change */
};
st_dev 文件的设备编号
st_ino 文件的i-node
st_mode 文件的类型和存取的权限
st_nlink 连到该文件的硬连接数目,刚建立的文件值为1。
st_uid 文件所有者的用户识别码
st_gid 文件所有者的组识别码
st_rdev 若此文件为装置设备文件,则为其设备编号
st_size 文件大小,以字节计算
st_blksize 文件系统的I/O 缓冲区大小。
st_blcoks 占用文件区块的个数,每一区块大小为512 个字节。
st_atime 文件最近一次被存取或被执行的时间,一般只有在用mknod、utime、read、write与tructate时
改变。
st_mtime 文件最后一次被修改的时间,一般只有在用mknod、utime和write时才会改变
st_ctime i-node最近一次被更改的时间,此参数会在文件所有者、组、权限被更改时更新先前所描述的
st_mode 则定义了下列数种情况
S_IFMT 0170000 文件类型的位遮罩
S_IFSOCK 0140000 scoket
S_IFLNK 0120000 符号连接
S_IFREG 0100000 一般文件
S_IFBLK 0060000 区块装置
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符装置
S_IFIFO 0010000 先进先出
S_ISUID 04000 文件的(set user-id on execution)位
S_ISGID 02000 文件的(set group-id on execution)位
S_ISVTX 01000 文件的sticky位
S_IRUSR(S_IREAD) 00400 文件所有者具可读取权限
S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限
S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限
S_IRGRP 00040 用户组具可读取权限
S_IWGRP 00020 用户组具可写入权限
S_IXGRP 00010 用户组具可执行权限
S_IROTH 00004 其他用户具可读取权限
S_IWOTH 00002 其他用户具可写入权限
S_IXOTH 00001 其他用户具可执行权限
上述的文件类型在POSIX 中定义了检查这些类型的宏定义
S_ISLNK (st_mode) 判断是否为符号连接
S_ISREG (st_mode) 是否为一般文件
S_ISDIR (st_mode)是否为目录
S_ISCHR (st_mode)是否为字符装置文件
S_ISBLK (s3e) 是否为先进先出
S_ISSOCK (st_mode) 是否为socket
若一目录具有sticky 位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或
root来删除或改名。
返回值 执行成功则返回0,失败返回-1,错误代码存于errno
错误代码 ENOENT 参数file_name指定的文件不存在
ENOTDIR 路径中的目录存在但却非真正的目录
ELOOP 欲打开的文件有过多符号连接问题,上限为16符号连接
EFAULT 参数buf为无效指针,指向无法存在的内存空间
EACCESS 存取文件时被拒绝
ENOMEM 核心内存不足
ENAMETOOLONG 参数file_name的路径名称太长
范例 #include<sys/stat.h>
#include<unistd.h>
mian()
{
struct stat buf;
stat (“/etc/passwd”,&buf);
printf(“/etc/passwd file size = %d /n”,buf.st_size);
}
执行 /etc/passwd file size = 705
11.24 symlink(建立文件符号连接)
相关函数 link,unlink
表头文件 #include<unistd.h>
定义函数 int symlink( const char * oldpath,const char * newpath);
函数说明 symlink()以参数newpath指定的名称来建立一个新的连接(符号连接)到参数oldpath所指定的已
存在文件。参数oldpath指定的文件不一定要存在,如果参数newpath指定的名称为一已存在的文件则不
会建立连接。
返回值 成功则返回0,失败返回-1,错误原因存于errno。
错误代码 EPERM 参数oldpath与newpath所指的文件系统不支持符号连接
EROFS 欲测试写入权限的文件存在于只读文件系统内
EFAULT 参数oldpath或newpath指针超出可存取内存空间。
ENAMETOOLONG 参数oldpath或newpath太长
ENOMEM 核心内存不足
EEXIST 参数newpath所指的文件名已存在。
EMLINK 参数oldpath所指的文件已达到最大连接数目
ELOOP 参数pathname有过多符号连接问题
ENOSPC 文件系统的剩余空间不足
EIO I/O 存取错误
范例 #include<unistd.h>
main()
{
symlink(“/etc/passwd”,”pass”);
}
11.25 telldir(取得目录流的读取位置)
相关函数 open,opendir,closedir,rewinddir,seekdir,readdir,scandir
表头文件 #include<dirent.h>
定义函数 off_t telldir(DIR *dir);
函数说明 telldir()返回参数dir目录流目前的读取位置。此返回值代表距离目录文件开头的偏移量返回值
返回下个读取位置,有错误发生时返回-1。
错误代码 EBADF参数dir为无效的目录流。
范例 #include<sys/types.h>
#include<dirent.h>
#include<unistd.h>
main()
{
DIR *dir;
struct dirent *ptr;
int offset;
dir = opendir(“/etc/rc.d”);
while((ptr = readdir(dir))!=NULL)
{
offset = telldir (dir);
printf(“d_name : %s offset :%d/n”, ptr->d_name,offset);
}
closedir(dir);
}
执行 d_name : . offset :12
d_name : .. offset:24
d_name : init.d offset 40
d_name : rc0.d offset :56
d_name :rc1.d offset :72
d_name:rc2.d offset :88
d_name:rc3.d offset 104
d_name:rc4.d offset:120
d_name:rc5.d offset:136
d_name:rc6.d offset:152
d_name:rc offset 164
d_name:rc.local offset :180
d_name:rc.sysinit offset :4096
11.26 truncate(改变文件大小)
相关函数 open,ftruncate
表头文件 #include<unistd.h>
定义函数 int truncate(const char * path,off_t length);
函数说明 truncate()会将参数path 指定的文件大小改为参数length 指定的大小。如果原来的文件大小比
参数length大,则超过的部分会被删去。
返回值 执行成功则返回0,失败返回-1,错误原因存于errno。
错误代码 EACCESS 参数path所指定的文件无法存取。
EROFS 欲写入的文件存在于只读文件系统内
EFAULT 参数path指针超出可存取内存空间
EINVAL 参数path包含不合法字符
ENAMETOOLONG 参数path太长
ENOTDIR 参数path路径并非一目录
EISDIR 参数path 指向一目录
ETXTBUSY 参数path所指的文件为共享程序,而且正被执行中
ELOOP 参数path’有过多符号连接问题
EIO I/O 存取错误。
11.27 umask(设置建立新文件时的权限遮罩)
相关函数 creat,open
表头文件 #include<sys/types.h>
#include<sys/stat.h>
定义函数 mode_t umask(mode_t mask);
函数说明 umask()会将系统umask值设成参数mask&0777后的值,然后将先前的umask值返回。在使
用open()建立新文件时,该参数mode并非真正建立文件的权限,而是(mode&~umask)的权限值。例如
,在建立文件时指定文件权限为0666,通常umask值默认为022,则该文件的真正权限则为0666&~
022=0644,也就是rw-r--r--返回值此调用不会有错误值返回。返回值为原先系统的umask值。
11.28 unlink(删除文件)
相关函数 link,rename,remove
表头文件 #include<unistd.h>
定义函数 int unlink(const char * pathname);
函数说明 unlink()会删除参数pathname指定的文件。如果该文件名为最后连接点,但有其他进程打开了
此文件,则在所有关于此文件的文件描述词皆关闭后才会删除。如果参数pathname为一符号连接,则
此连接会被删除。
返回值 成功则返回0,失败返回-1,错误原因存于errno
错误代码 EROFS 文件存在于只读文件系统内
EFAULT 参数pathname指针超出可存取内存空间
ENAMETOOLONG 参数pathname太长
ENOMEM 核心内存不足
ELOOP 参数pathname 有过多符号连接问题
EIO I/O 存取错误
11.29 utime(修改文件的存取时间和更改时间)
相关函数 utimes,stat
表头文件 #include<sys/types.h>
#include<utime.h>
定义函数 int utime(const char * filename,struct utimbuf * buf);
函数说明 utime()用来修改参数filename文件所属的inode存取时间。
结构utimbuf定义如下
struct utimbuf{
time_t actime;
time_t modtime;
};
返回值 如果参数buf为空指针(NULL),则该文件的存取时间和更改时间全部会设为目前时间。
执行成功则返回0,失败返回-1,错误代码存于errno。
错误代码 EACCESS 存取文件时被拒绝,权限不足
ENOENT 指定的文件不存在。
11.30 utimes(修改文件的存取时间和更改时间)
相关函数 utime,stat
表头文件 #include<sys/types.h>
#include<utime.h>
定义函数 int utimes(char * filename.struct timeval *tvp);
函数说明 utimes()用来修改参数filename文件所属的inode存取时间和修改时间。
结构timeval定义如下
struct timeval {
long tv_sec;
long tv_usec; /* 微妙*/
};
返回值 参数tvp 指向两个timeval 结构空间,和utime()使用的utimebuf结构比较,tvp[0].tc_sec 则为
utimbuf.actime,tvp]1].tv_sec 为utimbuf.modtime。
执行成功则返回0。失败返回-1,错误代码存于errno。
错误代码 EACCESS 存取文件时被拒绝,权限不足
ENOENT 指定的文件不存在
13. 信号处理篇
13.1 alarm(设置信号传送闹钟)
相关函数 signal,sleep
表头文件 #include<unistd.h>
定义函数 unsigned int alarm(unsigned int seconds);
函数说明 alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参
数seconds 为0,则之前设置的闹钟会被取消,并将剩下的时间返回。
返回值 返回之前闹钟的剩余秒数,如果之前未设闹钟则返回0。
范例 #include<unistd.h>
#include<signal.h>
void handler() {
printf(“hello/n”);
}
main()
{
int i;
signal(SIGALRM,handler);
alarm(5);
for(i=1;i<7;i++){
printf(“sleep %d .../n”,i);
sleep(1);
}
}
执行 sleep 1 ...
sleep 2 ...
sleep 3 ...
sleep 4 ...
sleep 5 ...
hello
sleep 6 ...
13.2 kill(传送信号给指定的进程)
相关函数 raise,signal
表头文件 #include<sys/types.h>
#include<signal.h>
定义函数 int kill(pid_t pid,int sig);
函数说明 kill()可以用来送参数sig指定的信号给参数pid指定的进程。参数pid有几种情况:
pid>0 将信号传给进程识别码为pid 的进程。
pid=0 将信号传给和目前进程相同进程组的所有进程
pid=-1 将信号广播传送给系统内所有的进程
pid<0 将信号传给进程组识别码为pid绝对值的所有进程
参数sig代表的信号编号可参考附录D
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码 EINVAL 参数sig 不合法
ESRCH 参数pid 所指定的进程或进程组不存在
EPERM 权限不够无法传送信号给指定进程
范例 #include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/wait.h>
main()
{
pid_t pid;
int status;
if(!(pid= fork())){
printf(“Hi I am child process!/n”);
sleep(10);
return;
}
else{
printf(“send signal to child process (%d) /n”,pid);
sleep(1);
kill(pid ,SIGABRT);
wait(&status);
if(WIFSIGNALED(status))
printf(“chile process receive signal %d/n”,WTERMSIG(status));
}
}
执行 sen signal to child process(3170)
Hi I am child process!
child process receive signal 6
13.3 pause(让进程暂停直到信号出现)
相关函数 kill,signal,sleep
表头文件 #include<unistd.h>
定义函数 int pause(void);
函数说明 pause()会令目前的进程暂停(进入睡眠状态),直到被信号(signal)所中断。
返回值 只返回-1。
错误代码 EINTR 有信号到达中断了此函数。
13.4 sigaction(查询或设置信号处理方式)
相关函数 signal,sigprocmask,sigpending,sigsuspend
表头文件 #include<signal.h>
定义函数 int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);
函数说明 sigaction()会依参数signum指定的信号编号来设置该信号的处理函数。参数signum可以指定
SIGKILL和SIGSTOP以外的所有信号。
如参数结构sigaction定义如下
struct sigaction
{
void (*sa_handler) (int);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer) (void);
}
sa_handler此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。
sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号搁置。
sa_restorer 此参数没有使用。
sa_flags 用来设置信号处理的其他相关操作,下列的数值可用。
OR 运算(|)组合
A_NOCLDSTOP : 如果参数signum为SIGCHLD,则当子进程暂停时并不会通知父进程
SA_ONESHOT/SA_RESETHAND:当调用新的信号处理函数前,将此信号处理方式改为系统预设的方
式。
SA_RESTART:被信号中断的系统调用会自行重启
SA_NOMASK/SA_NODEFER:在处理此信号未结束前不理会此信号的再次到来。
如果参数oldact不是NULL指针,则原来的信号处理方式会由此结构sigaction 返回。
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码 EINVAL 参数signum 不合法, 或是企图拦截SIGKILL/SIGSTOPSIGKILL信号
EFAULT 参数act,oldact指针地址无法存取。
EINTR 此调用被中断
范例 #include<unistd.h>
#include<signal.h>
void show_handler(struct sigaction * act)
{
switch (act->sa_flags)
{
case SIG_DFL:printf(“Default action/n”);break;
case SIG_IGN:printf(“Ignore the signal/n”);break;
default: printf(“0x%x/n”,act->sa_handler);
}
}
main()
{
int i;
struct sigaction act,oldact;
act.sa_handler = show_handler;
act.sa_flags = SA_ONESHOT|SA_NOMASK;
sigaction(SIGUSR1,&act,&oldact);
for(i=5;i<15;i++)
{
printf(“sa_handler of signal %2d =”.i);
sigaction(i,NULL,&oldact);
}
}
执行 sa_handler of signal 5 = Default action
sa_handler of signal 6= Default action
sa_handler of signal 7 = Default action
sa_handler of signal 8 = Default action
sa_handler of signal 9 = Default action
sa_handler of signal 10 = 0x8048400
sa_handler of signal 11 = Default action
sa_handler of signal 12 = Default action
sa_handler of signal 13 = Default action
sa_handler of signal 14 = Default action
13.5 sigaddset(增加一个信号至信号集)
相关函数 sigemptyset,sigfillset,sigdelset,sigismember
表头文件 #include<signal.h>
定义函数 int sigaddset(sigset_t *set,int signum);
函数说明 sigaddset()用来将参数signum 代表的信号加入至参数set 信号集里。
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码 EFAULT 参数set指针地址无法存取
EINVAL 参数signum非合法的信号编号
13.6 sigdelset(从信号集里删除一个信号)
相关函数 sigemptyset,sigfillset,sigaddset,sigismember
表头文件 #include<signal.h>
定义函数 int sigdelset(sigset_t * set,int signum);
函数说明 sigdelset()用来将参数signum代表的信号从参数set信号集里删除。
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码 EFAULT 参数set指针地址无法存取
EINVAL 参数signum非合法的信号编号
13.7 sigemptyset(初始化信号集)
相关函数 sigaddset,sigfillset,sigdelset,sigismember
表头文件 #include<signal.h>
定义函数 int sigemptyset(sigset_t *set);
函数说明 sigemptyset()用来将参数set信号集初始化并清空。
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码 EFAULT 参数set指针地址无法存取
13.8 sigfillset(将所有信号加入至信号集)
相关函数 sigempty,sigaddset,sigdelset,sigismember
表头文件 #include<signal.h>
定义函数 int sigfillset(sigset_t * set);
函数说明 sigfillset()用来将参数set信号集初始化,然后把所有的信号加入到此信号集里。
返回值 执行成功则返回0,如果有错误则返回-1。
附加说明 EFAULT 参数set指针地址无法存取
13.9 sigismember(测试某个信号是否已加入至信号集里)
相关函数 sigemptyset,sigfillset,sigaddset,sigdelset
表头文件 #include<signal.h>
定义函数 int sigismember(const sigset_t *set,int signum);
函数说明 sigismember()用来测试参数signum 代表的信号是否已加入至参数set信号集里。如果信号集
里已有该信号则返回1,否则返回0。
返回值 信号集已有该信号则返回1,没有则返回0。如果有错误则返回-1。
错误代码 EFAULT 参数set指针地址无法存取
EINVAL 参数signum 非合法的信号编号
13.10 signal(设置信号处理方式)
相关函数 sigaction,kill,raise
表头文件 #include<signal.h>
定义函数 void (*signal(int signum,void(* handler)(int)))(int);
函数说明 signal()会依参数signum 指定的信号编号来设置该信号的处理函数。当指定的信号到达时就
会跳转到参数handler指定的函数执行。如果参数handler不是函数指针,则必须是下列两个常数之一:
SIG_IGN 忽略参数signum指定的信号。
SIG_DFL 将参数signum 指定的信号重设为核心预设的信号处理方式。
关于信号的编号和说明,请参考附录
返回值 返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。
附加说明 在信号发生跳转到自定的handler处理函数执行后,系统会自动将此处理函数换回原来系统预
设的处理方式,如果要改变此操作请改用sigaction()。
范例 参考alarm()或raise()。
13.11 sigpending(查询被搁置的信号)
相关函数 signal,sigaction,sigprocmask,sigsuspend
表头文件 #include<signal.h>
定义函数 int sigpending(sigset_t *set);
函数说明 sigpending()会将被搁置的信号集合由参数set指针返回。
返回值执 行成功则返回0,如果有错误则返回-1。
错误代码 EFAULT 参数set指针地址无法存取
EINTR 此调用被中断。
13.12 sigprocmask(查询或设置信号遮罩)
相关函数 signal,sigaction,sigpending,sigsuspend
表头文件 #include<signal.h>
定义函数 int sigprocmask(int how,const sigset_t *set,sigset_t * oldset);
函数说明 sigprocmask()可以用来改变目前的信号遮罩,其操作依参数how来决定
SIG_BLOCK 新的信号遮罩由目前的信号遮罩和参数set 指定的信号遮罩作联集
SIG_UNBLOCK 将目前的信号遮罩删除掉参数set指定的信号遮罩
SIG_SETMASK 将目前的信号遮罩设成参数set指定的信号遮罩。
如果参数oldset不是NULL指针,那么目前的信号遮罩会由此指针返回。
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码 EFAULT 参数set,oldset指针地址无法存取。
EINTR 此调用被中断
13.13 sleep(让进程暂停执行一段时间)
相关函数 signal,alarm
表头文件 #include<unistd.h>
定义函数 unsigned int sleep(unsigned int seconds);
函数说明 sleep()会令目前的进程暂停,直到达到参数seconds 所指定的时间,或是被信号所中断。
返回值 若进程暂停到参数seconds 所指定的时间则返回0,若有信号中断则返回剩余秒数。
13.14 ferror(检查文件流是否有错误发生)
相关函数 clearerr,perror
表头文件 #include<stdio.h>
定义函数 int ferror(FILE *stream);
函数说明 ferror()用来检查参数stream所指定的文件流是否发生了错误情况,如有错误发生则返回非0
值。
返回值 如果文件流有错误发生则返回非0值。
13.15 perror(打印出错误原因信息字符串)
相关函数 strerror
表头文件 #include<stdio.h>
定义函数 void perror(const char *s);
函数说明 perror()用来将上一个函数发生错误的原因输出到标准错误(stderr)。参数s所指的字符串会先
打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串。
返回值
范例 #include<stdio.h>
main()
{
FILE *fp;
fp = fopen(“/tmp/noexist”,”r+”);
if(fp = =NULL) perror(“fopen”);
}
执行 $ ./perror
fopen : No such file or diretory
13.16 strerror(返回错误原因的描述字符串)
相关函数 perror
表头文件 #include<string.h>
定义函数 char * strerror(int errnum);
函数说明 strerror()用来依参数errnum的错误代码来查询其错误原因的描述字符串,然后将该字符串指
针返回。
返回值 返回描述错误原因的字符串指针。
范例 /* 显示错误代码0 至9 的错误原因描述*/
#include<string.h>
main()
{
int i;
for(i=0;i<10;i++)
printf(“%d : %s/n”,i,strerror(i));
}
执行 0 : Success
1 : Operation not permitted
2 : No such file or directory
3 : No such process
4 : Interrupted system call
5 : Input/output error
6 : Device not configured
7 : Argument list too long
8 : Exec format error
9 : Bad file descriptor
13.17 mkfifo(建立具名管道)
相关函数 pipe,popen,open,umask
表头文件 #include<sys/types.h>
#include<sys/stat.h>
定义函数 int mkfifo(const char * pathname,mode_t mode);
函数说明 mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件
的权限(mode%~umask),因此umask值也会影响到FIFO文件的权限。Mkfifo()建立的FIFO文件其他
进程都可以用读写一般文件的方式存取。当使用open()来打开FIFO文件时,O_NONBLOCK旗标会有影
响
1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程
打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。
2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才
正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。
返回值 若成功则返回0,否则返回-1,错误原因存于errno中。
错误代码 EACCESS 参数pathname所指定的目录路径无可执行的权限
EEXIST 参数pathname所指定的文件已存在。
ENAMETOOLONG 参数pathname的路径名称太长。
ENOENT 参数pathname包含的目录不存在
ENOSPC 文件系统的剩余空间不足
ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。
EROFS 参数pathname指定的文件存在于只读文件系统内。
范例 #include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
main()
{
char buffer[80];
int fd;
unlink(FIFO);
mkfifo(FIFO,0666);
if(fork()>0){
char s[ ] = “hello!/n”;
fd = open (FIFO,O_WRONLY);
write(fd,s,sizeof(s));
close(fd);
}
else{
fd= open(FIFO,O_RDONLY);
read(fd,buffer,80);
printf(“%s”,buffer);
close(fd);
}
}
执行 hello!
13.18 pclose(关闭管道I/O)
相关函数 popen
表头文件 #include<stdio.h>
定义函数 int pclose(FILE * stream);
函数说明 pclose()用来关闭由popen所建立的管道及文件指针。参数stream为先前由popen()所返回的
文件指针。
返回值 返回子进程的结束状态。如果有错误则返回-1,错误原因存于errno中。
错误代码 ECHILD pclose()无法取得子进程的结束状态。
范例 参考popen()。
13.19 pipe(建立管道)
相关函数 mkfifo,popen,read,write,fork
表头文件 #include<unistd.h>
定义函数 int pipe(int filedes[2]);
函数说明 pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,
filedes[1]则为管道的写入端。
返回值 若成功则返回零,否则返回-1,错误原因存于errno中。
错误代码 EMFILE 进程已用完文件描述词最大量。
ENFILE 系统已无文件描述词可用。
EFAULT 参数filedes数组地址不合法。
范例 /* 父进程借管道将字符串“hello!/n”传给子进程并显示*/
#include <unistd.h>
main()
{
int filedes[2];
char buffer[80];
pipe(filedes);
if(fork()>0){
/* 父进程*/
char s[ ] = “hello!/n”;
write(filedes[1],s,sizeof(s));
}
else{
/*子进程*/
read(filedes[0],buffer,80);
printf(“%s”,buffer);
}
}
执行 hello!
13.20 popen(建立管道I/O)
相关函数 pipe,mkfifo,pclose,fork,system,fopen
表头文件 #include<stdio.h>
定义函数 FILE * popen( const char * command,const char * type);
函数说明 popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令
。参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输
出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出
设备或是写入到子进程的标准输入设备中。此外,所有使用文件指针(FILE*)操作的函数也都可以使用
,除了fclose()以外。
返回值 若成功则返回文件指针,否则返回NULL,错误原因存于errno中。
错误代码 EINVAL参数type不合法。
注意事项 在编写具SUID/SGID权限的程序时请尽量避免使用popen(),popen()会继承环境变量,通过
环境变量可能会造成系统安全的问题。
范例 #include<stdio.h>
main()
{
FILE * fp;
char buffer[80];
fp=popen(“cat /etc/passwd”,”r”);
fgets(buffer,sizeof(buffer),fp);
printf(“%s”,buffer);
pclose(fp);
}
执行 root :x:0 0: root: /root: /bin/bash