1

《Unix/Linux编程实践教程》笔记(1)

 2 years ago
source link: https://houye.xyz/2017-11/uup1/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
《Unix/Linux编程实践教程》笔记(1)

第二章讲了文件操作函数(open,read,write,lseek,close),并且编程实现了系统命令who的部份功能,通过man手册,知道who命令就是通过读取var/run/utmp得到用户登录信息,随后man utmp得到文件中存储的结构体源码,最后实现一个0.1版本的who命令。接下来解决了空白记录和时间显示的问题,实现了一个更加好用的who命令。2.6节实现了cp命令,read一个文件的内容在write到另一个文件。2.7节,用缓冲区减少文件读写的次数来提高文件IO效率。

系统重启时,会清除utmp中的登录信息

whoami命令只会打印执行命令的有效用户,who命令则显示当前系统登录的用户,终端和登录时间等信息。 实现whoami命令需要用到系统函数geteuid,代码如下

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>

int main (void){
	uid_t uid;
	struct passwd *puser = NULL;

	uid = geteuid();
	if ((puser = getpwuid(uid)) != NULL)
		printf ("%s\n",puser->pw_name);
	else
		printf ("error\n");

	return 0;
}

Linux系统通过inode号来区分文件,所以这里用了系统函数getinode,比较两个文件的inode号就可以判断原文件和目标文件是否是同一个文件。

ac命令通过读取wtmp文件,来统计用户登录时间。man utmp可以得到utmp的结构体定义,ut_type USER_PREOCESS 记录用户登入时间,登出时间有几种情况,一是用户正常登出即ut_type为DEAD_PROCESS,二是系统reboot或者shutdown(reboot或者shutdown时,wtmp会增加有ut_name为reboot或者shutdown的记录),三是正登录的用户,此时将这些记录的登出时间设为当前时间。我仅实现了统计所有登录时间的功能,没有系统时间被更改的情况,完整代码如下:

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

//#define	INFOFILE	"/var/run/utmp"
#define	INFOFILE	"/var/log/wtmp"

struct logutmp {
	char ut_name[UT_NAMESIZE];
	char ut_line[UT_LINESIZE];
	time_t logintime;
	time_t logoutime;
};
struct logutmp tmplogutmp[256];
int numuse = 0;
long alltime = 0;

void countalltime(char *ut_namep, struct utmp *utbufp)
{
	if (utbufp == ((struct utmp*) NULL)) //已经读到wtmp的结尾,把正登录用户的登出时间设为当前时间
	{
		for ( int i =0; i < numuse; i++)
		{
			if ( strcmp (tmplogutmp[i].ut_name, "houye") == 0 && tmplogutmp[i].logintime != 0 && tmplogutmp[i].logoutime ==0)
			{
				time(&tmplogutmp[i].logoutime);
				alltime += (long)(tmplogutmp[i].logoutime - tmplogutmp[i].logintime);
			}

		}
		return;
	}
	if ( utbufp->ut_type == USER_PROCESS && strcmp(utbufp->ut_name, ut_namep) == 0) //读到wtmp中的登录记录
	{
		int i;
		for ( i = 0; i < numuse; i++ )
		{
			if ( strcmp ( tmplogutmp[i].ut_line, utbufp->ut_line ) == 0)
			{
				tmplogutmp[i].logintime = utbufp->ut_time;
				tmplogutmp[i].logoutime = 0;
				break;
			}

		}
		if ( i >= numuse ) 
		{
			strcpy ( tmplogutmp[numuse].ut_name, utbufp->ut_name );
			strcpy ( tmplogutmp[numuse].ut_line, utbufp->ut_line );
			tmplogutmp[numuse].logintime = utbufp->ut_time;
			tmplogutmp[numuse].logoutime = 0;
			numuse ++;
		}
	}
	if ( utbufp->ut_type == DEAD_PROCESS ) //读到wtmp中的登出记录 ,ut_name 为空,ut_type 设为
	{
		for ( int i = 0; i < numuse; i++ )
		{
			if ( strcmp ( tmplogutmp[i].ut_line, utbufp->ut_line ) == 0 && tmplogutmp[i].logintime != 0)
			{
				tmplogutmp[i].logoutime = utbufp->ut_time;
				printf ("%s  %d -- %d\n", tmplogutmp[i].ut_name, tmplogutmp[i].logintime, tmplogutmp[i].logoutime );
				alltime += (long)(tmplogutmp[i].logoutime - tmplogutmp[i].logintime);
				tmplogutmp[i].logintime = 0;
				break;
			}
		}

	}
	if ( strcmp(utbufp->ut_name, "reboot" ) == 0 || strcmp(utbufp->ut_name, "shutdown") == 0 ) //读到wtmp中的关机重启记录,将所有记录的登出时间设为关机重启时间
	{
		for (int i = 0; i < numuse; i++)
		{
			if ( tmplogutmp[i].logintime != 0)
			{
				tmplogutmp[i].logoutime = utbufp->ut_time;
				alltime += (long)(tmplogutmp[i].logoutime - tmplogutmp[i].logintime);
				tmplogutmp[i].logintime = 0;

			}
		}
	}
	return ;
}


int main(int ac, char **av)
{
	struct utmp	*utbufp;		/* read info into here */

	if ( utmp_open( INFOFILE ) == -1 )
	{
		        fprintf(stderr,"%s: cannot open %s\n", *av, UTMP_FILE);
				        exit(1);
	}   

	do
	{
				utbufp = utmp_next();
				countalltime( "houye", utbufp );
	}while(utbufp != ((struct utmp*) NULL));

	utmp_close( );
	
	double t=alltime/3600.0;
	printf ("%f hours\n", t);
	return 0;			/* went ok			*/
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK