| /* |
| * utmp.c Routines to read/write the utmp and wtmp files. |
| * Basically just wrappers around the library routines. |
| * |
| * Version: @(#)utmp.c 2.77 09-Jun-1999 miquels@cistron.nl |
| * |
| */ |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/ioctl.h> |
| #include <sys/utsname.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <stdio.h> |
| #include <time.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <utmpx.h> |
| |
| #include "init.h" |
| #include "initreq.h" |
| #include "paths.h" |
| |
| |
| #if defined(__GLIBC__) |
| # if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0) && defined(__powerpc__) |
| # define HAVE_UPDWTMPX 0 |
| # else |
| # define HAVE_UPDWTMPX 1 |
| # endif |
| #else |
| # define HAVE_UPDWTMPX 0 |
| #endif |
| |
| #ifndef WTMPX_FILE |
| #if defined _WTMPX_FILE |
| #define WTMPX_FILE _WTMPX_FILE |
| #elif defined _PATH_WTMPX |
| #define WTMPX_FILE _PATH_WTMPX |
| #elif defined _PATH_WTMP |
| #define WTMPX_FILE _PATH_WTMP |
| #else |
| #define WTMPX_FILE "/var/log/wtmpx" |
| #endif |
| #endif |
| |
| #if !defined ut_time && !defined __CYGWIN__ |
| #define ut_time ut_tv.tv_sec |
| #endif |
| |
| |
| /* |
| * Log an event in the wtmp file (reboot, runlevel) |
| */ |
| void write_wtmp( |
| char *user, /* name of user */ |
| char *id, /* inittab ID */ |
| int pid, /* PID of process */ |
| int type, /* TYPE of entry */ |
| char *line) /* Which line is this */ |
| { |
| int fd; |
| struct utmpx utmp; |
| struct utsname uname_buf; |
| struct timeval tv; |
| |
| /* |
| * Try to open the wtmp file. Note that we even try |
| * this if we have updwtmpx() so we can see if the |
| * wtmp file is accessible. |
| */ |
| if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND)) < 0) return; |
| |
| #ifdef INIT_MAIN |
| /* |
| * Note if we are going to write a boot record. |
| */ |
| if (type == BOOT_TIME) wrote_wtmp_reboot++; |
| |
| /* |
| * See if we need to write a reboot record. The reason that |
| * we are being so paranoid is that when we first tried to |
| * write the reboot record, /var was possibly not mounted |
| * yet. As soon as we can open WTMP we write a delayed boot record. |
| */ |
| if (wrote_wtmp_reboot == 0 && type != BOOT_TIME) |
| write_wtmp("reboot", "~~", 0, BOOT_TIME, "~"); |
| #endif |
| |
| /* |
| * Zero the fields and enter new fields. |
| */ |
| memset(&utmp, 0, sizeof(utmp)); |
| #if defined(__GLIBC__) |
| gettimeofday(&tv, NULL); |
| utmp.ut_tv.tv_sec = tv.tv_sec; |
| utmp.ut_tv.tv_usec = tv.tv_usec; |
| #else |
| time(&utmp.ut_time); |
| #endif |
| utmp.ut_pid = pid; |
| utmp.ut_type = type; |
| strncpy(utmp.ut_user, user, sizeof(utmp.ut_user)); |
| strncpy(utmp.ut_id , id , sizeof(utmp.ut_id )); |
| strncpy(utmp.ut_line, line, sizeof(utmp.ut_line)); |
| |
| /* Put the OS version in place of the hostname */ |
| if (uname(&uname_buf) == 0) |
| strncpy(utmp.ut_host, uname_buf.release, sizeof(utmp.ut_host)); |
| |
| #if HAVE_UPDWTMPX |
| updwtmpx(WTMPX_FILE, &utmp); |
| #else |
| write(fd, (char *)&utmp, sizeof(utmp)); |
| #endif |
| close(fd); |
| } |
| |
| /* |
| * Write an entry to the UTMP file. For DEAD_PROCESS, put |
| * the previous ut_line into oldline if oldline != NULL. |
| */ |
| static void write_utmp( |
| char *user, /* name of user */ |
| char *id, /* inittab ID */ |
| int pid, /* PID of process */ |
| int type, /* TYPE of entry */ |
| char *line, /* LINE if used. */ |
| char *oldline) /* Line of old utmp entry. */ |
| { |
| struct utmpx utmp; |
| struct utmpx tmp; |
| struct utmpx *utmptr; |
| struct timeval tv; |
| |
| /* |
| * Can't do much if UTMPX_FILE is not present. |
| */ |
| if (access(UTMPX_FILE, F_OK) < 0) |
| return; |
| |
| #ifdef INIT_MAIN |
| /* |
| * Note if we are going to write a boot record. |
| */ |
| if (type == BOOT_TIME) wrote_utmp_reboot++; |
| |
| /* |
| * See if we need to write a reboot record. The reason that |
| * we are being so paranoid is that when we first tried to |
| * write the reboot record, /var was possibly not mounted |
| * yet. As soon as we can open WTMP we write a delayed boot record. |
| */ |
| if (wrote_utmp_reboot == 0 && type != BOOT_TIME) |
| write_utmp("reboot", "~~", 0, BOOT_TIME, "~", NULL); |
| #endif |
| |
| /* |
| * Fill out an utmp struct. |
| */ |
| memset(&utmp, 0, sizeof(utmp)); |
| utmp.ut_type = type; |
| utmp.ut_pid = pid; |
| strncpy(utmp.ut_id, id, sizeof(utmp.ut_id)); |
| #if defined(__GLIBC__) |
| gettimeofday(&tv, NULL); |
| utmp.ut_tv.tv_sec = tv.tv_sec; |
| utmp.ut_tv.tv_usec = tv.tv_usec; |
| #else |
| time(&utmp.ut_time); |
| #endif |
| strncpy(utmp.ut_user, user, sizeof utmp.ut_user); |
| if (line) strncpy(utmp.ut_line, line, sizeof utmp.ut_line); |
| |
| /* |
| * We might need to find the existing entry first, to |
| * find the tty of the process (for wtmp accounting). |
| */ |
| if (type == DEAD_PROCESS) { |
| /* |
| * Find existing entry for the tty line. |
| */ |
| setutxent(); |
| tmp = utmp; |
| if ((utmptr = getutxid(&tmp)) != NULL) { |
| strncpy(utmp.ut_line, utmptr->ut_line, sizeof utmptr->ut_line); |
| if (oldline) |
| strncpy(oldline, utmptr->ut_line, sizeof utmptr->ut_line); |
| } |
| } |
| |
| /* |
| * Update existing utmp file. |
| */ |
| setutxent(); |
| pututxline(&utmp); |
| endutxent(); |
| } |
| |
| /* |
| * Write a record to both utmp and wtmp. |
| */ |
| void write_utmp_wtmp( |
| char *user, /* name of user */ |
| char *id, /* inittab ID */ |
| int pid, /* PID of process */ |
| int type, /* TYPE of entry */ |
| char *line) /* LINE if used. */ |
| { |
| struct utmpx tmp; |
| char oldline[sizeof tmp.ut_line]; |
| |
| /* |
| * For backwards compatibility we just return |
| * if user == NULL (means : clean up utmp file). |
| */ |
| if (user == NULL) |
| return; |
| |
| oldline[0] = 0; |
| write_utmp(user, id, pid, type, line, oldline); |
| write_wtmp(user, id, pid, type, line && line[0] ? line : oldline); |
| } |
| |