linux系统编程:自己动手写一个who命令
2018-01-08 16:52
549 查看
who命令的作用用于显示当前有哪些用户登录到系统。
这个命令执行的原理是读取了系统上utmp文件中记录的所有登录信息,直接显示出来的
当我指定file参数为/var/run/utmp或者省略这个参数的时候,结果都是一样, 当我用一个错误的文件时,没有任何结果,从这里可以推断,who命令确实从/var/run/utmp中读取用户登录的信息
那么utmp到底在哪里?
利用man -k utmp 查找所有的可能: 推断---> utmp (5) - login records 这里的可能性比较大,描述说,这里是记录登录信息的
接下来,我们去 man 5 utmp 看下,会发现有这么一段提示:
意思是utmp文件的信息是一系列utmp结构体数据, 这个结构体定义在utmp.h文件中, 每个linux发行版可能不一样.
接下来,我用强大的find命令查找到了2个目标:
结构体的定义就在这个文件中( /usr/include/x86_64-linux-gnu/bits/utmp.h )
这里有两个宏要注意下( ut_time和UTMP_FILE ), 下面的程序会用到
UTMP_FILE的查找思路: 首先grep两个目录下面的文件utmp.h,在/usr/include/utmp.h找到一个宏定义 _PATH_UTMP,下一步就是确定 _PATH_UTMP到底是什么,利用grep "_PATH_UTMP" /usr/include/*.h
最终在paths.h头文件中,发现了他的真面目
2)格式化4个信息:用户名,主机,地址,时间
3)只打印当前活动的用户(当前登录的用户)
4)格式化时间( 小时,分钟,秒, >10的补0, <10的原样返回 )
源代码
View Code
总结:
一个非常小的功能,囊括以下知识点:
1)文件读取
2)man手册与系统命令使用技巧
3)指针用法
4)字符串函数用法
5)时间函数用法
6)宏与typedef的用法
这个命令执行的原理是读取了系统上utmp文件中记录的所有登录信息,直接显示出来的
utmp文件在哪里呢?
man who的时候,在手册下面有这么一段说明:意思就是不指定文件参数,那么读取的就是/var/run/utmp,到底是不是,验证下If FILE is not specified, use /var/run/utmp. /var/log/wtmp as FILE is common. If ARG1 ARG2 given, -m presumed: 'am i' or 'mom likes' are usual.
当我指定file参数为/var/run/utmp或者省略这个参数的时候,结果都是一样, 当我用一个错误的文件时,没有任何结果,从这里可以推断,who命令确实从/var/run/utmp中读取用户登录的信息
ghostwu@ubuntu:~$ who ghostwu tty7 2018-01-08 09:09 (:0) ghostwu pts/18 2018-01-08 12:59 (:0) ghostwu pts/19 2018-01-08 13:00 (:0) ghostwu pts/20 2018-01-08 13:03 (:0) ghostwu@ubuntu:~$ who -b system boot 2018-01-08 09:08 ghostwu@ubuntu:~$ who -b /var/run/utmp system boot 2018-01-08 09:08 ghostwu@ubuntu:~$ who -b /var/run/utmp2 ghostwu@ubuntu:~$ who -b /var/run/utmp3
那么utmp到底在哪里?
利用man -k utmp 查找所有的可能: 推断---> utmp (5) - login records 这里的可能性比较大,描述说,这里是记录登录信息的
ghostwu@ubuntu:~$ man -k utmp endutent (3) - access utmp file entries endutxent (3) - access utmp file entries getutent (3) - access utmp file entries getutent_r (3) - access utmp file entries getutid (3) - access utmp file entries getutid_r (3) - access utmp file entries getutline (3) - access utmp file entries getutline_r (3) - access utmp file entries getutmp (3) - copy utmp structure to utmpx, and vice versa getutmpx (3) - copy utmp structure to utmpx, and vice versa getutxent (3) - access utmp file entries getutxid (3) - access utmp file entries getutxline (3) - access utmp file entries login (3) - write utmp and wtmp entries logout (3) - write utmp and wtmp entries pututline (3) - access utmp file entries pututxline (3) - access utmp file entries sessreg (1) - manage utmpx/wtmpx entries for non-init clients setutent (3) - access utmp file entries setutxent (3) - access utmp file entries systemd-update-utmp (8) - Write audit and utmp updates at bootup, runlevel ch... systemd-update-utmp-runlevel.service (8) - Write audit and utmp updates at bo... systemd-update-utmp.service (8) - Write audit and utmp updates at bootup, run... utmp (5) - login records utmpdump (1) - dump UTMP and WTMP files in raw format utmpname (3) - access utmp file entries utmpx (5) - login records utmpxname (3) - access utmp file entries
接下来,我们去 man 5 utmp 看下,会发现有这么一段提示:
The file is a sequence of utmp structures, declared as follows in <utmp.h> (note that this is only one of several definitions around; details depend on the version of libc):
意思是utmp文件的信息是一系列utmp结构体数据, 这个结构体定义在utmp.h文件中, 每个linux发行版可能不一样.
接下来,我用强大的find命令查找到了2个目标:
ghostwu@ubuntu:~$ find /usr/include -name "utmp.h" /usr/include/x86_64-linux-gnu/bits/utmp.h /usr/include/utmp.h
结构体的定义就在这个文件中( /usr/include/x86_64-linux-gnu/bits/utmp.h )
这里有两个宏要注意下( ut_time和UTMP_FILE ), 下面的程序会用到
#ifndef _NO_UT_TIME /* We have a problem here: `ut_time' is also used otherwise. Define _NO_UT_TIME if the compiler complains. */ # define ut_time ut_tv.tv_sec #endif
ghostwu@ubuntu:~$ grep "UTMP_FILE" /usr/include/utmp.h #define UTMP_FILE _PATH_UTMP #define UTMP_FILENAME _PATH_UTMP ghostwu@ubuntu:~$ grep "_PATH_UTMP" /usr/include/utmp.h #define UTMP_FILE _PATH_UTMP #define UTMP_FILENAME _PATH_UTMP ghostwu@ubuntu:~$ grep "_PATH_UTMP" /usr/include/x86_64-linux-gnu/bits/utmp.h ghostwu@ubuntu:~$ grep "_PATH_UTMP" /usr/include/*.h /usr/include/paths.h:#define _PATH_UTMP "/var/run/utmp" /usr/include/utmp.h:#define UTMP_FILE _PATH_UTMP /usr/include/utmp.h:#define UTMP_FILENAME _PATH_UTMP /usr/include/utmpx.h:# define UTMPX_FILE _PATH_UTMPX /usr/include/utmpx.h:# define UTMPX_FILENAME _PATH_UTMPX ghostwu@ubuntu:~$
UTMP_FILE的查找思路: 首先grep两个目录下面的文件utmp.h,在/usr/include/utmp.h找到一个宏定义 _PATH_UTMP,下一步就是确定 _PATH_UTMP到底是什么,利用grep "_PATH_UTMP" /usr/include/*.h
最终在paths.h头文件中,发现了他的真面目
who命令书写思路:
1)从/var/run/utmp读取文件,每次读取一个struct utmp结构体这么大,如果长度每次都有这么大,继续读取2)格式化4个信息:用户名,主机,地址,时间
3)只打印当前活动的用户(当前登录的用户)
4)格式化时间( 小时,分钟,秒, >10的补0, <10的原样返回 )
源代码
/*================================================================ * Copyright (C) 2018 . All rights reserved. * * 文件名称:mywho.c * 创 建 者:ghostwu(吴华) * 创建日期:2018年01月08日 * 描 述: * ================================================================*/ #include <stdio.h> #include <utmp.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <string.h> #ifndef UTMP_FILE #define UTMP_FILE "/var/run/utmp" #endif int count = 0; //格式化时间, <10 就补0, >10 原样返回 char* format_time( char* s, const char *time ) { if( strlen( time ) < 2 ) { return strcat( s, time ); } return strcpy( s, time ); } void show_info( struct utmp* t_utmp ) { if ( t_utmp->ut_type != USER_PROCESS ) //不显示 非活跃的用户信息 return; printf( "%-8.8s", t_utmp->ut_user ); printf( " " ); printf( "%-8.8s", t_utmp->ut_line ); printf( " " ); //printf( " " ); //printf( "%12.12s", ctime( (time_t*)&(t_utmp->ut_time) ) + 4 ); //+4--->去除天(day)和后面的空格 /*测试localtime用法 //当前时间 time_t now; struct tm* pNow; time( &now ); pNow = localtime( &now ); printf( "%d-%d-%d %d:%d", pNow->tm_year + 1900, pNow->tm_mon + 1, pNow->tm_mday, pNow->tm_hour, pNow->tm_min ); */ struct tm* ptm; time_t u_time = t_utmp->ut_time; ptm = localtime( &u_time ); int ihour = ptm->tm_hour; int imin = ptm->tm_min; char hour[3] = "0"; char hour2[3] = "0"; sprintf( hour2, "%d", ihour ); format_time( hour, hour2 ); char min[3] = "0"; char min2[3] = "0"; sprintf( min2, "%d", imin ); format_time( min, min2 ); //printf( "%d-%d-%d %d:%d", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ihour, imin ); printf( "%d-%d-%d %s:%s", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, hour, min ); printf( " " ); printf( "%-8.8s", t_utmp->ut_host ); printf( "\n" ); } int main(int argc, char *argv[]) { struct utmp myutmp; int fd = -1; int reclen = sizeof( myutmp ); fd = open( UTMP_FILE, O_RDONLY ); if( -1 == fd ) { perror( "open utmp" ); exit( -1 ); } //printf( "fd = %d\n", fd ); while( read( fd, &myutmp, reclen ) == reclen ) { count++; show_info( &myutmp ); } printf( "文件读取的次数:%d\n", count ); close( fd ); return 0; }
View Code
总结:
一个非常小的功能,囊括以下知识点:
1)文件读取
2)man手册与系统命令使用技巧
3)指针用法
4)字符串函数用法
5)时间函数用法
6)宏与typedef的用法
相关文章推荐
- linux系统编程:自己动手写一个cp命令
- 自己动手编写一个简单的who命令(不带参数)
- 自己动手编写一个简单的who命令(不带参数)
- 自己动手制作(DIY)一个Mini-Linux系统
- Linux_自己编写一个who命令
- DIY:自己动手做一个迷你 Linux 系统
- 自己动手做一个迷你 Linux 系统
- 自己动手做一个迷你Linux 系统
- Linux内核高危漏洞,一个命令可以***所有Linux系统
- 一个命令可以攻击所有的Linux系统
- DIY:自己动手做一个迷你 Linux 系统
- 在Android系统中修改Android.mk使其同时编译rgb2565和rgb2888(向out/host/linux-x86/bin/下新增加一个工具命令)
- 音频视频编程相关:GStreamer/ffmpeg/directshow/vfw linux和window下几种流行的音频视频编程框架作一个总结,防止自己迷惘,免于晕头转向。
- DIY:自己动手做一个迷你 Linux 系统
- (转载) 使用 Linux 系统调用的内核命令, 探究 SCI(systen call interface) 并添加自己的调用.
- 黑客再爆Linux内核高危漏洞 一个命令可以攻击所有Linux系统
- 作为一个linux系统运维师必须掌握的定期任务执行命令cront
- 自己动手做一个迷你 Linux 系统
- 在Android系统中修改Android.mk使其同时编译rgb2565和rgb2888(向out/host/linux-x86/bin/下新增加一个工具命令)
- 使用 Linux 系统调用的内核命令--探究 SCI 并添加自己的调用