Unix/Linux编程实践教程阅读笔记-终端注销代码-来自第二章P54-P57的笔记

在完成了对who指令的实现后(参考链接:https://www.cnblogs.com/czw52460183/p/10999434.html),我们已经知道Linux系统的用户登录信息存储在utmp这个文件里,因此要实现终端注销,就是修改这个文件的内容。

终端注销的基本思路:

  1.打开utmp文件,要考虑到打开失败的情况。

  2.循环读取每一个utmp结构体,要考虑读取异常的情况。对读取到的每一个结构体,判断其终端名是否和传入的名字一致。

  3.一旦一致,修改其登录状态和登录时间,登录时间修改时要考虑到获取系统时间失败的情况。

  4.重定位光标到刚刚读取的地方,把修改后的信息重新写入文件。重定位和写入都要考虑到失败的情况。注意,3,4两点中出现任意一种失败情况,都要直接跳出循环,不能再继续读取下一个utmp结构体,因为匹配只能匹配一条。

  5.循环结束后,关闭打开的文件,也要考虑到关闭失败的情况。

由此看出,写程序的时候一定要注意对各种异常情况要考虑周全,这样写出的程序才能有更好的健壮性。

  之前的文章说过了,我们在Mac下的环境中对utmp的访问已经做了封装,直接访问会有乱码,所以书上的代码就不进行测试了,直接加上注释后贴出来:

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <utmp.h>

//终端注销函数,传入参数为本终端名
//返回值0代表成功,返回值-1代表失败
int logout_tty(char *line)
{
    int fd;
    //先要打开utmp文件,打开时要考虑到打开失败的情况
    if((fd = open(UTMP_FILE,O_RDWR)) == -1)
    {
        return -1;
    }
    struct utmp rec;
    int len = sizeof(struct utmp);
    int retval = -1;
    //循环读取文件中的结构体,要考虑读取异常的情况
    while(read(fd,&rec,len) == len)
    {
        //比较终端名是否匹配
        if(strncmp(rec.ut_line,line,sizeof(rec.ut_line)) == 0)
        {
            //修改登录状态
            rec.ut_type = DEAD_PROCESS;
            //修改登录时间,要判断是否成功
            if(time(&rec.ut_time) != -1)
            {
                //将光标定位到之前读取的结构体的位置
                if(lseek(fd,-len,SEEK_CUR) != -1)
                {
                    //写入修改后的信息
                    if(write(fd,&rec,len) == len)
                    {
                        retval = 0;
                    }
                }
            }
            //终端名一旦匹配后在某一个修改环节出错,则直接退出,不会进行后续读取匹配
            break;
        }
    }
    //关闭文件,也要判断是否成功
    if(close(fd) == -1)
    {
        retval = -1;
    }
    return retval;
}
原文地址:https://www.cnblogs.com/czw52460183/p/11016708.html