$ who man
$ find /usr/include/ -name utmp.h
> /usr/include/x86_64-linux-gnu/bits/utmp.h
$ vi /usr/include/x86_64-linux-gnu/bits/utmp.h
struct utmp
{
short int ut_type; /* Type of login. */
pid_t ut_pid; /* Process ID of login process. */
char ut_line[UT_LINESIZE] /* Devicename. */
char ut_id[4] /* Inittab ID. */
char ut_user[UT_NAMESIZE] /* Username. */
char ut_host[UT_HOSTSIZE /* Hostname for remote login. */
struct exit_status ut_exit; /* Exit status of a process marked as DEAD_PROCESS. */
#if __WORDSIZE_TIME64_COMPAT32
int32_t ut_session; /* Session ID, used for windowing. */
struct
{
int32_t tv_sec; /* Seconds. */
int32_t tv_usec; /* Microseconds. */
} ut_tv; /* Time entry was made. */
#else
long int ut_session; /* Session ID, used for windowing. */
struct timeval ut_tv; /* Time entry was made. */
#endif
int32_t ut_addr_v6[4]; /* Internet address of remote host. */
char
__glibc_reserved[20]; /* Reserved for future use. */
};
open
#include <sys/types.h>
#include <fcntl.h>
int open(const char *path, int flag);
-> return a file descriptor if success, -1 if error

close
#include <unistd.h>
int close(int fd);
-> return 0 if success, -1 if error
read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
-> 실제 읽은 byte 수를 리턴
-> EOF면 0 리턴, 읽기 실패하면 1 리턴
기본형
#include <time.h>
char *ctime(const time_t *timer);
who에서 응용
#include <time.h>
#include <utmp.h>
struct utmp buf;
time_t sec = (time_t) buf.ut_tv.tv_sec;
char *ctime_str = ctime(&sec);
void show_time(long seconds){
time_t sec = (time_t)secondsl
char *cp = ctime(&sec);
printf("%12.12s", cp+4)
}
utmplib.c
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <utmp.h>
#include <unistd.h>
#include <stdlib.h>
#define NRECS 16
#define NULLUT ((struct utmp *)NULL)
#define UTSIZE (sizeof(struct utmp))
static char utmpbuf[NRECS * UTSIZE]; // storage(buffer)
static int num_recs; // num stored
static int cur_rec; // next to go
static int fd_utmp = -1;
int utmp_open(char *filename) {
fd_utmp = open(filename, O_RDONLY);
cur_rec = 0;
num_recs = 0;
return fd_utmp;
}
int utmp_reload(){
int amt_read = read(fd_utmp, &utmpbuf, NRECS * UTSIZE);
if (amt_read == -1){
fprintf(stderr, "Error: can not read from the utmp file");
perror("");
exit(-1);
}
num_recs = amt_read / UTSIZE;
cur_rec = 0; // reset to 0
return num_recs;
}
struct utmp *utmp_next(){
struct utmp *recp = NULLUT;
if (fd_utmp == -1){
return recp;
}
if ((cur_rec == num_recs) && (utmp_reload() == 0)){
return recp;
}
recp = (struct utmp *)(&utmpbuf[cur_rec * UTSIZE]);
cur_rec += 1; // increment the pointer by one
return recp;
}
void utmp_close(){
if (fd_utmp != -1){
close(fd_utmp);
}
}
who.c
#include <stdio.h>
#include <utmp.h>
#include <stdlib.h>
#include <time.h>
extern int utmp_open(char *filename);
extern struct utmp *utmp_next();
extern void utmp_close();
void show_time(long seconds){
time_t sec = (time_t)seconds;
char *cp = ctime(&sec);
printf("%12.12s", cp+4);
}
void show_info(struct utmp *ut_buf_p){
if (ut_buf_p->ut_type != USER_PROCESS)
return;
printf("%-8.8s", ut_buf_p->ut_user);
printf(" ");
printf("%-8.8s", ut_buf_p->ut_line);
printf(" ");
show_time(ut_buf_p->ut_tv.tv_sec);
if (ut_buf_p->ut_host[0] != '\0'){
printf("(%s)", ut_buf_p->ut_host);
}
printf("\n");
}
int main(){
struct utmp *utbufp = NULL;
if (utmp_open("/var/run/utmp") == -1){
perror("/var/run/utmp");
exit(-1);
} // file open
while ((utbufp = utmp_next()) != NULL){
show_info(utbufp);
} // file read
utmp_close();
return 0;
}