[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
readutmp: On Cygwin and Windows, return the boot time
From: |
Bruno Haible |
Subject: |
readutmp: On Cygwin and Windows, return the boot time |
Date: |
Fri, 11 Aug 2023 14:37:28 +0200 |
Windows has no utmp file. But it's possible to derive the boot time by looking
at the time stamp of a file, namely C:\pagefile.sys. This is the same trick as
used by Emacs (see emacs/nt/inc/ms-w32.h:BOOT_TIME_FILE).
Other ways to determine the boot time, through the event log, would also be
possible: Search for event 6005 [1][2].
[1] https://serverfault.com/questions/702828/
[2]
https://www.renanrodrigues.com/post/how-to-find-out-the-last-time-windows-rebooted-and-started-up
[3]
https://www.whatsupgold.com/blog/how-to-find-restart-info-for-machines-on-your-network-using-powershell-and-windows-event-logs
2023-08-11 Bruno Haible <bruno@clisp.org>
readutmp: On Cygwin and Windows, return the boot time.
* lib/readutmp.h (READ_UTMP_SUPPORTED): Define also on native Windows.
* lib/readutmp.c (desirable_utmp_entry): Ignore READ_UTMP_CHECK_PIDS on
Windows.
(read_utmp_from_file): Add a BOOT_TIME entry on Windows.
diff --git a/lib/readutmp.c b/lib/readutmp.c
index eabd3e7678..c19ec2f6b1 100644
--- a/lib/readutmp.c
+++ b/lib/readutmp.c
@@ -178,11 +178,13 @@ desirable_utmp_entry (STRUCT_UTMP const *ut, int options)
bool user_proc = IS_USER_PROCESS (ut);
if ((options & READ_UTMP_USER_PROCESS) && !user_proc)
return false;
+# if !(defined __CYGWIN__ || defined _WIN32)
if ((options & READ_UTMP_CHECK_PIDS)
&& user_proc
&& 0 < UT_PID (ut)
&& (kill (UT_PID (ut), 0) < 0 && errno == ESRCH))
return false;
+# endif
return true;
}
@@ -359,7 +361,9 @@ read_utmp_from_file (char const *file, idx_t *n_entries,
STRUCT_UTMP **utmp_buf,
struct utmp_alloc a = {0};
-# if defined UTMP_NAME_FUNCTION /* glibc, musl, macOS, FreeBSD, NetBSD, Minix,
AIX, IRIX, Solaris, Cygwin, Android */
+# if READUTMP_USE_SYSTEMD || HAVE_UTMPX_H || HAVE_UTMP_H
+
+# if defined UTMP_NAME_FUNCTION /* glibc, musl, macOS, FreeBSD, NetBSD,
Minix, AIX, IRIX, Solaris, Cygwin, Android */
/* Ignore the return value for now.
Solaris' utmpname returns 1 upon success -- which is contrary
@@ -369,17 +373,17 @@ read_utmp_from_file (char const *file, idx_t *n_entries,
STRUCT_UTMP **utmp_buf,
SET_UTMP_ENT ();
-# if defined __linux__ && !defined __ANDROID__
+# if defined __linux__ && !defined __ANDROID__
bool file_is_utmp = (strcmp (file, UTMP_FILE) == 0);
/* Timestamp of the "runlevel" entry, if any. */
struct timespec runlevel_ts = {0};
-# endif
+# endif
void const *entry;
while ((entry = GET_UTMP_ENT ()) != NULL)
{
-# if __GLIBC__ && _TIME_BITS == 64
+# if __GLIBC__ && _TIME_BITS == 64
/* This is a near-copy of glibc's struct utmpx, which stops working
after the year 2038. Unlike the glibc version, struct utmpx32
describes the file format even if time_t is 64 bits. */
@@ -410,9 +414,9 @@ read_utmp_from_file (char const *file, idx_t *n_entries,
STRUCT_UTMP **utmp_buf,
char ut_reserved[20]; /* Reserved for future use. */
};
struct utmpx32 const *ut = (struct utmpx32 const *) entry;
-# else
+# else
struct UTMP_STRUCT_NAME const *ut = (struct UTMP_STRUCT_NAME const *)
entry;
-# endif
+# endif
struct timespec ts =
#if (HAVE_UTMPX_H ? 1 : HAVE_STRUCT_UTMP_UT_TV)
@@ -452,17 +456,17 @@ read_utmp_from_file (char const *file, idx_t *n_entries,
STRUCT_UTMP **utmp_buf,
#endif
UT_EXIT_E_TERMINATION (ut), UT_EXIT_E_EXIT (ut)
);
-# if defined __linux__ && !defined __ANDROID__
+# if defined __linux__ && !defined __ANDROID__
if (file_is_utmp
&& memcmp (UT_USER (ut), "runlevel", strlen ("runlevel") + 1) == 0
&& memcmp (ut->ut_line, "~", strlen ("~") + 1) == 0)
runlevel_ts = ts;
-# endif
+# endif
}
END_UTMP_ENT ();
-# if defined __linux__ && !defined __ANDROID__
+# if defined __linux__ && !defined __ANDROID__
/* On Alpine Linux, UTMP_FILE is not filled. It is always empty.
So, fake a BOOT_TIME entry, by getting the time stamp of a file that
gets touched only during the boot process.
@@ -519,9 +523,9 @@ read_utmp_from_file (char const *file, idx_t *n_entries,
STRUCT_UTMP **utmp_buf,
}
}
}
-# endif
+# endif
-# if defined __ANDROID__
+# if defined __ANDROID__
/* On Android, there is no /var, and normal processes don't have access
to system files. Therefore use the kernel's uptime counter, although
it produces wrong values after the date has been bumped in the running
@@ -565,9 +569,9 @@ read_utmp_from_file (char const *file, idx_t *n_entries,
STRUCT_UTMP **utmp_buf,
}
}
}
-# endif
+# endif
-# else /* old FreeBSD, OpenBSD, HP-UX */
+# else /* old FreeBSD, OpenBSD, HP-UX */
FILE *f = fopen (file, "re");
@@ -627,7 +631,7 @@ read_utmp_from_file (char const *file, idx_t *n_entries,
STRUCT_UTMP **utmp_buf,
return -1;
}
-# if defined __OpenBSD__
+# if defined __OpenBSD__
/* On OpenBSD, UTMP_FILE is not filled. It contains only dummy entries.
So, fake a BOOT_TIME entry, by getting the time stamp of a file that
gets touched only during the boot process. */
@@ -661,8 +665,41 @@ read_utmp_from_file (char const *file, idx_t *n_entries,
STRUCT_UTMP **utmp_buf,
}
}
}
+# endif
+
# endif
+# endif
+
+# if defined __CYGWIN__ || defined _WIN32
+ /* On Cygwin, /var/run/utmp is empty.
+ On native Windows, <utmpx.h> and <utmp.h> don't exist.
+ Instead, on Windows, the boot time can be retrieved by looking at the
+ time stamp of a file that (normally) gets touched only during the boot
+ process, namely C:\pagefile.sys. */
+ if ((options & (READ_UTMP_USER_PROCESS | READ_UTMP_NO_BOOT_TIME)) == 0
+ && strcmp (file, UTMP_FILE) == 0
+ && a.filled == 0)
+ {
+ const char * const boot_touched_file =
+ #if defined __CYGWIN__ && !defined _WIN32
+ "/cygdrive/c/pagefile.sys"
+ #else
+ "C:\\pagefile.sys"
+ #endif
+ ;
+ struct stat statbuf;
+ if (stat (boot_touched_file, &statbuf) >= 0)
+ {
+ struct timespec boot_time = get_stat_mtime (&statbuf);
+ a = add_utmp (a, options,
+ "reboot", strlen ("reboot"),
+ "", 0,
+ "", 0,
+ "", 0,
+ 0, BOOT_TIME, boot_time, 0, 0, 0);
+ }
+ }
# endif
a = finish_utmp (a);
diff --git a/lib/readutmp.h b/lib/readutmp.h
index 8db549a393..70cd3801db 100644
--- a/lib/readutmp.h
+++ b/lib/readutmp.h
@@ -243,7 +243,7 @@ enum { UT_HOST_SIZE = -1 };
|| (UT_TYPE_NOT_DEFINED && UT_TIME_MEMBER (UT) != 0)))
/* Define if read_utmp is not just a dummy. */
-#if READUTMP_USE_SYSTEMD || HAVE_UTMPX_H || HAVE_UTMP_H
+#if READUTMP_USE_SYSTEMD || HAVE_UTMPX_H || HAVE_UTMP_H || defined __CYGWIN__
|| defined _WIN32
# define READ_UTMP_SUPPORTED 1
#endif
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- readutmp: On Cygwin and Windows, return the boot time,
Bruno Haible <=