/* * 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 * * Copyright (C) 1999 Miquel van Smoorenburg. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include #else #include #endif #include "init.h" #include "initreq.h" #include "paths.h" #if defined(__GLIBC__) # if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0) && defined(__powerpc__) # define HAVE_UPDWTMP 0 # else # define HAVE_UPDWTMP 1 # endif #else # define HAVE_UPDWTMP 0 #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 utmp utmp; struct utsname uname_buf; struct timeval tv; /* * Can't do much if WTMP_FILE is not present or not writable. */ if (access(WTMP_FILE, W_OK) < 0) return; /* * Try to open the wtmp file. Note that we even try * this if we have updwtmp() so we can see if the * wtmp file is accessible. */ if ((fd = open(WTMP_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, "~"); /* * Note if we are going to write a runlevel record. */ if (type == RUN_LVL) wrote_wtmp_rlevel++; /* * See if we need to write a runlevel 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 runlevel record. */ if (wrote_wtmp_rlevel == 0 && type != RUN_LVL) { int runlevel = thislevel; int oldlevel = prevlevel; write_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~"); } #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_name, user, sizeof(utmp.ut_name)); 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_UPDWTMP updwtmp(WTMP_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 utmp utmp; struct utmp tmp; struct utmp *utmptr; struct timeval tv; /* * Can't do much if UTMP_FILE is not present or not writable. */ if (access(UTMP_FILE, W_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 UTMP we write a delayed boot record. */ if (wrote_utmp_reboot == 0 && type != BOOT_TIME) write_utmp("reboot", "~~", 0, BOOT_TIME, "~", NULL); /* * Note if we are going to write a runlevel record. */ if (type == RUN_LVL) wrote_utmp_rlevel++; /* * See if we need to write a runlevel 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 UTMP we write a delayed runlevel record. */ if (wrote_utmp_rlevel == 0 && type != RUN_LVL) { int runlevel = thislevel; int oldlevel = prevlevel; write_utmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~", 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, UT_NAMESIZE); if (line) strncpy(utmp.ut_line, line, UT_LINESIZE); /* * 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. */ setutent(); tmp = utmp; if ((utmptr = getutid(&tmp)) != NULL) { strncpy(utmp.ut_line, utmptr->ut_line, UT_LINESIZE); if (oldline) strncpy(oldline, utmptr->ut_line, UT_LINESIZE); } } /* * Update existing utmp file. */ setutent(); pututline(&utmp); endutent(); } /* * 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. */ { char oldline[UT_LINESIZE]; /* * 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); }