uptime command for Services For Unix (Interix)

Windows stores the time of system boot in the internals of the w32api subsystem. A Microsoft supplied windows utilities have been written to access this; It was on the Windows NT resource kit, and now as a separate binary, uptime.exe. I think some cygwin applications also.

However the SFU subsystem is not layered on the w32api (as cygwin is) and hence doesn't have access to this information.

Unix systems provide the uptime command through the use of the utmp/wtmp files . These log various significant events such as logins, time changes and reboots. Interix/SFU is sufficiently good in its emulation to emulate these files. Strictly the boot entry will be when the SFU subsystem started rather than windows. Below is some code to search the file for the most recent reboot and display this in Unix uptime format.

/*
Program: uptime
reports time since system booted. (Like the Unix command)
Under Services for Unix (Interix), this is reliant
on the start time of the interix posix subsystem which
(like Unix) writes records to the wtmp file.
This contains logins etc, but also boot records

Author: David Horton
www.chapelhill.homeip.net
dhorton@iprimus.com.au david_horton@acslink.net.au
14-May-2005
*/
#include <stdio.h>
#include <utmpx.h>
#include <fcntl.h>
#ifndef _PATH_WTMPX
#define _PATH_WTMPX "/var/adm/wtmpx"
#endif

main(void) {
/* Sample output
SFU(Windows):
09:23:22 up 23 day(s) 16:03:21

Linux:
00:36:46 up 36 days, 10:24, 4 users, load average: 0.00, 0.00, 0.00
(time of day) (uptime) (logins) (load average)
Solaris:
12:34am up 36 day(s), 10:04, 2 users, load average: 0.28, 0.16, 0.14
*/
int fd = -1;
struct utmpx wtmp;
time_t up = 0; /* time system came up */
time_t now = 0; /* the time now */
time_t uptime; /* elapsed time since system came up */
char bufn[100];
char bufu[100];
struct tm now_tm;
struct tm uptime_tm;

if (0 > (fd = open(_PATH_WTMPX,O_RDONLY))) {
perror("open(" _PATH_WTMPX);
exit(1);
}
while( read(fd, &wtmp, sizeof(wtmp))) {
if (wtmp.ut_type == BOOT_TIME) {
up = wtmp.ut_tv.tv_sec;
}
}
close (fd);
now = time(NULL);
uptime = now - up;
(void) localtime_r(&now, &now_tm);
(void) gmtime_r(&uptime, &uptime_tm);

(void) strftime(bufn, sizeof(bufn), "%H:%M:%S", &now_tm);
sprintf(bufu,"%d day(s), %2.2d:%2.2d:%2.2d",
uptime_tm.tm_yday,
uptime_tm.tm_hour,
uptime_tm.tm_min,
uptime_tm.tm_sec);

printf ("%s up %s\n", bufn, bufu);
exit (0);
}

To do:
  1. read backwards through the file for the last reboot. Sequential scanning is potentially slow for large files.
  2. Implement user counts
  3. Implement load averages.

David Horton
email: david_horton@acslink.net.au
WWW: www.ChapelHill.homeip.net