/*
 * proc/whattime.c - libproc uptime routines
 *
 * This is a trivial uptime program.  I hereby release this program
 * into the public domain.  I disclaim any responsibility for this
 * program --- use it at your own risk.  (as if there were any.. ;-)
 * -michaelkjohnson (johnsonm@sunsite.unc.edu)
 *
 * Modified by Larry Greenfield to give a more traditional output,
 * count users, etc.  (greenfie@gauss.rutgers.edu)
 *
 * Modified by mkj again to fix a few tiny buglies.
 *
 * Modified by J. Cowley to add printing the uptime message to a
 * string (for top) and to optimize file handling.  19 Mar 1993.
 *
 * Modified by Robert Love to remove global variables and use
 * dynamic memory.  This is cleaner and is now thread-safe.
 * Also now does bounds checking.  23 Nov 2002.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <utmp.h>
#include "proc/whattime.h"
#include "proc/sysinfo.h"

static char * sprint_uptime(char *buf, size_t size)
{
	struct utmp *utmpstruct;
	int upminutes, uphours, updays;
	int pos;
	struct tm *realtime;
	time_t realseconds;
	int numuser;
	double uptime_secs, idle_secs;
	double av[3];

	/* first get the current time */
	time(&realseconds);
	realtime = localtime(&realseconds);
	pos = snprintf(buf, size, " %02d:%02d:%02d  ",
			realtime->tm_hour, realtime->tm_min, realtime->tm_sec);

	/* read and calculate the amount of uptime */
	uptime(&uptime_secs, &idle_secs);

	updays = (int) uptime_secs / (60 * 60 * 24);
	pos += snprintf(buf + pos, size - pos, "up ");
	if (updays)
		pos += snprintf(buf + pos, size - pos, "%d day%s, ", updays,
				(updays != 1) ? "s" : "");
	upminutes = (int) uptime_secs / 60;
	uphours = upminutes / 60;
	uphours = uphours % 24;
	upminutes = upminutes % 60;
	if (uphours)
		pos += snprintf(buf + pos, size - pos,
				"%2d:%02d, ", uphours, upminutes);
	else
		pos += snprintf(buf + pos, size - pos, "%d min, ", upminutes);

	/* count the number of users */
	numuser = 0;
	setutent();
	while ((utmpstruct = getutent())) {
		if ((utmpstruct->ut_type == USER_PROCESS) &&
		    (utmpstruct->ut_name[0] != '\0'))
			numuser++;
	}
	endutent();

	pos += snprintf(buf + pos, size - pos, "%2d user%s, ", numuser,
			numuser == 1 ? "" : "s");

	loadavg(&av[0], &av[1], &av[2]);

	pos += snprintf(buf + pos, size - pos,
			" load average: %.2f, %.2f, %.2f", av[0], av[1], av[2]);

	/*
	 * Our current position is at or exceeding our size... we did not
	 * have enough room and the string is incomplete.  Error.
	 */
	if ((unsigned int) pos >= size)
		return NULL;

	return buf;
}

/*
 * Size of the uptime string.  The maximum string size possible depends on
 * your locale, so we play it safe with a high buffer size.  But on my
 * en-us system with triple-digit users, the max size is only 65.
 */
#define UPTIME_SIZE	128

void print_uptime(void)
{
	char buf[UPTIME_SIZE];

	if (sprint_uptime(buf, UPTIME_SIZE))
		printf("%s", buf);
	else
		printf("error getting uptime!");
}
