#!/usr/skunk/bin/gawk -f #!/usr/bin/awk -f # upstat: process wtmp boot time entries & generate statistics # @(#) upstat.awk 2.1 94/03/09 # 89/07 john h. dubois iii (john@armory.com) # 90/11/23 this program was originally written for DOS; # changed expected date format to that produced by who -a: # . system boot Oct 5 15:51 # and made other assorted changes. # 91/10/28 changed name to upstat # 92/01/06 added help option # 92/02/08 added ability to hand year spanning wtmp files # 92/05/02 Changed to be a #!awk script # 94/03/09 Use gawk so - options can be given BEGIN { if (ARGV[1] ~ "^[-+]h$") { print \ "upstat: generate uptime statistics from wtmp boot time entries.\n" \ "Usage: upstat [-h] [who-output]\n" \ "[who-output] should be the output of who -a.\n" \ "If it is not given, upstat uses the output of who -a /etc/wtmp." exit(0) } MonthList = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec" # This does not work if wtmp spans a year-end. # So, assume every year is a leap year. # At worst, an extra day of no boots (Feb. 29) is added. #"/bin/date +%y" | getline Y #if (Y % 4) # DaysList = "0 31 59 90 120 151 181 212 243 273 304 334 365" #else DaysList = "0 31 60 91 121 152 182 213 244 274 305 335 366" split(MonthList,Months,",") split(DaysList,NumDays," ") for (Month in Months) Days[Months[Month]] = NumDays[Month] MinDiffTime = 2000000000 Year = 0 MinuteSecs = 60 HourSecs = MinuteSecs * 60 DaySecs = HourSecs * 24 YearSecs = DaySecs * 366 if (ARGC > 1) while ((getline < ARGV[1]) == 1) ProcLine() else while (("who -a /etc/wtmp" | getline) == 1) ProcLine() if (DisconCt || BadYearCt) printf("Errors: %d time discontinuities, %d bad years.\n", DisconCt,BadYearCt); LogSecs = TotSec - FirstSec printf("Period covered by log: %s (%s to %s)\n", SecToTime(LogSecs),FirstDate,LastDateTime) printf "Year-ends spanned by log: %d.\n",Year printf("Number of reboots: %d.\n",BootLines) printf("Number of days on which machine was rebooted: %d.\n",NumRebootDays); printf("Fraction of days on which machine was rebooted: 1/%.1f.\n", (1.0 * LogSecs / 86400.0)/NumRebootDays); printf("Shortest period between reboots: %s (%s to %s)\n", SecToTime(MinDiffTime),MinLastDate,MinDate) printf("Longest period between reboots: %s (%s to %s)\n", SecToTime(MaxDiffTime),MaxLastDate,MaxDate) printf("Average period between reboots: %s.\n", SecToTime(int(LogSecs/BootLines))); } function ProcLine() { if (($2 != "system") || ($3 != "boot")) return Date = $4 " " $5 DateTime = Date " " $6 if (($4 == "Jan") && (LastDate ~ "^Dec")) { Year++ printf "Year change on line %d: %s to %s.\n",NR,LastDate,Date } TotSec = EntryToSec(Year,$4,$5,$6) DiffTime = TotSec - LastTotSec LastTotSec = TotSec if (DiffTime < 0) { printf("Error on line %d: time discontinuity.\n",NR) DisconCt++ Discon = 1 return } if (Date != LastDate) NumRebootDays++; BootLines++ if (FirstDate == "") { FirstDate = DateTime FirstSec = TotSec } else if (Discon) Discon = 0 else { if (DiffTime < MinDiffTime) { MinDiffTime = DiffTime MinDate = DateTime MinLastDate = LastDateTime } if (DiffTime > MaxDiffTime) { MaxDiffTime = DiffTime; MaxDate = DateTime MaxLastDate = LastDateTime } } LastDateTime = DateTime LastDate = Date } function SecToTime(Seconds, Days,Hours,Minutes,Time) { Days = int(Seconds / 86400) Seconds %= 86400 Hours = int(Seconds / 3600) Seconds %= 3600 Minutes = int(Seconds / 60) Seconds %= 60 if (Days) Time = Days "d " if (Time || Hours) Time = Time Hours "h " if (Time || Minutes) Time = Time Minutes "m " if (!Time || Seconds) Time = Time Seconds "s " return substr(Time,1,length(Time) - 1) } function EntryToSec(Year,Month,Day,HM) { split(HM,HMArr,":") return HMArr[2] * MinuteSecs + HMArr[1] * HourSecs + \ (Days[Month] + Day - 1) * DaySecs + Year * YearSecs }