《Unix/Linux编程实践教程》chapter2 用户、文件操作与联机帮助

chapter2 用户、文件操作与联机帮助

章节知识总结

who命令通过读取系统日志(UTMP_FILE文件)的内容显示当前已经登录的用户.

Unix系统把数据存放在普通文件中,可以通过以下系统调用操作文件:

  • open(filename,how):how为打开方式(O_RDONLY,O_WRONLY,O_RDWR三种方式)
  • creat(filename,mode):mode为创建的文件的权限,该权限只是给系统的建议,实际权限由系统的umask决定
  • read(fd,buffer,amt):amt为读取的size大小,该函数返回值为实际读取的size大小
  • write(fd,buffer,amt):同read,该函数返回值为实际读取的size大小
  • lseek(fd,distance,base);将文件指针移动到指定位置,base为参考坐标,distance为偏移量
  • close(fd):关闭文件

进程对文件的读/写都要通过文件描述符,文件描述符表示文件和进程之间的连接.

  • 如果同时打开好几个文件,它们所对应的文件描述符是不同的;如果将一个文件打开多次,对应的文件描述符也是不同的。

每次系统调用都会导致用户模式和内核模式的切换以及执行内核代码,所以减少程序中的系统调用发生的次数可以提高程序的运行效率。

  • 当工作在内核模式时,程序可以直接访问磁盘、终端、打印机等设备,还可以访问全部的内存空间;而在用户模式,程序不能直接访问设备,也只能访问特定部分的内存空间。

程序可以通过缓冲技术来减少系统调用的次数,仅当写缓冲区满或读缓冲区空时才调用内核服务。(Unix内核中采用了缓冲技术来减少访问磁盘I/O的次数)

内核运用缓冲技术导致的结果:

  • 提高磁盘I/O效率
  • 优化磁盘的写操作
  • 需要及时地将缓冲数据写入磁盘(系统异常断点等情况可能会导致缓冲中的数据不能及时写回磁盘)

当系统调用出错时会把全局变量errno的值设为相应的错误代码,返回返回-1,程序可以通过检测errno来确定错误的类型,并采取相应的措施。(在<errno.h>头文件中有相应的说明)

cp指令实现

cp指令的简易实现如下:

/*
    cp指令简易实现
*/
#include<stdio.h>
#include<fcntl.h>    //for open() and creat()
#include<unistd.h>   //for close() and read()

#define BUFSIZE 4096    //声明缓冲区大小
#define FMODE 0644      //声明创建的文件权限

//声明打印错误信息的函数
void oop(char* ,char*);

int main(int ac,char* av[]){

    //参数数量检查
    if(ac!=3){
        fprintf(stderr,"usage: %s source destination\n",*av);
        exit(1);
    }

    //判断源文件和目标文件是否相同
    if(strcmp(av[1],av[2])==0){
        fprintf(stderr,"cp: %s and %s are the same file. \n",av[1],av[2]);
        exit(1);
    }

    //打开源文件
    int source_fp;
    if((source_fp=open(av[1],O_RDONLY))==-1){
        oop("open file error",av[1]);
    }

    //创建目标文件
    int taget_fp;
    if((taget_fp=creat(av[2],FMODE))==-1){
        oop("creat file error",av[2]);
    }

    //复制源文件到目标文件
    char buf[BUFSIZE];
    int n_char;
    while((n_char=read(source_fp,&buf,BUFSIZE))>0){
        if((write(taget_fp,&buf,n_char))!=n_char)
            oop("write file error",av[2]);
    }

    //关闭文件
    if(close(source_fp)==-1||close(taget_fp)==-1){
        oop("close file error",av[0]);
    }

    return 0;
}

void oop(char* error,char* filename){
    fprintf(stderr,"usage: %s",error);
    perror(filename);
    exit(1);
}
who指令实现

who指令的简易实现如下:

/*
    who指令简易实现
*/
#include<stdio.h>
#include<fcntl.h>    //for open() and creat()
#include<unistd.h>   //for read() and write()
#include<time.h>     //for ctime()
#include<utmp.h>     //for struct utmp

#define BUF_NUM 16   //定义缓冲区数量
#define BUF_SIZE (sizeof(struct utmp))  //定义缓冲区单位大小
#define NULLUTP ((struct utmp*)NULL)

#define SHOWHOST
#define ACTIVE_ONLY

//函数声明
void show_time(long);
void show_info(struct utmp*);

static char utmpbuf[BUF_NUM*BUF_SIZE];  //缓冲区大小
static int  num_recs;                   //缓冲区总存量
static int  cur_rec;                    //当前已使用缓冲区个数
static int  fd_utmp=-1;                 //utmp文件的文件描述符

//打开utmp文件
int utmp_open(char* filename){
    fd_utmp=open(filename,O_RDONLY);
    num_recs=cur_rec=0;
    return fd_utmp;
}

//申请更多缓冲区
int utmp_reload(){
    int amt_read;
    amt_read=read(fd_utmp,&utmpbuf,BUF_NUM*BUF_SIZE);
    num_recs=amt_read/BUF_SIZE;
    cur_rec=0;
    return num_recs;
}

//读取下一个数据
struct utmp* utmp_next()
{
    struct utmp* recp;
    if(fd_utmp==-1)
        return NULLUTP;
    //当缓冲区全部用完后,重新申请
    //若申请为0,表示读取utmp完毕
    while(1){
        if(cur_rec==num_recs&&utmp_reload()==0)
            return NULLUTP;
        recp=(struct utmp*)&utmpbuf[cur_rec*BUF_SIZE];
        ++cur_rec;
        #ifdef ACTIVE_ONLY
        if(recp->ut_type==USER_PROCESS)
        #endif
            return recp;
    }
    return NULLUTP;
}

//关闭utmp文件
void utmp_close(){
    if(fd_utmp!=-1)
        close(fd_utmp);
}

int main(){
    if(utmp_open(UTMP_FILE)==-1){
        perror(UTMP_FILE);
        exit(1);
    }
    struct utmp* utbufp;
    while((utbufp=utmp_next())!=(struct utmp*)NULL)
        show_info(utbufp);
    utmp_close();
    return 0;
}

void show_info(struct utmp* utp){
    //为在线的用户信息不打印
    if(utp->ut_type!=USER_PROCESS) return;
    printf("%-8.8s",utp->ut_user);      //the logname
    printf(" ");
    printf("%-8.8s",utp->ut_line);      //the tty
    printf(" ");
    show_time(utp->ut_time);            //the log time
    #ifdef SHOWHOST
    if(utp->ut_host[0]!='\0')
        printf("(%s)",utp->ut_host);    //the host
    #endif
    printf("\n");
}

void show_time(long timeval){
    char *cp;
    cp=ctime(&timeval);
    //cp="Tue Feb 23 09:25"
    printf("%12.16s",cp+4);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值