[net.sources] uptime for System V

sjm@dayton.UUCP (Steven J. McDowall) (09/14/86)

In response to a request in net.unix (well, no one is perfect :-)
and because the program is interesting in its own right, here is
the source to a version of uptime (BSD isn't it?) that I wrote 
for our NCR Tower/32 (Sys V.2 Unix):

It's fairly short, and the only mods (if any) you may have to
do is change where some of the include files reside. After
compilation, move to your favorite directory, and setuid
to root (it has to read /dev/kmem). 

------------------------------CUT HERE----------------------------
/*
 *	uptime.c -- Print how long the system has been up 
 *				System V Implmenentation
 *
 *	(sjm@dayton)	Steven McDowall
 *
 *	cc -O -o uptime uptime.c
 *	chown root uptime
 *	chmod u+s uptime			So we can read /dev/kmem
 */

# include <sys/types.h>			/* system types */
# include <sys/sysinfo.h>		/* sysinfo structure */
# include <sys/param.h>			/* for HZ */
# include <stdio.h>
# include <nlist.h>
# include <fcntl.h>
# include <time.h>

#define	MINUTES	60
#define HOURS	(MINUTES * 60)
#define DAYS	(HOURS * 24)

# define SYSTEM "/unix"
# define KMEM "/dev/kmem"

struct nlist nl[] = {
# define NL_SYSINFO 0
        { "sysinfo" },			/* 0 */
# define NL_LBOLT 1
	{ "lbolt" },			/* 1 */
        { 0 }
};


int		memfd;
char	*system = SYSTEM;
char	*kmem = KMEM;
char	*argv0;

main(argc, argv)
int  argc;
char *argv[];
{
	time_t	boothz, uptime;
	void	ptime();

	argv0 = argv[0];
	init_nlist();			/* get name values, open kmem */

/*
	Now read kmem to get the boot time
*/
	l_lseek(memfd, (long)nl[NL_LBOLT].n_value, 0);
	r_read(memfd, (char *)&boothz, sizeof( boothz ) );
	uptime = (boothz / HZ);
	ptime(uptime);
} /* main */

init_nlist()
{
	nlist(system, nl);		/* get system values */

    if(nl[NL_SYSINFO].n_value == 0)
	{
	    fprintf(stderr, "%s: can't find sysinf structure\n", argv0);
        exit(1);
    } /* no value */

	if ((memfd = open(kmem, O_RDONLY)) < 0)
	{
		fprintf(stderr, "%s: no mem\n", argv0);
		exit(1);
	} /* could not open kmem */

} /* init_nlist */

/* lseek with error checking */
l_lseek(fd, offset, whence)
int fd, whence;
long	offset;
{
	if (lseek(fd, offset, whence) == -1)
	{
		fprintf(stderr, "%s: error on lseek\n", argv0);
		exit(1);
	}
}

/* read with error checking */
r_read (fd, buf, nbytes)
int	fd, nbytes;
char	*buf;
{
	if (read(fd, buf, nbytes) != nbytes)
	{
		fprintf(stderr, "%s: error on read\n", argv0);
		exit(1);
	}
}

/*
	Print the time in a nice format 
*/
void ptime(secs)
time_t secs;
{
	short	days, hours, minutes;

	secs -= (days = secs / DAYS) * DAYS;
	secs -= (hours = secs / HOURS) * HOURS;
	secs -= (minutes = secs / MINUTES) * MINUTES;

	printf("The system has been up for ");
	if (days != 0)
		printf("%d %s ", days, (days == 1 ? "day" : "days"));
	if (hours != 0)
		printf("%d %s ", hours, (hours == 1 ? "hour" : "hours"));
	if (minutes != 0)
		printf("%d %s ", minutes, (minutes == 1 ? "minute" : "minutes"));
	printf("and %d %s.\n", secs, (secs == 1 ? "second" : "seconds"));
}
-- 
Steven J. McDowall	
Dayton-Hudson Dept. Store. Co.		UUCP: ihnp4!rosevax!dayton!sjm
700 on the Mall				ATT:  1 612 375 2816
Mpls, Mn. 55408

sjm@dayton.UUCP (sjm) (09/19/86)

Well, it happens to the best of us (which certainly excludes me :-)
Two days after posting the original uptime.c program for Sys V,
Paul Jatkowski @ cuuxb reminds me that the times() call will
return the number of clock ticks since boot time. (Though
the System V definition only says that it will return some
arbitrary number of ticks (e.g. clock ticks)). Anyway, needless
to say this is a much faster method of determining uptime 
(although not as fun :-) than reading kernel memory. This 
version also doesn't need to be set uid-ed.

Also, an option (any argument) will instead cause the date
of the last boot.

---------------------------CUT HERE------------------------------
/*
 *	uptime.c -- Print how long the system has been up 
 *				System V Implmenentation
 *
 *	8/19/86	- Version 1.0
 *		(sjm@dayton)	Steven McDowall
 *
 *	9/19/86 - Version 1.1
 *	  Get boot time much faster from times() call
 *		(pej@cuuxb)		Paul Jatkowski
 *
 *	cc -O -o uptime uptime.c
 */

# include <sys/types.h>			/* system types */
# include <sys/param.h>			/* for HZ */
# include <sys/times.h>
# include <time.h>

#define	MINUTES	60
#define HOURS	(MINUTES * 60)
#define DAYS	(HOURS * 24)

int		memfd;

main(argc, argv)
int  argc;
char *argv[];
{
	time_t	uptime, times();
	struct  tm  *ts;
	struct	tms tbuf;
	void	ptime();

	
/*
	Get the number of clock cycles the system has been running
	and divide by the clock rate (HZ) to get seconds
*/
	uptime = (times(tbuf) / HZ);

/*
	Print out information in one of 2 formats
*/
	if (argc > 1)				/* assume we want boot date */
	{
		uptime = time((long *) 0) - uptime;
		ts = localtime(&uptime);
		printf("System was last booted on %s", asctime(ts));
	}
	else						/* we want old uptime format */
		ptime(uptime);

} /* main */

/*
	Print the time in a nice format 
*/
void ptime(secs)
time_t secs;
{
	short	days, hours, minutes;

	secs -= (days = secs / DAYS) * DAYS;
	secs -= (hours = secs / HOURS) * HOURS;
	secs -= (minutes = secs / MINUTES) * MINUTES;

	printf("The system has been up for ");
	if (days != 0)
		printf("%d %s ", days, (days == 1 ? "day" : "days"));
	if (hours != 0)
		printf("%d %s ", hours, (hours == 1 ? "hour" : "hours"));
	if (minutes != 0)
		printf("%d %s ", minutes, (minutes == 1 ? "minute" : "minutes"));
	printf("and %d %s.\n", secs, (secs == 1 ? "second" : "seconds"));
}
-- 
Steven J. McDowall	
Dayton-Hudson Dept. Store. Co.		UUCP: ihnp4!rosevax!dayton!sjm
700 on the Mall				ATT:  1 612 375 2816
Mpls, Mn. 55408