+\f
+/* Return the time of the last system boot. */
+
+static time_t boot_time;
+static int boot_time_initialized;
+
+extern Lisp_Object Vshell_file_name;
+
+#ifdef BOOT_TIME
+static void get_boot_time_1 P_ ((char *, int));
+#endif
+
+static time_t
+get_boot_time ()
+{
+#if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
+ int counter;
+#endif
+
+ if (boot_time_initialized)
+ return boot_time;
+ boot_time_initialized = 1;
+
+#if defined (CTL_KERN) && defined (KERN_BOOTTIME)
+ {
+ int mib[2];
+ size_t size;
+ struct timeval boottime_val;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTTIME;
+ size = sizeof (boottime_val);
+
+ if (sysctl (mib, 2, &boottime_val, &size, NULL, 0) >= 0)
+ {
+ boot_time = boottime_val.tv_sec;
+ return boot_time;
+ }
+ }
+#endif /* defined (CTL_KERN) && defined (KERN_BOOTTIME) */
+
+ if (BOOT_TIME_FILE)
+ {
+ struct stat st;
+ if (stat (BOOT_TIME_FILE, &st) == 0)
+ {
+ boot_time = st.st_mtime;
+ return boot_time;
+ }
+ }
+
+#if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
+#ifndef CANNOT_DUMP
+ /* The utmp routines maintain static state.
+ Don't touch that state unless we are initialized,
+ since it might not survive dumping. */
+ if (! initialized)
+ return boot_time;
+#endif /* not CANNOT_DUMP */
+
+ /* Try to get boot time from utmp before wtmp,
+ since utmp is typically much smaller than wtmp.
+ Passing a null pointer causes get_boot_time_1
+ to inspect the default file, namely utmp. */
+ get_boot_time_1 ((char *) 0, 0);
+ if (boot_time)
+ return boot_time;
+
+ /* Try to get boot time from the current wtmp file. */
+ get_boot_time_1 (WTMP_FILE, 1);
+
+ /* If we did not find a boot time in wtmp, look at wtmp, and so on. */
+ for (counter = 0; counter < 20 && ! boot_time; counter++)
+ {
+ char cmd_string[100];
+ Lisp_Object tempname, filename;
+ int delete_flag = 0;
+
+ filename = Qnil;
+
+ sprintf (cmd_string, "%s.%d", WTMP_FILE, counter);
+ tempname = build_string (cmd_string);
+ if (! NILP (Ffile_exists_p (tempname)))
+ filename = tempname;
+ else
+ {
+ sprintf (cmd_string, "%s.%d.gz", WTMP_FILE, counter);
+ tempname = build_string (cmd_string);
+ if (! NILP (Ffile_exists_p (tempname)))
+ {
+ Lisp_Object args[6];
+
+ /* The utmp functions on mescaline.gnu.org accept only
+ file names up to 8 characters long. Choose a 2
+ character long prefix, and call make_temp_file with
+ second arg non-zero, so that it will add not more
+ than 6 characters to the prefix. */
+ tempname = Fexpand_file_name (build_string ("wt"),
+ Vtemporary_file_directory);
+ tempname = make_temp_name (tempname, 1);
+ args[0] = Vshell_file_name;
+ args[1] = Qnil;
+ args[2] = Qnil;
+ args[3] = Qnil;
+ args[4] = build_string ("-c");
+ sprintf (cmd_string, "gunzip < %s.%d.gz > %s",
+ WTMP_FILE, counter, XSTRING (tempname)->data);
+ args[5] = build_string (cmd_string);
+ Fcall_process (6, args);
+ filename = tempname;
+ delete_flag = 1;
+ }
+ }
+
+ if (! NILP (filename))
+ {
+ get_boot_time_1 (XSTRING (filename)->data, 1);
+ if (delete_flag)
+ unlink (XSTRING (filename)->data);
+ }
+ }
+
+ return boot_time;
+#else
+ return 0;
+#endif
+}
+
+#ifdef BOOT_TIME
+/* Try to get the boot time from wtmp file FILENAME.
+ This succeeds if that file contains a reboot record.
+
+ If FILENAME is zero, use the same file as before;
+ if no FILENAME has ever been specified, this is the utmp file.
+ Use the newest reboot record if NEWEST is nonzero,
+ the first reboot record otherwise.
+ Ignore all reboot records on or before BOOT_TIME.
+ Success is indicated by setting BOOT_TIME to a larger value. */
+
+void
+get_boot_time_1 (filename, newest)
+ char *filename;
+ int newest;
+{
+ struct utmp ut, *utp;
+ int desc;
+
+ if (filename)
+ {
+ /* On some versions of IRIX, opening a nonexistent file name
+ is likely to crash in the utmp routines. */
+ desc = emacs_open (filename, O_RDONLY, 0);
+ if (desc < 0)
+ return;
+
+ emacs_close (desc);
+
+ utmpname (filename);
+ }
+
+ setutent ();
+
+ while (1)
+ {
+ /* Find the next reboot record. */
+ ut.ut_type = BOOT_TIME;
+ utp = getutid (&ut);
+ if (! utp)
+ break;
+ /* Compare reboot times and use the newest one. */
+ if (utp->ut_time > boot_time)
+ {
+ boot_time = utp->ut_time;
+ if (! newest)
+ break;
+ }
+ /* Advance on element in the file
+ so that getutid won't repeat the same one. */
+ utp = getutent ();
+ if (! utp)
+ break;
+ }
+ endutent ();
+}
+#endif /* BOOT_TIME */