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