一.注销过程
1.基本步骤:
(有关 utmp 的内容参见 :who命令的编写)
注销过程中,系统改变了文件utmp中相应的登录记录,注销过程如下:
(1).打开文件utmp;
(2).从utmp中找到包含你所在终端的登录记录;
(3).对当前记录做修改;
(4).关闭文件;
其中要注意的是第3步:对当前记录做修改。
2.对当前记录做修改:
(1)把ut_type的值从USER_PROCESS DEAD_PROCESS;
(2)把ut_time字段的值改为注销时间,即当前时间;
(3)有些版本会把用户名和远程主机字段的内容清空;
除以上步骤外:最棘手的是如何把修改过阿记录写回文件?不能用write,write只会更新下一条记录,而不是当前那条要修改的记录。因为系统每次打开一个文件都会保存一个指向文件当前位置的指针,当读写完成时,指针都会移向下一个记录位置,这个指针与文件描述符相关联。如何操作呢?可以使用系统调用 lseek 。
指针是与文件描述符相关联的,而不是与文件关联 ,所以如果两个程序同时打开一个文件,这时会有两个指针,两个程序对文件的读操作不会互相干扰。lseek改变文件描述符所关联的指针位置。
3.lseek函数
目标 使指针指向文件中的指针位置
头文件 #include<sys/type.h>
#include<unistd.h>
函数原型 off_t currpos = lseek( int fd , off_t dist , int base );
参数 fd:文件描述符 ; dist:移动的距离 (可以为负);
base :SEEK_SET 文件的开始 ; SEEK_CUR 文件当前; SEEK_END 文件结尾 ;
返回值 -1 遇到错误 ;
二.代码实例
程序需要在终端下以root身份运行,如 #: ./a.out pts/1
( pts/1 为一个打开的终端用户 )
#include <stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include<utmp.h>
#include<fcntl.h>
#include<string.h>
#include<time.h>
int logout_tty(char *line);
int main(int ac,char * av[])
{
if(ac != 2)
{
puts("参数个数不正确\n");
exit(1);
}
char line[32];
strcpy(line,av[1]);
logout_tty(line);
return EXIT_SUCCESS;
}
int logout_tty(char *line)
{
int fd;
struct utmp rec;
int len = sizeof(struct utmp);
int retval = -1;
// 此处 O_RDWR 需要root用户运行
if((fd = open(UTMP_FILE , O_RDWR)) == -1)
{
perror(UTMP_FILE);
return -1;
}
off_t pos;
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( (pos=lseek(fd,-len,SEEK_CUR) )!= -1)
if(write(fd,&rec,len) == len)
retval = 0;
break;
}
}
if(close(fd) == -1)
retval = -1;
return retval;
}