/* logwtmp.c - A version of BSDs `logwtmp' that should be widely portable Copyright (C) 1997-2025 Free Software Foundation, Inc. This file is part of GNU Inetutils. GNU Inetutils 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 3 of the License, or (at your option) any later version. GNU Inetutils 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, see `http://www.gnu.org/licenses/'. */ /* Written by Miles Bader. */ /* If `KEEP_OPEN' is defined, then a special version of logwtmp is compiled, called logwtmp_keep_open, which keeps the wtmp file descriptor open between calls, and doesn't attempt to open the file after the first call. */ #include #include #include #include #include #include #include #include #include #ifdef HAVE_UTMPX_H # ifndef __USE_GNU # define __USE_GNU 1 # endif # include # define OUR_WTMP PATH_WTMPX #elif defined HAVE_UTMP_H # include # define OUR_WTMP PATH_WTMP #endif #include #ifdef HAVE_UTMPX_H static void _logwtmp (struct utmpx *ut) #else /* !HAVE_UTMPX_H */ static void _logwtmp (struct utmp *ut) #endif /* !HAVE_UTMP_H */ { #ifdef KEEP_OPEN static int fd = -1; if (fd < 0) fd = open (OUR_WTMP, O_WRONLY | O_APPEND, 0); #else int fd = open (OUR_WTMP, O_WRONLY | O_APPEND, 0); #endif if (fd >= 0) { struct stat st; #ifdef HAVE_FLOCK if (flock (fd, LOCK_EX | LOCK_NB) < 0 && errno != ENOSYS) { sleep (1); flock (fd, LOCK_EX | LOCK_NB); /* ignore error */ } #endif #ifdef HAVE_FTRUNCATE if (fstat (fd, &st) == 0 && write (fd, (char *) ut, sizeof *ut) != sizeof *ut) ftruncate (fd, st.st_size); #else write (fd, (char *) ut, sizeof *ut); #endif #ifdef HAVE_FLOCK flock (fd, LOCK_UN); #endif #ifndef KEEP_OPEN close (fd); #endif } } void #ifdef KEEP_OPEN logwtmp_keep_open (char *line, char *name, char *host) #else logwtmp (char *line, char *name, char *host) #endif { #ifdef HAVE_UTMPX_H struct utmpx ut; struct timeval tv; #else /* !HAVE_UTMPX_H */ struct utmp ut; # ifdef HAVE_STRUCT_UTMP_UT_TV struct timeval tv; # endif #endif /* Set information in new entry. */ memset (&ut, 0, sizeof (ut)); #if defined HAVE_STRUCT_UTMP_UT_TYPE || defined HAVE_STRUCT_UTMPX_UT_TYPE if (name && *name) ut.ut_type = USER_PROCESS; else ut.ut_type = DEAD_PROCESS; #endif /* UT_TYPE */ #if defined HAVE_STRUCT_UTMP_UT_PID || defined HAVE_STRUCT_UTMPX_UT_PID ut.ut_pid = getpid (); #endif /* UT_PID */ strncpy (ut.ut_line, line, sizeof ut.ut_line); #if defined HAVE_STRUCT_UTMP_UT_USER || defined HAVE_STRUCT_UTMPX_UT_USER strncpy (ut.ut_user, name, sizeof ut.ut_user); #elif defined HAVE_STRUCT_UTMP_UT_NAME || defined HAVE_STRUCT_UTMPX_UT_NAME strncpy (ut.ut_name, name, sizeof ut.ut_name); #endif #if defined HAVE_STRUCT_UTMP_UT_HOST || defined HAVE_STRUCT_UTMPX_UT_HOST strncpy (ut.ut_host, host, sizeof ut.ut_host); # ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN /* Only utmpx. */ if (strlen (host) < sizeof (ut.ut_host)) ut.ut_syslen = strlen (host) + 1; /* Including NUL. */ else { ut.ut_host[sizeof (ut.ut_host) - 1] = '\0'; ut.ut_syslen = sizeof (ut.ut_host); } # endif/* UT_SYSLEN */ #endif /* UT_HOST */ #if defined HAVE_STRUCT_UTMP_UT_TV || defined HAVE_STRUCT_UTMPX_UT_TV gettimeofday (&tv, NULL); ut.ut_tv.tv_sec = tv.tv_sec; ut.ut_tv.tv_usec = tv.tv_usec; #else time (&ut.ut_time); #endif _logwtmp (&ut); }