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");
}
可知打印當前用戶名。
(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;
}