
From wmcbrine@clark.net Thu Jun 19 23:43:21 1997
Date: 17 Jun 1997 17:01:53 GMT
From: William McBrine <wmcbrine@clark.net>
Newsgroups: comp.os.minix
Subject: "uptime" for Minix

One thing I really missed in Minix was the "uptime" command. So, I wrote
my own. Perhaps this will be of use to others. Suggestions for
improvements welcome. 

(To compile this, just type "cc uptime.c -o uptime":)

/* uptime for Minix (and other systems), version 0.2
 * Reports time/users only; no load report
 *
 * by William McBrine <wmcbrine@clark.net>, June 17, 1997
 * Public domain
 *
 * This version of "uptime" relies on the wtmp file, so it can be a little
 * slow. Although written for Minix 2.0, it's portable; I compiled and ran
 * it under Linux/i386 and Solaris/Sparc without modification.
 *
 */

#include <sys/types.h>
#include <utmp.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#define WTMPPATH "/usr/adm/wtmp"
#define UTMPPATH "/etc/utmp"

void plural(const int x)
{
    if (x != 1)
	printf("s");
}

int ampm(int x)
{
    if (x > 12)
	x -= 12;
    if (!x)
	x = 12;
    return x;
}

int main(void)
{
    FILE *wtmpfile;
    struct utmp wtrec;
    struct tm tboot, tnow;
    time_t boottime, now;
    int years, days, hours, mins, ucount = 0;

    /* Find last reboot */

    if ((wtmpfile = fopen(WTMPPATH, "r")) == NULL) {
	printf("Cannot find %s\n", WTMPPATH);
	exit(1);
    }
    while (fread(&wtrec, sizeof(struct utmp), 1, wtmpfile) == 1)
	if (wtrec.ut_line[0] == '~')
	     boottime = wtrec.ut_time;
    fclose(wtmpfile);

/* Find last reboot -- backwards version

 * I thought it would be faster to scan backwards from the end of the file
 * and stop after the last '~'. This did speed things up on my Minix and
 * Linux systems, but was taking so long on my ISP's Solaris box (with a 15
 * meg wtmp file) that I aborted it before it finished. Maybe it fouled up
 * the cache's strategy? Anyway, try this if you like.
 *
 *   long wtpoint = 0;
 *
 *   if ((wtmpfile = fopen(WTMPPATH, "r")) == NULL) {
 *      printf("Cannot find %s\n", WTMPPATH);
 *      exit(1);
 *   }
 *   do {
 *      wtpoint -= sizeof(struct utmp);
 *      fseek(wtmpfile, wtpoint, SEEK_END);
 *      fread(&wtrec, sizeof(struct utmp), 1, wtmpfile);
 *   } while ((!ferror(wtmpfile)) && (wtrec.ut_line[0] != '~'));
 *   boottime = wtrec.ut_time;
 *   fclose(wtmpfile);
 *
 */

    /* Count users */

    if ((wtmpfile = fopen(UTMPPATH, "r")) == NULL) {
	printf("Cannot find %s\n", UTMPPATH);
	exit(1);
    }
    while (fread(&wtrec, sizeof(struct utmp), 1, wtmpfile) == 1)
	if ((wtrec.ut_user[0]) && (wtrec.ut_type == USER_PROCESS))
	     ucount++;
    fclose(wtmpfile);

    /* Calculate uptime */

    time(&now);

    tboot = *(localtime(&boottime));
    tnow = *(localtime(&now));

    years = tnow.tm_year - tboot.tm_year;
    days = tnow.tm_yday - tboot.tm_yday;
    hours = tnow.tm_hour - tboot.tm_hour;
    mins = tnow.tm_min - tboot.tm_min;

    if (mins < 0) {
	mins += 60;
	hours -= 1;
    }
    if (hours < 0) {
	hours += 24;
	days -= 1;
    }
    if (days < 0) {
	days += 365;		/* No attempt to deal with leap years */
	years -= 1;
    }
    /* I've never actually seen a system with an uptime over a year,
     * so I don't know what the original "uptime" does in that case. :-)
     * I hope this will suffice.
     */

    /* Report */

    printf("%3d:%02d%cm  up ", ampm(tnow.tm_hour), tnow.tm_min,
	   (tnow.tm_hour < 12) ? 'a' : 'p');
    if (years > 0) {
	printf("%d year", years);
	plural(years);
	printf(", ");
    }
    if (days > 0) {
	printf("%d day", days);
	plural(days);
	printf(", ");
    }
    if (hours > 0)
	printf("%2d:%02d,", hours, mins);
    else
	printf("%d min,", mins);
    printf("%3d user", ucount);
    plural(ucount);
    printf("\n");

    return 0;
}

-- 
William McBrine    | http://www.clark.net/pub/wmcbrine/html/
wmcbrine@clark.net | Unsolicited commercial emailers will be annihilated


