您的位置:首页 > 运维架构 > Linux

unix/linux who命令的实现

2017-03-07 14:35 489 查看
Understanding Unix/Linux Programming(Unix/Linux编程实践教程)
学习模式:
(1)它能做什么?
(2)它是如何实现的?
(3)能不能自己编写一个?
(实验环境:gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) )

who命令的学习

(1) who命令能做什么? 



(2)如何实现的?

         联机帮助告诉我们,who命令通过读取utmp这个文件以实现对应的功能。utmp这个结构包含了我们需要的who所需要的全部信息,除此之外还提供了其他信息。

命令输入: man 5 utmp



输入命令:cat /usr/include/utmp.h

可知道_UTMP_FILE保存了用户登录的信息。



(3)编码实现

#include<stdio.h>
#include<stdlib.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>

#define SHOWHOST /*include remote machine on output*/
void show_info(struct utmp* utbufp)
{
printf("%-8.8s ",utbufp->ut_name); /*thie logname */
printf("%-8.8s ",utbufp->ut_line); /*the logtty*/
printf("%10ld ",utbufp->ut_time); /*the logtime*/

#ifdef SHOWHOST
printf("s",utbufp->ut_host);  /*the host*/
#endif
printf("\n");
}

int main()
{
struct utmp current_record; /*read info into here*/
int    utmpfd;              /*read from the descriptor*/
int    reclen  = sizeof(current_record);

//if((utmpfd = open("UTMP_FILE",O_RDONLY)) == -1)
if((utmpfd = open(UTMP_FILE,O_RDONLY)) == -1)
{
perror(UTMP_FILE);       /* UTMP_FILE is in utmp.h  ,  #define UTMP_FILE  _PATH_UTMP
/*#define _PATH_UTMP      "/var/run/utmp"*/
exit(1);
}

while(read(utmpfd,¤t_record,reclen) == reclen)
show_info(¤t_record);
close(utmpfd);
return 0;
}
运行结果:可知跟我们shell提供的命令打印不太一样。



完善:

(1) 清除空白记录(通过判断用户是否在线即可)

同样可通过命令:man 5 utmp



(2)时间格式化打印(使用系统调用将long int转为ASCII 打印输出)

通过联机查询步骤:

1.man -k time | grep transform

2.man 3 ctime

代码完善实现如下:

#include<stdio.h>
#include<stdlib.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<time.h>
#define SHOWHOST /*include remote machine on output*/
void showtime(long timeval)
{
char* cp;
cp = ctime(&timeval);
printf("%12.12s",cp+4);
}
void show_info(struct utmp* utbufp)
{
/*USER_PROCESS indicate the user is active or not*/
if(utbufp->ut_type!= USER_PROCESS)
return ;

printf("%-8.8s ",utbufp->ut_name); /*thie logname */
printf("%-8.8s ",utbufp->ut_line); /*the logtty*/
showtime(utbufp->ut_time);
#ifdef SHOWHOST
if(utbufp->ut_host[0] != '\0')
printf("s",utbufp->ut_host);  /*the host*/
#endif
printf("\n");
}

int main()
{
struct utmp current_record; /*read info into here*/
int    utmpfd;              /*read from the descriptor*/
int    reclen  = sizeof(current_record);

//if((utmpfd = open("UTMP_FILE",O_RDONLY)) == -1)
if((utmpfd = open(UTMP_FILE,O_RDONLY)) == -1)
{
perror(UTMP_FILE);  /* UTMP_FILE is in utmp.h  ,  #define UTMP_FILE  _PATH_UTMP
/*#define _PATH_UTMP      "/var/run/utmp"*/
exit(1);
}

while(read(utmpfd,¤t_record,reclen) == reclen)
show_info(¤t_record);
close(utmpfd);
return 0;
}



还记得前面那三个问题吗?这里增加一个问题,如何使程序的运行更加高效呢?





代码实现:

utmplib.h

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<utmp.h>

#define NRECS 16
#define NULLUT ((struct utmp*) NULL)
#define UTSIZE (sizeof(struct utmp))

static char utmpbuf[NRECS* UTSIZE]; /*storage*/
static int  num_recs;               /*num stored*/
static int  cur_rec;				/*next to go */
static int  fd_utmp = -1;  			/*read from*/

int utmp_open(char* filename)
{
fd_utmp = open(filename,O_RDONLY);
cur_rec = num_recs = 0;
return fd_utmp;
}
int utmp_reload()
/*read next bunch of records into buffer*/
{
int amt_read;
amt_read = read(fd_utmp,utmpbuf,NRECS*UTSIZE);
num_recs = amt_read/UTSIZE;
cur_rec = 0;
return num_recs;
}
struct utmp* utmp_next()
{
struct utmp* recp;
if(fd_utmp == -1)
return NULLUT;
if(cur_rec == num_recs && utmp_reload() == 0)
return NULLUT;
recp = (struct utmp* )&utmpbuf[cur_rec * UTSIZE];
cur_rec ++;
return recp;
}
void utmp_close()
{
if(fd_utmp!=-1)
close(fd_utmp);
}


who3.c

#include<stdio.h>
#include<stdlib.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<time.h>
#include"utmplib.h"
#define SHOWHOST /*include remote machine on output*/
void showtime(long timeval)
{
char* cp;
cp = ctime(&timeval);
printf("%12.12s",cp+4);
}
void show_info(struct utmp* utbufp)
{
/*USER_PROCESS indicate the user is active or not*/
if(utbufp->ut_type!= USER_PROCESS)
return ;

printf("%-8.8s ",utbufp->ut_name); /*this logname */
printf("%-8.8s ",utbufp->ut_line); /*the logtty*/
showtime(utbufp->ut_time);
#ifdef SHOWHOST
if(utbufp->ut_host[0] != '\0')
printf("s",utbufp->ut_host);  /*the host*/
#endif
printf("\n");
}

int main()
{
struct utmp *utbufp; /*read info into here*/
int    utmpfd;              /*read from the descriptor*/
if(utmp_open(UTMP_FILE) == -1)
{
perror(UTMP_FILE);
exit(1);
}
while((utbufp =utmp_next()) != ((struct utmp*)NULL))
{
show_info(utbufp);
}
utmp_close();
return 0;
}




(1)who am i 能做什么?



用户当前使用的相关终端设备。

(2)如何实现?

我们可以在who2的基础上进行筛选出用户名相关终端设备的信息。

问题在于如何获取用户名相关的当前终端设备??



(3)代码实现

#include<stdio.h>
#include<unistd.h>
#include<utmp.h>
#include<fcntl.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
void showtime(long);
void show_info(struct utmp*);
char* whats_my_line(int);

int main(int argc,char* argv[])
{
if(argc!=3)
{
printf("argument need : who am i");
exit(1);
}
struct utmp utbuf; //read info into here
int utmpfd; // read from this descriptor
char* myline = NULL;

myline = whats_my_line(0);// get the device name of tty
if((utmpfd = open(UTMP_FILE,O_RDONLY)) == -1)
{
perror(UTMP_FILE);
exit(1);
}
while(read(utmpfd,&utbuf,sizeof(utbuf)) == sizeof(utbuf))
{
if(myline == NULL || strcmp(utbuf.ut_line,myline) == 0)
show_info(&utbuf);
}
close(utmpfd);
return 0;
}
char* whats_my_line(int fd)
{
char *rv;
rv = ttyname(fd);
//puts(rv); //debug print: dev/pts/6
if(rv)
if(strncmp(rv,"/dev/",5) == 0)
return rv+5;
return rv;
// return pts/6
}
void showtime(long timeval)
{
char* cp;
cp = ctime(&timeval);
printf("%12.12s",cp + 4);
}
void show_info(struct utmp* utbufp)
{
if(utbufp->ut_type != USER_PROCESS) //online
return ;
printf("%-8.8s ",utbufp->ut_name);
printf("%-8.8s ",utbufp->ut_line);
showtime(utbufp->ut_time);
#ifdef SHOWHOST
if(utbufp->host[0] != '\0')
printf(" (%s) ",utbuf->ut_host);
#endif
printf("\n");
}



(1)whoami能做什么?



可知打印当前用户名。

(2)如何实现的??

通过联机帮助:man 2 geteuid, 可以通过获取当前用户id,通过使用getpwuid函数对应id找到用户所对应的信息,这些信息包括用户名。





cat /usr/include/pwd.h



(3)代码实现#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pwd.h>
#include<sys/types.h>

int main()
{
uid_t id; //effective user id of process
struct passwd* p; // will hold pwd data for user
id = geteuid(); //manpage says geteuid always succeeds
p = getpwuid(id);

if(p == NULL)
printf("I don't know thow you are \n");
else
printf("%s\n",p->pw_name);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: