# if READUTMP_USE_SYSTEMD
/* Use systemd and Linux /proc and kernel APIs. */
-static struct timeval
+static struct timespec
get_boot_time_uncached (void)
{
/* /proc/uptime contains the uptime with a resolution of 0.01 sec. */
double uptime = strtod (buf, &endptr);
if (endptr > buf)
{
- struct timeval result;
- if (gettimeofday (&result, NULL) >= 0)
+ struct timespec result;
+ if (0 <= timespec_get (&result, TIME_UTC))
{
- long uptime_sec = (long) uptime;
- int uptime_usec =
- (int) ((uptime - (double) uptime_sec) * 1000000.0 + 0.5);
- if (result.tv_usec < uptime_usec)
+ time_t uptime_sec = uptime;
+ struct timespec up =
{
- result.tv_usec += 1000000;
+ .tv_sec = uptime_sec,
+ .tv_nsec = (uptime - uptime_sec) * 1e9 + 0.5
+ };
+ if (result.tv_nsec < up.tv_nsec)
+ {
+ result.tv_nsec += 1000000000;
result.tv_sec -= 1;
}
- result.tv_sec -= uptime_sec;
- result.tv_usec -= uptime_usec;
+ result.tv_sec -= up.tv_sec;
+ result.tv_nsec -= up.tv_nsec;
return result;
}
}
struct sysinfo info;
if (sysinfo (&info) >= 0)
{
- struct timeval result;
- if (gettimeofday (&result, NULL) >= 0)
+ struct timespec result;
+ if (0 <= timespec_get (&result, TIME_UTC))
{
result.tv_sec -= info.uptime;
return result;
}
/* We shouldn't get here. */
- return (struct timeval) { .tv_sec = 0, .tv_usec = 0 };
+ return (struct timespec) {0};
}
-static struct timeval
+static struct timespec
get_boot_time (void)
{
- static int cached;
- static struct timeval boot_time;
+ static bool cached;
+ static struct timespec boot_time;
if (!cached)
{
+ cached = true;
boot_time = get_boot_time_uncached ();
- cached = 1;
}
return boot_time;
}
static struct utmp_alloc
add_utmp (struct utmp_alloc a, int options,
char const *user, char const *id, char const *line, pid_t pid,
- short type, struct timeval t, char const *host, long session)
+ short type, struct timespec ts, char const *host, long session)
{
if (!user) user = "";
if (!host) host = "";
ut->ut_user = p = memcpy (p - usersize, user, usersize);
ut->ut_id = p = memcpy (p - idsize, id, idsize);
ut->ut_line = p = memcpy (p - linesize, line, linesize);
- ut->ut_pid = pid;
- ut->ut_type = type;
- ut->ut_tv = t;
ut->ut_host = memcpy (p - hostsize, line, hostsize);
+ ut->ut_ts = ts;
+ ut->ut_pid = pid;
ut->ut_session = session;
+ ut->ut_type = type;
if (desirable_utmp_entry (ut, options))
{
/* Now that UT has been checked, relocate its string slots to be
uint64_t start_usec;
if (sd_session_get_start_time (session, &start_usec) < 0)
start_usec = 0;
- struct timeval start_tv;
- start_tv.tv_sec = start_usec / 1000000;
- start_tv.tv_usec = start_usec % 1000000;
+ struct timespec start_ts;
+ start_ts.tv_sec = start_usec / 1000000;
+ start_ts.tv_nsec = start_usec % 1000000 * 1000;
char *seat;
if (sd_session_get_seat (session, &seat) < 0)
if (sd_session_get_service (session, &service) < 0)
service = NULL;
- char *pty;
uid_t uid;
- if (sd_session_get_uid (session, &uid) >= 0)
- {
- struct timespec start_ts =
- {
- .tv_sec = start_tv.tv_sec,
- .tv_nsec = start_tv.tv_usec * 1000
- };
- pty = guess_pty_name (uid, start_ts);
- }
- else
- pty = NULL;
+ char *pty = (sd_session_get_uid (session, &uid) < 0 ? NULL
+ : guess_pty_name (uid, start_ts));
if (service != NULL && pty != NULL)
{
if (seat != NULL)
a = add_utmp (a, options, user, session, seat,
leader_pid /* the best we have */,
- USER_PROCESS, start_tv, host, leader_pid);
+ USER_PROCESS, start_ts, host, leader_pid);
if (tty != NULL)
a = add_utmp (a, options, user, session, tty,
leader_pid /* the best we have */,
- USER_PROCESS, start_tv, host, leader_pid);
+ USER_PROCESS, start_ts, host, leader_pid);
free (host);
free (user);
#include <stdlib.h>
#include <sys/types.h>
+#include <time.h>
/* AIX 4.3.3 has both utmp.h and utmpx.h, but only struct utmp
has the ut_exit member. */
# undef HAVE_UTMPX_H
#endif
-#if READUTMP_USE_SYSTEMD
+/* HPUX 10.20 needs utmp.h, for the definition of e.g., UTMP_FILE. */
+#if HAVE_UTMP_H
+# include <utmp.h>
+#endif
-/* Get 'struct timeval'. */
-# include <sys/time.h>
+/* Needed for BOOT_TIME and USER_PROCESS. */
+#if HAVE_UTMPX_H
+# if defined _THREAD_SAFE && defined UTMP_DATA_INIT
+ /* When including both utmp.h and utmpx.h on AIX 4.3, with _THREAD_SAFE
+ defined, work around the duplicate struct utmp_data declaration. */
+# define utmp_data gl_aix_4_3_workaround_utmp_data
+# endif
+# include <utmpx.h>
+#endif
+
+#if READUTMP_USE_SYSTEMD || ! (HAVE_UTMPX_H || HAVE_UTMP_H)
-/* Type for the entries returned by read_utmp. */
struct gl_utmp
{
/* All 'char *' here are of arbitrary length and malloc-allocated. */
char *ut_user; /* User name */
char *ut_id; /* Session ID */
char *ut_line; /* seat / device */
+ char *ut_host; /* for remote sessions: user@host or host */
+ struct timespec ut_ts; /* time */
pid_t ut_pid; /* process ID of ? */
+ pid_t ut_session; /* process ID of session leader */
short ut_type; /* BOOT_TIME or USER_PROCESS */
- struct timeval ut_tv; /* time */
- char *ut_host; /* for remote sessions: user@host or host */
- long ut_session; /* process ID of session leader */
};
-/* Get values for ut_type: BOOT_TIME, USER_PROCESS. */
-# include <utmpx.h>
-
+# define HAVE_GL_UTMP 1
# define UTMP_STRUCT_NAME gl_utmp
-# define UT_TIME_MEMBER(UT) ((UT)->ut_tv.tv_sec)
+# define UT_TIME_MEMBER(UT) ((UT)->ut_ts.tv_sec)
# define UT_EXIT_E_TERMINATION(UT) 0
# define UT_EXIT_E_EXIT(UT) 0
⎣ ut_ss struct sockaddr_storage NetBSD, Minix
*/
-# if HAVE_UTMP_H
- /* HPUX 10.20 needs utmp.h, for the definition of e.g., UTMP_FILE. */
-# include <utmp.h>
-# endif
-# if defined _THREAD_SAFE && defined UTMP_DATA_INIT
- /* When including both utmp.h and utmpx.h on AIX 4.3, with _THREAD_SAFE
- defined, work around the duplicate struct utmp_data declaration. */
-# define utmp_data gl_aix_4_3_workaround_utmp_data
-# endif
-# include <utmpx.h>
# define UTMP_STRUCT_NAME utmpx
# define UT_TIME_MEMBER(UT) ((UT)->ut_tv.tv_sec)
# define SET_UTMP_ENT setutxent
⎣ ut_addr_v6 [u]int[4] glibc, musl, Android
*/
-# include <utmp.h>
# if !HAVE_DECL_GETUTENT
struct utmp *getutent (void);
# endif
# define UTMP_STRUCT_NAME utmp
-# define UT_TIME_MEMBER(UT) ((UT)->ut_time)
+# define UT_TIME_MEMBER(UT) ((UT)->ut_ts.tv_sec)
# define SET_UTMP_ENT setutent
# define GET_UTMP_ENT getutent
# define END_UTMP_ENT endutent
# define UT_EXIT_E_EXIT(UT) 0
# endif
-#else
-
-/* Provide a dummy fallback. */
-
-/* Get 'struct timeval'. */
-# include <sys/time.h>
-
-struct gl_utmp
-{
- char ut_user[1];
- char ut_line[1];
- struct timeval ut_tv;
-};
-# define UTMP_STRUCT_NAME gl_utmp
-# define UT_TIME_MEMBER(UT) ((UT)->ut_tv.tv_sec)
-# define UT_EXIT_E_TERMINATION(UT) 0
-# define UT_EXIT_E_EXIT(UT) 0
-
#endif
/* Accessor macro for the member named ut_user or ut_name. */
-#if READUTMP_USE_SYSTEMD
-
-# define UT_USER(UT) ((UT)->ut_user)
-
-#elif HAVE_UTMPX_H
-
-# if HAVE_STRUCT_UTMPX_UT_USER
-# define UT_USER(UT) ((UT)->ut_user)
-# endif
-# if HAVE_STRUCT_UTMPX_UT_NAME
-# undef UT_USER
-# define UT_USER(UT) ((UT)->ut_name)
-# endif
-
-#elif HAVE_UTMP_H
-
-# if HAVE_STRUCT_UTMP_UT_USER
-# define UT_USER(UT) ((UT)->ut_user)
-# endif
-# if HAVE_STRUCT_UTMP_UT_NAME
-# undef UT_USER
-# define UT_USER(UT) ((UT)->ut_name)
-# endif
-
-#else /* dummy fallback */
-
+#if (!HAVE_GL_UTMP \
+ && (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_NAME \
+ : HAVE_UTMP_H && HAVE_STRUCT_UTMP_UT_NAME))
+# define UT_USER(UT) ((UT)->ut_name)
+#else
# define UT_USER(UT) ((UT)->ut_user)
-
#endif
-#if READUTMP_USE_SYSTEMD
-# define HAVE_STRUCT_XTMP_UT_EXIT 0
-#else
-# define HAVE_STRUCT_XTMP_UT_EXIT \
- (HAVE_STRUCT_UTMP_UT_EXIT \
- || HAVE_STRUCT_UTMPX_UT_EXIT)
-#endif
+#define HAVE_STRUCT_XTMP_UT_EXIT \
+ (!HAVE_GL_UTMP && (HAVE_STRUCT_UTMP_UT_EXIT || HAVE_STRUCT_UTMPX_UT_EXIT)
-#if READUTMP_USE_SYSTEMD
-# define HAVE_STRUCT_XTMP_UT_ID 1
-#else
-# define HAVE_STRUCT_XTMP_UT_ID \
- (HAVE_STRUCT_UTMP_UT_ID \
- || HAVE_STRUCT_UTMPX_UT_ID)
-#endif
+#define HAVE_STRUCT_XTMP_UT_ID \
+ (HAVE_GL_UTMP || HAVE_STRUCT_UTMP_UT_ID || HAVE_STRUCT_UTMPX_UT_ID)
-#if READUTMP_USE_SYSTEMD
-# define HAVE_STRUCT_XTMP_UT_PID 1
-#else
-# define HAVE_STRUCT_XTMP_UT_PID \
- (HAVE_STRUCT_UTMP_UT_PID \
- || HAVE_STRUCT_UTMPX_UT_PID)
-#endif
+#define HAVE_STRUCT_XTMP_UT_PID \
+ (HAVE_GL_UTMP || HAVE_STRUCT_UTMP_UT_PID || HAVE_STRUCT_UTMPX_UT_PID)
-#if READUTMP_USE_SYSTEMD
-# define HAVE_STRUCT_XTMP_UT_HOST 1
-#else
-# define HAVE_STRUCT_XTMP_UT_HOST \
- (HAVE_STRUCT_UTMP_UT_HOST \
- || HAVE_STRUCT_UTMPX_UT_HOST)
-#endif
+#define HAVE_STRUCT_XTMP_UT_HOST \
+ (HAVE_GL_UTMP || HAVE_STRUCT_UTMP_UT_HOST || HAVE_STRUCT_UTMPX_UT_HOST)
/* Type of entry returned by read_utmp(). */
typedef struct UTMP_STRUCT_NAME STRUCT_UTMP;
/* Size of the UT_USER (ut) member, or -1 if unbounded. */
-#if READUTMP_USE_SYSTEMD
+#if HAVE_GL_UTMP
enum { UT_USER_SIZE = -1 };
#else
enum { UT_USER_SIZE = sizeof UT_USER ((STRUCT_UTMP *) 0) };
#endif
/* Size of the ut->ut_id member, or -1 if unbounded. */
-#if READUTMP_USE_SYSTEMD
+#if HAVE_GL_UTMP
enum { UT_ID_SIZE = -1 };
#else
enum { UT_ID_SIZE = sizeof (((STRUCT_UTMP *) 0)->ut_id) };
#endif
/* Size of the ut->ut_line member, or -1 if unbounded. */
-#if READUTMP_USE_SYSTEMD
+#if HAVE_GL_UTMP
enum { UT_LINE_SIZE = -1 };
#else
enum { UT_LINE_SIZE = sizeof (((STRUCT_UTMP *) 0)->ut_line) };
#endif
/* Size of the ut->ut_host member, or -1 if unbounded. */
-#if READUTMP_USE_SYSTEMD
+#if HAVE_GL_UTMP
enum { UT_HOST_SIZE = -1 };
#else
enum { UT_HOST_SIZE = sizeof (((STRUCT_UTMP *) 0)->ut_host) };
/* Accessor macros for the member named ut_type. */
-#if READUTMP_USE_SYSTEMD || HAVE_STRUCT_UTMP_UT_TYPE || HAVE_STRUCT_UTMPX_UT_TYPE
+#if HAVE_GL_UTMP || HAVE_STRUCT_UTMP_UT_TYPE || HAVE_STRUCT_UTMPX_UT_TYPE
# define UT_TYPE_EQ(UT, V) ((UT)->ut_type == (V))
# define UT_TYPE_NOT_DEFINED 0
#else