程序清单 8-1 fork函数示例 P173
/**
* 程序清单 8-1 fork函数示例 P173
*
* zy:
* 在下面的代码中,
* 关键是区分好
* 父进程执行的部分
* 子进程执行的部分
* 父、子进程都执行的部分
*
* 父进程和子进程谁先进程是不确定的。
*/
#include "apue.h"
#include "error.c"
int glob=6;
char buf[]="a write to stdout\n";
int main(int argc, char **argv) {
int var;
pid_t pid;
var = 88;
if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1){
err_sys("write error");
}
printf("before fork\n");
if((pid=fork())<0){
err_sys("fork error");
}else if (pid==0) {//child
glob++;
var++;
}else {//parent,休眠两秒,所以
sleep(2);
}
printf("pid=%d,glob=%d,var=%d\n",getpid(),glob,var);
}
结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
a write to stdout
before fork
pid=3305,glob=7,var=89
pid=3304,glob=6,var=88
asd@asd-desktop:~/workspace/test/src$
程序清单 8-2 vfork函数示例 P177
/**
* 程序清单 8-2 vfork函数示例 P177
*
* zy:
* 关键就是:
* 产生的子进程的目地是在exec一个新程序
* 产生的子进程不会将父进程的地址空间完全复制,
* 在调用exec或者exit之前会直接在父进程的空间内运行,所以就会改变父进程的值
*
* 并且vfork产生的子进程保证了子进程先进程,
* 在子进程调用了exec或者exit之后才会,父进程才得到调用
*/
#include "apue.h"
#include "error.c"
int glob=6;
int main(int argc, char **argv) {
int var;
pid_t pid;
var = 88;
printf("before fork\n");
if((pid=vfork())<0){
err_sys("fork error");
}else if (pid==0) {//child
glob++;
var++;
_exit(0);//为什么是这个请看177页
}
/**
* 只有父进程才会在这里进程
*/
printf("pid=%d,glob=%d,var=%d\n",getpid(),glob,var);
exit(0);
}
结果:
asd@asd-desktop:~/workspace/test/src$ gcc test.c
asd@asd-desktop:~/workspace/test/src$ ./a.out
before fork
pid=3395,glob=7,var=89
asd@asd-desktop:~/workspace/test/src$
程序清单 8-3 打印exit状态的说明 P180
/**
* 程序清单 8-3 打印exit状态的说明 P180
*
* zy:
* 背景是这样,
* 如果子进程终止了,无论异常还是正常的,
* 那么内核就会通过给父进程发送SIGCHLD信号
* 父进程可以调用wait和waitpid这个两个函数获得子进程结束的状态,
* 如果父进程收到SIGCHLD之后调用wait,那么可以立刻返回,获得子进程结束的状态
* 如果父进程在任意时刻调用wait,那么会堵塞,直接接受到SIGCHLD信号,然后拿到子进程结束的状态
*
* 这个8-3的代码就是写一个函数
* 传入子进程结束的状态
* 就打印出一些信息,供我们判断。
*/
#include "apue.h"
#include "error.c"
#include <sys/wait.h>
void pr_exit(int status){
printf("status: %d",status);
if(WIFEXITED(status)){//如果是子进程正常返回,该判断为真
printf("normal termination, exit status = %d \n",
WEXITSTATUS(status));//取得子进程 exit()返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。
}else if (WIFSIGNALED(status)) {//如果子进程是异常返回,则为真
printf("abnormal termination, signal number = %d %s \n",
WTERMSIG(status),//取得子进程因信号而中止的信号代码,一般会先用 WIFSIGNALED 来判断后才使用此宏。
#ifdef WCOREDUMP
WCOREDUMP(status)?"(croe file generated )": " "
#else
" ");
#endif
}else if(WIFSTOPPED(status))//若为当前暂停子进程的返回的状态,则为真
printf("child stopped,signal number = %d\n",WSTOPSIG(status));
}
程序清单 8-4 演示不同的exit值 P181
/**
程序清单 8-4 演示不同的exit值 P181
zy:
同时,我们也演示了wait函数,
注意,调用wait函数后,我们将等待子进程返回,
拿到状态后,我们再用pr_exit来打印其状态信息
*/
#include "apue.h"
#include "error.c"
#include <sys/wait.h>
void pr_exit(int status){
printf("status: %d",status);
if(WIFEXITED(status)){//如果是子进程正常返回,该判断为真
printf("normal termination, exit status = %d \n",
WEXITSTATUS(status));//取得子进程 exit()返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。
}else if (WIFSIGNALED(status)) {//如果子进程是异常返回,则为真
printf("abnormal termination, signal number = %d %s \n",
WTERMSIG(status),//取得子进程因信号而中止的信号代码,一般会先用 WIFSIGNALED 来判断后才使用此宏。
#ifdef WCOREDUMP
WCOREDUMP(status)?"(croe file generated )": " "
#else
" ");
#endif
}else if(WIFSTOPPED(status))//若为当前暂停子进程的返回的状态,则为真
printf("child stopped,signal number = %d\n",WSTOPSIG(status));
}
int main(void){
pid_t pid;
int status;
if((pid=fork())<0){
err_sys("fork error");
}else if( pid==0){//child
exit(7);
}
if(wait(&status)!=pid){
err_sys("wait error");
}
pr_exit(status);
if((pid=fork())<0){
err_sys("fork error");
}else if( pid==0){//child
abort();
}
if(wait(&status)!=pid){
err_sys("wait error");
}
pr_exit(status);
if((pid=fork())<0){
err_sys("fork error");
}else if( pid==0){//child
status/=0;
}
if(wait(&status)!=pid){
err_sys("wait error");
}
pr_exit(status);
exit(0);
}
结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
status: 1792normal termination, exit status = 7
status: 134abnormal termination, signal number = 6
status: 136abnormal termination, signal number = 8
asd@asd-desktop:~/workspace/test/src$
程序清单 8-5 调用fork两次以避免僵尸进程 P183
/**
* 程序清单 8-5 调用fork两次以避免僵尸进程 P183
*
* zy:
* 首先要明白什么是僵尸进程
* 也就是就是一个虽然已经终止的子进程,但是父进程没有回收其资源的
* 就是僵尸进程。
*
* 我们这里避免成为僵尸进程的办法其实就是
* 让init进程变为一个子进程的父进程,这样就是可以由init进程完全其回收资源等工作
*
*/
#include "apue.h"
#include "error.c"
#include <sys/wait.h>
int main(){
pid_t pid;
if((pid=fork())<0){
err_sys("fork error");
}else if (pid == 0){//first child
if((pid=fork())<0){
err_sys("fork error");
}else if(pid>0){//这是第一孩子,也是第二个孩子的父亲
exit(0);
}
//第二个孩子执行这一段代码
//由于第二个孩子的父亲,也就是第一个孩子自己exit了,所以其父进程很快就会变成为init进程
sleep(2);
printf("我是第二个孩子,我们的父进程是:%d\n",getppid());
exit(0);
}
//下面是第一个孩子的父进程执行的代码,这里是为了回收一个第一个孩子的资源
if(waitpid(pid,NULL,0)!=pid){
err_sys("waitpid error");
}
//下面我就可以在这里写第一个孩子,父进程的代码了,在这里它已经不是任何孩子的父亲了
exit(0);
}
结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
asd@asd-desktop:~/workspace/test/src$ 我是第二个孩子,我们的父进程是:1
程序清单 8-6 具有竞争条件的程序 P186
/**
* 程序清单 8-6 具有竞争条件的程序 P186
*
* zy:
由子进程和父进程各输出一段话,由于依赖于进程调度,包括顺序和运行时间
所以每次运行的结果都不是一样的。
*
*/
#include "apue.h"
#include "error.c"
static void charatatime( char * str){
char *ptr;
int c;
setbuf(stdout,NULL);//设置其没有缓冲
for(ptr=str;(c= *ptr++)!=0;){//设置其一个字符一个字符的打
putc(c,stdout);
}
}
int main(){
pid_t pid;
if((pid=fork())<0){
err_sys("fork error");
}else if (pid == 0){//first child
charatatime("output from child\n");
}else{
charatatime("output from parent\n");
}
}
结果:
asd@asd-desktop:~/workspace/test/src$ gcc test.c
asd@asd-desktop:~/workspace/test/src$ ./a.out
outputou tfpruotm fpraorme ncth
ild
asd@asd-desktop:~/workspace/test/src$ ./a.out
output from parent
output from child
asd@asd-desktop:~/workspace/test/src$ ./a.out
output from parent
output from child
asd@asd-desktop:~/workspace/test/src$ ./a.out
outpuotu tfpruotm fpraorme ncth
ild
asd@asd-desktop:~/workspace/test/src$ ./a.out
outpuotu tfpruotm fpraorme ncth
ild
asd@asd-desktop:~/workspace/test/src$ ./a.out
outputo uftrpoumt pfarroemn tc
hild
asd@asd-desktop:~/workspace/test/src$
asd@asd-desktop:~/workspace/test/src$ ./a.out
output from parent
output from child
asd@asd-desktop:~/workspace/test/src$ ./a.out
outpuotu tfpruotm fpraorme ncth
ild
asd@asd-desktop:~/workspace/test/src$
程序清单 8-7 修改程序清单8-6以避免竞争条件
/**
* 程序清单 8-7 修改程序清单8-6以避免竞争条件
*
* zy:
* 我们主要使用了tell wait、wait parent等一系列函数
* 这些函数都不能理解
* 顾名思义即可
* 以后会具体分析其实现方法
*
* 所以该代码现在还不能运行,因为现在还没有现实嘛,先放在这里吧
*
*/
#include "apue.h"
#include "error.c"
#include "apue.h"
static void charatatime( char * str){
char *ptr;
int c;
setbuf(stdout,NULL);//设置其没有缓冲
for(ptr=str;(c= *ptr++)!=0;){//设置其一个字符一个字符的打
putc(c,stdout);
}
}
int main(){
pid_t pid;
TELL_WAIT();
if((pid=fork())<0){
err_sys("fork error");
}else if (pid == 0){//first child
WAIT_PARENT();
charatatime("output from child\n");
}else{
charatatime("output from parent\n");
TELL_CHILD(pid);
}
}
程序清单 8-7 exec函数实例
/**
* 程序清单 8-7 exec函数实例 P191
*
* zy:
* 我们用子进程去执行echoall.out程序,这个程序也是我们自己写的,是程序清单8-9
* 其中参数有个关键就是(char *) 0之前表示参数结束
*
* 下面这段程序的execlp部分能够正常执行的,也就是能够正常执行echoall.out这个函数
* 但是execle部分是没有成功执行的,我也没有查出原因
* 如果我对第一个参数传入:/home/asd/workspace/test/src/的话,得到的错误是:Permission denied
*
* 但是如果我传入/home/asd/workspace/test/src/echoall.out,得到的错误又将是:Bad address
*
*/
#include "error.c"
#include "apue.h"
#include "sys/wait.h"
char *env_init[]={"USER=unknown","PATH=/tmp",NULL};
int main(){
pid_t pid;
if((pid=fork())<0){
err_sys("fork error");
}else if (pid == 0){//first child
if(execle("/home/asd/workspace/test/src/echoall.out","echoall.out","myarg1","MY_ARG2","(char *)0",env_init)<0){
err_sys("execle error");
}
}
if(waitpid(pid,NULL,0)<0){
err_sys("wait error");
}
if((pid=fork())<0){
err_sys("fork error");
}else if (pid == 0){//first child
if(execlp("./echoall","echoall","only 1 arg",(char *)0)<0){
err_sys("execlp error");
}
}
exit(0);
}
程序清单 8-9 回送所有命令行参数和所有环境字符串 P192
/**
程序清单 8-9 回送所有命令行参数和所有环境字符串 P192
zy:
这个程序是被8-8所执行的echoall.out,没有什么特别的
只是回送了所有的参数和环境变量
*/
#include "apue.h"
#include "error.c"
int main(int argc, char **argv) {
int i;
char **ptr;
extern char **environ;
for(i=0;i<argc;i++){
printf("agrv[%d] : %s \n",i,argv[i]);
}
for(ptr=environ;*ptr!=0;ptr++){
printf("%s\n",*ptr);
}
exit(0);
}
程序清单 8-10 执行一个解释器文件的程序
/**
* 程序清单 8-10 执行一个解释器文件的程序 P197
*
* zy:
* 出现的错误和8-9类似
* 总是permission denied 似乎和机子有关
*
* 在这个题中,解释器的存在显得非常的简单,因解释器就是一个文本,文本里面放着要执行的程序
*
*/
#include "error.c"
#include "apue.h"
#include "sys/wait.h"
int main(){
pid_t pid;
if((pid=fork())<0){
err_sys("fork error");
}else if (pid == 0){//first child
if(execl("/home/asd/workspace/test/src/testinterp","testinterp","myarg1","MY_ARG2","(char *)0")<0){
err_sys("execle error");
}
}
if(waitpid(pid,NULL,0)<0){
err_sys("wait error");
}
exit(0);
}
程序清单 8-11 作为解释器文件的awk程序
基本上不太明白这段代码是怎么回事,搞了半天好像也不是c代码
程序清单 8-12 system函数(没有信号处理)P200
/**
* 程序清单 8-12 system函数(没有信号处理)P200
*
* zy:
* system函数在代码中调用的时候就是说:相当于在终端输入一些命令
* 产生的结果方便在代码中使用
*/
#include "sys/wait.h"
#include "error.c"
#include "apue.h"
#include "unistd.h"
#include <errno.h>
int mySystem(const char * cmdstring){
pid_t pid;
int status;
if(cmdstring==NULL){
return(1);
}
if((pid=fork())<0){
status=-1;
}else if(pid==0){//child
execl("/bin/sh","sh","-c",cmdstring,(char *)0);
_exit(127);
}else{//parent
while(waitpid(pid,&status,0)<0){
if(errno!=EINTR){
status=-1;
break;
}
}
}
return status;
}
int main(){
mySystem("date");
}
程序清单 8-13 调用system函数P201
/**
* 程序清单 8-13 调用system函数P201
*
* zy:
* 这是一段代码用于测试8-12所写的system函数
*/
#include "sys/wait.h"
#include "error.c"
#include "apue.h"
#include "unistd.h"
#include <errno.h>
int mySystem(const char * cmdstring){
pid_t pid;
int status;
if(cmdstring==NULL){
return(1);
}
if((pid=fork())<0){
status=-1;
}else if(pid==0){//child
execl("/bin/sh","sh","-c",cmdstring,(char *)0);
_exit(127);
}else{//parent
while(waitpid(pid,&status,0)<0){
if(errno!=EINTR){
status=-1;
break;
}
}
}
return status;
}
int main(int argc, char **argv) {
int status;
if((status=mySystem("date"))<0){
err_sys("system() error");
}
//pr_exit(status);这个好像以后才实现,现在还没实现呢
if((status=mySystem("nosuchcommmand"))<0){
err_sys("system() error");
}
//pr_exit(status);
if((status=mySystem("who;exit 44"))<0){
err_sys("system() error");
}
//pr_exit(status);
exit(0);
}
结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
Mon Mar 10 21:55:03 CST 2014
sh: 1: nosuchcommmand: not found
asd tty7 2014-03-10 18:52
asd pts/0 2014-03-10 21:41 (:0.0)
asd@asd-desktop:~/workspace/test/src$
程序清单 8-14 用system执行命令行参数
/**
* 程序清单 8-14 用system执行命令行参数
*
* zy:
* 这个本身没什么,主要是和8-15配合
*/
#include "error.c"
#include "apue.h"
int main(int argc, char **argv){
int status;
if(argv<2)
err_quit("command-line argument required");
if((status=system(argv[1]))<0)
err_sys("system ()error");
//pre_exit(status);//暂时没找到这个代码的实现处
}
程序清单 8-15 打印实际和有效用户ID P203
/**
* 程序清单 8-15 打印实际和有效用户ID P203
*
* zy:
* 这里主要是讲一个漏洞,
* 当我们让给予了8-14的程序超级用户权限时,
* 其在system函数中执行的fork和exec也具有超级用户的权限
*
* 为了预防这样的情况,我们应该直接调用fork和exec,而不要调用system函数
*/
#include "error.c"
#include "apue.h"
int main() {
printf("real uid=%d, efffective uid =%d \n",getuid(),geteuid());
}
结果:
asd@asd-desktop:~/workspace/test/src$ ./tsys /home/asd/printuids
real uid=1000, efffective uid =1000
asd@asd-desktop:~/workspace/test/src$ su
Password:
root@asd-desktop:/home/asd/workspace/test/src# chown root t
test2.c test2.c~ test.c test.c~ testinterp tsys
root@asd-desktop:/home/asd/workspace/test/src# chown root tsys
root@asd-desktop:/home/asd/workspace/test/src# chmod u+s tsys
root@asd-desktop:/home/asd/workspace/test/src# ls -l tsys
-rwsrwxr-x 1 root asd 7765 Mar 13 09:22 tsys
root@asd-desktop:/home/asd/workspace/test/src# exit
exit
asd@asd-desktop:~/workspace/test/src$ ./tsys /home/asd/printuids
real uid=1000, efffective uid =0
其中:chmod u+s
- “为了方便普通用户执行一些特权命令,SUID/SGID程序允许普通用户以root身份暂时执行该程序,并在执行结束后再恢复身份。”
chmod u+s 就是给某个程序的所有者以suid权限,可以像root用户一样操作。
请注意,我们使用了chown之后,tsys的所有者是root,然而我们又退出了root权限,在执行第二句:
./tsys /home/asd/printuids
的时候,我们的身份是asd,那么为什么能够执行root所有者的程序,就是因为chmod u+s这个命令。
此外,我们可以看到在system函数中执行的fork和exec也具有超级用户的权限,预防这样的情况发生就是,不要使用system,而是使用fork和exec。
程序清单 8-16 产生会计数据的程序 P205
/**
* 程序清单 8-16 产生会计数据的程序 P205
*
* zy:
* 这主要是用于产生会计进程的数据
* 这些数据将由另一个程序8-17调用,以供我们的观察
*
* 会计进程当进程结束时就会记录,可以用accton命令将其打开
* 注意我的系统是linux,那么我的会计文件会产生在/var/account/pacct
*/
#include "error.c"
#include "apue.h"
int main() {
pid_t pid;
if((pid=fork())<0)
err_sys("fork error");
else if(pid!=0){//parent
sleep(2);
exit(2);
}
//first child
if((pid=fork())<0)
err_sys("fork error");
else if(pid!=0){// first child as parent
sleep(4);
abort();
}
//second child
if((pid=fork())<0)
err_sys("fork error");
else if(pid!=0){// second child as parent
execl("/bin/dd","dd","if=//home/asd/Downloads/vimrc.zip","of=/dev/null",NULL);//dd就是一个复制的命令,后面两个参数应该不言而喻吧
exit(7);
}
//third child
if((pid=fork())<0)
err_sys("fork error");
else if(pid!=0){// third child as parent
sleep(8);
abort();
}
//fourth child
sleep(6);
kill(getpid(),SIGKILL);
exit(6);
}
程序清单 8-17 用system执行命令行参数 P206
/**
* 程序清单 8-17 用system执行命令行参数 P206
*
* zy:
* 用这个程度去读会计文件,将我们需要的东西打印出来
*/
#include "error.c"
#include "apue.h"
#include <sys/acct.h>
#ifdef HAS_SA_STAT
#define FMT "%-*.*s e=%6ld, chars = %7ld, stat=%3u: %c %c %c %c\n" //%-*.*s翻K&R的书136页,-表示左对齐,
//第一个*字符串总共多长
//第二个*表示占占多长
#else
#define FMT "%-*.*s e=%6ld, chars = %7ld, %c %c %c %c\n"
#endif
#ifndef HAS_ACORE
#define ACORE 0
#endif
#ifndef HAS_AXSIG
#define AXSIG 0
#endif
static unsigned long compt2ulong(comp_t comptime){ //将comp_t格式转化为unsign long的形式
//long形式之后的数字是就墙上时钟时间,以每秒滴答数为单位测量
unsigned long val;
int exp;
val=comptime & 0x1fff;
exp=(comptime >> 13 )& 7;
while(exp -- >0)
val*=8;
return(val);
}
int main(int argc, char **argv){
struct acct acdata;
FILE *fp;
if(argc!=2)
err_quit("usage:pracct filename");
if((fp=fopen(argv[1],"r"))==NULL){
err_sys("can't open %s ",argv[1]);
}
while(fread(&acdata,sizeof(acdata),1,fp)==1){
printf(FMT,
(int)sizeof(acdata.ac_comm), //command name 就是程序名
(int)sizeof(acdata.ac_comm),
acdata.ac_comm, //这个是字符串,那上面两个是打印什么的
compt2ulong(acdata.ac_etime), //elapsed tiem
compt2ulong(acdata.ac_io), //传输的字节数,包括read和write
#ifdef HAS_SA_STAT
(unsigned char)acdata.ac_stat, //终止状态
#endif
acdata.ac_flag & ACORE ?'D':' ',//进程转储core
acdata.ac_flag & AXSIG ?'X':' ',//进程由信号杀死
acdata.ac_flag & AFORK ?'F':' ',//进程是由fork产生
acdata.ac_flag & ASU ?'S':' ' //进程使用超级用户模式
);
}
if(ferror(fp))
err_sys("read error");
exit(0);
}
结果:
asd@asd-desktop:~/workspace/test/src$ accton on
Turning on process accounting, file set to the default '/var/log/account/pacct'.
accton: Operation not permitted
asd@asd-desktop:~/workspace/test/src$ ./a.out
7+1 records in
7+1 records out
4074 bytes (4.1 kB) copied, 0.000168319 s, 24.2 MB/s
asd@asd-desktop:~/workspace/test/src$ accton off
Turning off process accounting.
accton: Operation not permitted
asd@asd-desktop:~/workspace/test/src$ sudo accton off
Turning off process accounting.
asd@asd-desktop:~/workspace/test/src$ gcc test.c
asd@asd-desktop:~/workspace/test/src$ ./a.out /var/log/account/pacct
� e= 7350, chars = 7349, S
e= 7349, chars = 7333,
e= 7333, chars = 7327,
e= 7327, chars = 7326,
, e= 7326, chars = 7295,
e= 7353, chars = 7352,
e= 7352, chars = 7351,
Y1 e= 7351, chars = 7295, F
e= 7354, chars = 7295,
e= 7355, chars = 7295,
e= 7356, chars = 7295,
o$ e= 7295, chars = 7294, S
8 e= 7294, chars = 7132, S
�% e= 7358, chars = 7357,
e= 7359, chars = 7357,
e= 7360, chars = 7357,
e= 7361, chars = 7357,
e= 7362, chars = 7357,
k' e= 7357, chars = 2261,
x e= 7365, chars = 7363,
l e= 7366, chars = 7363,
0 e= 7368, chars = 1724, F
p e= 7373, chars = 7371,
e= 7371, chars = 7369,
�% e= 7374, chars = 7369,
�( e= 7367, chars = 7363,
e= 7363, chars = 2261,
e= 7375, chars = 7369,
e= 7376, chars = 7369,
e= 7377, chars = 7369,
� e= 7378, chars = 7132,
� e= 7379, chars = 7132,
0 e= 7380, chars = 1724, F
e= 7382, chars = 7132,
]* e= 7381, chars = 1,
e= 7384, chars = 7132,
$ e= 7387, chars = 7386,
� e= 7385, chars = 7132,
1' e= 7390, chars = 7040, S
� e= 7386, chars = 1, F
� e= 7389, chars = 7388, F
2' e= 7391, chars = 7242, S
� e= 7388, chars = 1, F
e= 7392, chars = 7132,
e= 7394, chars = 7393,
可能和机子有关,我打印出来名字全是乱码,反正意思我大概懂了,书上讲的很清楚。
程序清单 8-18 时间以及执行所有命令参数 P209
/**
* 程序清单 8-18 时间以及执行所有命令参数 P209
*
* zy:
* 主要将times这个函数
* 可以得到一个结构,结构里有各种时间
* 比如用户cpu时间、系统cpu时间
* 主要注意是需要记录两个时间,然后算差值
*/
#include "error.c"
#include "apue.h"
#include <sys/times.h>
static void pr_times(clock_t,struct tms *,struct tms*);
static void do_cmd(char *);
int main(int argc, char *argv[]){
int i;
setbuf(stdout,NULL);//标准输出是无缓冲的
for(i=1;i<argc;i++){
do_cmd(argv[i]);
}
exit(0);
}
static void do_cmd(char *cmd){
struct tms tmsstart,tmsend;
clock_t start,end;
int status;
printf("\ncommand: %s\n",cmd);
if((start=times(&tmsstart))==-1)//times的返回值就是当前流逝的墙上时钟时间
err_sys("times error");
if((status=system(cmd))<0){
err_sys("system() error");
}
if((end=times(&tmsend))==-1){//需要start和end两者相减得到运行的时间
err_sys("times error");
}
pr_times(end-start,&tmsstart,&tmsend);
//pr_exit(status);
}
static void pr_times(clock_t real,struct tms *tmsstart,struct tms *tmsend){
static long clktck=0;
if(clktck==0){
if((clktck=sysconf(_SC_CLK_TCK))<0){//每秒的滴答数,我们用这个将滴答数转化为秒数
err_sys("sysconf error");
}
}
printf("\treal:\t%7.2f\n",real/(double)clktck);
printf("\tuser:\t%7.2f\n",(tmsend->tms_utime-tmsstart->tms_utime)/(double)clktck);
printf("\tsys :\t%7.2f\n",(tmsend->tms_stime-tmsstart->tms_stime)/(double)clktck);
printf("\tchild user:\t%7.2f\n",(tmsend->tms_cutime-tmsstart->tms_cutime)/(double)clktck);
printf("\tchild sys:\t%7.2f\n",(tmsend->tms_cstime-tmsstart->tms_cstime)/(double)clktck);
}
结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out "sleep 5" "date"
command: sleep 5
real: 5.02
user: 0.00
sys : 0.00
child user: 0.00
child sys: 0.00
command: date
Thu Mar 13 12:00:57 CST 2014
real: 0.02
user: 0.00
sys : 0.00
child user: 0.00
child sys: 0.00
asd@asd-desktop:~/workspace/test/src$