From f0d5c17ea7b2b5b815f24b101d35ddda1a88d8a4 Mon Sep 17 00:00:00 2001 From: Alexander Amelkin Date: Thu, 26 Jul 2018 19:40:44 +0300 Subject: [PATCH] Refactor timestamp handling Handle all date/time stamps uniformly, taking in account the host endianness. Respect the local time zone and the '-Z' option for all ipmitool commands. Unify the date and time formatting. Add correct handling of IPMI timestamps 'since system startup' and for 'unspecified' timestamps. Partially resolves ipmitool/ipmitool#23 Signed-off-by: Alexander Amelkin --- include/ipmitool/ipmi.h | 1 - include/ipmitool/ipmi_fru.h | 5 +- include/ipmitool/ipmi_time.h | 91 +++++++++++++ lib/Makefile.am | 2 +- lib/ipmi_chassis.c | 33 +---- lib/ipmi_dcmi.c | 22 +--- lib/ipmi_delloem.c | 249 +++++++++++++---------------------- lib/ipmi_ekanalyzer.c | 22 ++-- lib/ipmi_fru.c | 14 +- lib/ipmi_mc.c | 10 +- lib/ipmi_pef.c | 13 +- lib/ipmi_sdr.c | 23 +--- lib/ipmi_sel.c | 147 +++++++-------------- lib/ipmi_time.c | 217 ++++++++++++++++++++++++++++++ src/ipmievd.c | 1 - src/ipmitool.c | 2 - 16 files changed, 485 insertions(+), 367 deletions(-) create mode 100644 include/ipmitool/ipmi_time.h create mode 100644 lib/ipmi_time.c diff --git a/include/ipmitool/ipmi.h b/include/ipmitool/ipmi.h index fda76d5..f541496 100644 --- a/include/ipmitool/ipmi.h +++ b/include/ipmitool/ipmi.h @@ -67,7 +67,6 @@ #define IPMI_PAYLOAD_TYPE_RAKP_4 0x15 extern int verbose; -extern int time_in_utc; extern int csv_output; struct ipmi_rq { diff --git a/include/ipmitool/ipmi_fru.h b/include/ipmitool/ipmi_fru.h index d03abfc..28226d8 100644 --- a/include/ipmitool/ipmi_fru.h +++ b/include/ipmitool/ipmi_fru.h @@ -591,7 +591,10 @@ struct fru_picmgext_amc_link_desc_record { #endif /* FRU Board manufacturing date */ -static const uint64_t secs_from_1970_1996 = 820454400; +static inline time_t ipmi_fru2time_t(void *mfg_date) { + const uint64_t secs_from_1970_1996 = 820454400; + return ipmi24toh(mfg_date) * 60 + secs_from_1970_1996; +} static const char * chassis_type_desc[] __attribute__((unused)) = { "Unspecified", "Other", "Unknown", "Desktop", "Low Profile Desktop", "Pizza Box", diff --git a/include/ipmitool/ipmi_time.h b/include/ipmitool/ipmi_time.h new file mode 100644 index 0000000..e5e44b9 --- /dev/null +++ b/include/ipmitool/ipmi_time.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2018 Alexander Amelkin. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the copyright holder, nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * THE COPYRIGHT HOLDER AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * THE COPYRIGHT HOLDER OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, + * PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE + * THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS + * SOFTWARE, EVEN IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. + */ +#ifndef IPMI_TIME_H +#define IPMI_TIME_H + +#include +#include + +extern bool time_in_utc; + +/* Special values according to IPMI v2.0, rev. 1.1, section 37.1 */ +#define IPMI_TIME_UNSPECIFIED 0xFFFFFFFFu +#define IPMI_TIME_INIT_DONE 0x20000000u + +#define SECONDS_A_DAY (24 * 60 * 60) + +/* + * Check whether the timestamp is in seconds since Epoch or since + * the system startup. + */ +static inline bool ipmi_timestamp_is_special(time_t ts) +{ + return (ts < IPMI_TIME_INIT_DONE); +} + +/* + * Check whether the timestamp is valid at all + */ +static inline bool ipmi_timestamp_is_valid(time_t ts) +{ + return (ts != IPMI_TIME_UNSPECIFIED); +} + +/* + * Just 26 characters are required for asctime_r(), plus timezone info. + * However just to be safe locale-wise and assuming that in no locale + * the date/time string exceeds the 'standard' legacy terminal width, + * the buffer size is set here to 80. + */ +#define IPMI_ASCTIME_SZ 80 +typedef char ipmi_datebuf_t[IPMI_ASCTIME_SZ]; + +/* + * These are ipmitool-specific versions that take + * in account the command line options + */ +char *ipmi_asctime_r(time_t stamp, ipmi_datebuf_t outbuf); +size_t ipmi_strftime(char *s, int max, const char *format, time_t stamp); + +/* These return pointers to static arrays and aren't thread safe */ +char *ipmi_timestamp_fmt(uint32_t stamp, const char *fmt); +char *ipmi_timestamp_string(uint32_t stamp); /* Day Mon DD HH:MM:SS YYYY ZZZ */ +char *ipmi_timestamp_numeric(uint32_t stamp); /* MM/DD/YYYY HH:MM:SS ZZZ */ +char *ipmi_timestamp_date(uint32_t stamp); /* MM/DD/YYYY ZZZ */ +char *ipmi_timestamp_time(uint32_t stamp); /* HH:MM:SS ZZZ */ + +/* Subtract the UTC offset from local time_t */ +time_t ipmi_localtime2utc(time_t local); + +#endif + diff --git a/lib/Makefile.am b/lib/Makefile.am index 8b6cc95..fd3534b 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -42,7 +42,7 @@ libipmitool_la_SOURCES = helper.c ipmi_sdr.c ipmi_sel.c ipmi_sol.c ipmi_pef.c \ ipmi_main.c ipmi_tsol.c ipmi_firewall.c ipmi_kontronoem.c \ ipmi_hpmfwupg.c ipmi_sdradd.c ipmi_ekanalyzer.c ipmi_gendev.c \ ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c hpm2.c ipmi_vita.c \ - ipmi_lanp6.c ipmi_cfgp.c ipmi_quantaoem.c \ + ipmi_lanp6.c ipmi_cfgp.c ipmi_quantaoem.c ipmi_time.c \ ../src/plugins/lan/md5.c ../src/plugins/lan/md5.h libipmitool_la_LDFLAGS = -export-dynamic diff --git a/lib/ipmi_chassis.c b/lib/ipmi_chassis.c index c251cfc..fba6b0b 100644 --- a/lib/ipmi_chassis.c +++ b/lib/ipmi_chassis.c @@ -42,6 +42,7 @@ #include #include #include +#include extern int verbose; @@ -699,45 +700,19 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg) case 6: { unsigned long session_id; - unsigned long timestamp; - char time_buf[40]; - time_t out_time; - struct tm *strtm; + uint32_t timestamp; session_id = ((unsigned long) rsp->data[3]); session_id |= (((unsigned long) rsp->data[4])<<8); session_id |= (((unsigned long) rsp->data[5])<<16); session_id |= (((unsigned long) rsp->data[6])<<24); - timestamp = ((unsigned long) rsp->data[7]); - timestamp |= (((unsigned long) rsp->data[8])<<8); - timestamp |= (((unsigned long) rsp->data[9])<<16); - timestamp |= (((unsigned long) rsp->data[10])<<24); - - memset(time_buf, 0, 40); - if(time_in_utc) - strtm = gmtime(&out_time); - else - strtm = localtime(&out_time); - - strftime( - time_buf, - sizeof(time_buf), - "%m/%d/%Y %H:%M:%S", strtm - ); + timestamp = ipmi32toh(&rsp->data[7]); printf(" Boot Initiator Info :\n"); printf(" Channel Number : %d\n", (rsp->data[2] & 0x0f)); printf(" Session Id : %08lXh\n",session_id); - if(timestamp != 0) - { - printf(" Timestamp : %08lXh, %s\n",timestamp,time_buf); - } - else - { - printf(" Timestamp : %08lXh, undefined\n",timestamp); - } - + printf(" Timestamp : %s\n", ipmi_timestamp_numeric(timestamp)); } break; case 7: diff --git a/lib/ipmi_dcmi.c b/lib/ipmi_dcmi.c index 94cc1ec..a7f7e52 100755 --- a/lib/ipmi_dcmi.c +++ b/lib/ipmi_dcmi.c @@ -56,6 +56,7 @@ #include #include #include +#include #include "../src/plugins/lanplus/lanplus.h" @@ -1399,11 +1400,7 @@ ipmi_dcmi_pwr_rd(struct ipmi_intf * intf, uint8_t sample_time) struct ipmi_rs * rsp; struct ipmi_rq req; struct power_reading val; - struct tm tm_t; - time_t t; uint8_t msg_data[4]; /* number of request data bytes */ - memset(&tm_t, 0, sizeof(tm_t)); - memset(&t, 0, sizeof(t)); msg_data[0] = IPMI_DCMI; /* Group Extension Identification */ if (sample_time) { @@ -1429,8 +1426,6 @@ ipmi_dcmi_pwr_rd(struct ipmi_intf * intf, uint8_t sample_time) /* rsp->data[0] is equal to response data byte 2 in spec */ /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */ memcpy(&val, rsp->data, sizeof (val)); - t = val.time_stamp; - gmtime_r(&t, &tm_t); printf("\n"); printf(" Instantaneous power reading: %8d Watts\n", val.curr_pwr); @@ -1441,7 +1436,7 @@ ipmi_dcmi_pwr_rd(struct ipmi_intf * intf, uint8_t sample_time) printf(" Average power reading over sample period: %8d Watts\n", val.avg_pwr); printf(" IPMI timestamp: %s", - asctime(&tm_t)); + ipmi_timestamp_numeric(ipmi32toh(&val.time_stamp))); printf(" Sampling period: "); if (sample_time) printf("%s \n", val2str2(val.sample,dcmi_sampling_vals)); @@ -2876,12 +2871,8 @@ ipmi_nm_get_statistics(struct ipmi_intf * intf, int argc, char **argv) uint8_t policy_id = -1; uint8_t have_policy_id = FALSE; int policy_mode = 0; - int cut; char *units = ""; - char datebuf[27]; struct nm_statistics stats; - struct tm tm_t; - time_t t; argv++; if (!argv[0] || @@ -2943,11 +2934,6 @@ ipmi_nm_get_statistics(struct ipmi_intf * intf, int argc, char **argv) } if (_ipmi_nm_statistics(intf, mode, domain, policy_id, &stats)) return -1; - t = stats.time_stamp; - gmtime_r(&t, &tm_t); - sprintf(datebuf, "%s", asctime(&tm_t)); - cut = strlen(datebuf) -1; - datebuf[cut] = 0; if (csv_output) { printf("%s,%s,%s,%s,%s,%d,%d,%d,%d,%s,%d\n", val2str2(stats.id_state & 0xF, nm_domain_vals), @@ -2964,7 +2950,7 @@ ipmi_nm_get_statistics(struct ipmi_intf * intf, int argc, char **argv) stats.min_value, stats.max_value, stats.ave_value, - datebuf, + ipmi_timestamp_numeric(ipmi32toh(&stats.time_stamp)), stats.stat_period); return 0; } @@ -2992,7 +2978,7 @@ ipmi_nm_get_statistics(struct ipmi_intf * intf, int argc, char **argv) printf(" Average reading over sample period: %8d %s\n", stats.ave_value, units); printf(" IPMI timestamp: %s\n", - datebuf); + ipmi_timestamp_numeric(ipmi32toh(&stats.time_stamp))); printf(" Sampling period: %08d Seconds.\n", stats.stat_period); printf("\n"); diff --git a/lib/ipmi_delloem.c b/lib/ipmi_delloem.c index 4658d0c..c1f3ef6 100644 --- a/lib/ipmi_delloem.c +++ b/lib/ipmi_delloem.c @@ -62,6 +62,7 @@ #include #include #include +#include #define DELL_OEM_NETFN (uint8_t)(0x30) #define GET_IDRAC_VIRTUAL_MAC (uint8_t)(0xC9) @@ -201,7 +202,6 @@ static int ipmi_lan_set_nic_selection_12g(struct ipmi_intf *intf, /* Power monitor Function prototypes */ static int ipmi_delloem_powermonitor_main(struct ipmi_intf *intf, int argc, char **argv); -static void ipmi_time_to_str(time_t rawTime, char *strTime); static int ipmi_get_sensor_reading(struct ipmi_intf *intf, unsigned char sensorNumber, SensorReadingType *pSensorReadingData); static int ipmi_get_power_capstatus_command(struct ipmi_intf *intf); @@ -2601,24 +2601,7 @@ ipmi_delloem_powermonitor_main(struct ipmi_intf * intf, int argc, char ** argv) } return rc; } -/* - * Function Name: ipmi_time_to_str - * - * Description: This function converts ipmi time format into gmtime format - * Input: rawTime - ipmi time format - * Output: strTime - gmtime format - * - * Return: - */ -static void -ipmi_time_to_str(time_t rawTime, char * strTime) -{ - struct tm *tm; - char *temp; - tm = gmtime(&rawTime); - temp = asctime(tm); - strcpy(strTime,temp); -} + /* * Function Name: ipmi_get_sensor_reading * @@ -2768,24 +2751,15 @@ ipmi_powermgmt(struct ipmi_intf * intf) struct ipmi_rs * rsp; struct ipmi_rq req; uint8_t msg_data[2]; - uint32_t cumStartTimeConv; - uint32_t cumReadingConv; - uint32_t maxPeakStartTimeConv; - uint32_t ampPeakTimeConv; - uint16_t ampReadingConv; - uint32_t wattPeakTimeConv; - uint32_t wattReadingConv; - uint32_t bmctimeconv; - uint32_t * bmctimeconvval; + uint32_t cumStartTime; + uint32_t cumReading; + uint32_t maxPeakStartTime; + uint32_t ampPeakTime; + uint32_t wattPeakTime; + uint32_t bmctime; IPMI_POWER_MONITOR * pwrMonitorInfo; - char cumStartTime[26]; - char maxPeakStartTime[26]; - char ampPeakTime[26]; - char wattPeakTime[26]; - char bmctime[26]; - int ampReading; int ampReadingRemainder; int remainder; @@ -2807,12 +2781,7 @@ ipmi_powermgmt(struct ipmi_intf * intf) rsp->ccode); return -1; } - bmctimeconvval=(uint32_t*)rsp->data; -# if WORDS_BIGENDIAN - bmctimeconv=BSWAP_32(*bmctimeconvval); -# else - bmctimeconv=*bmctimeconvval; -# endif + bmctime = ipmi32toh(rsp->data); /* get powermanagement info*/ req.msg.netfn = DELL_OEM_NETFN; @@ -2847,54 +2816,35 @@ ipmi_powermgmt(struct ipmi_intf * intf) } pwrMonitorInfo = (IPMI_POWER_MONITOR*)rsp->data; -# if WORDS_BIGENDIAN - cumStartTimeConv = BSWAP_32(pwrMonitorInfo->cumStartTime); - cumReadingConv = BSWAP_32(pwrMonitorInfo->cumReading); - maxPeakStartTimeConv = BSWAP_32(pwrMonitorInfo->maxPeakStartTime); - ampPeakTimeConv = BSWAP_32(pwrMonitorInfo->ampPeakTime); - ampReadingConv = BSWAP_16(pwrMonitorInfo->ampReading); - wattPeakTimeConv = BSWAP_32(pwrMonitorInfo->wattPeakTime); - wattReadingConv = BSWAP_16(pwrMonitorInfo->wattReading); -# else - cumStartTimeConv = pwrMonitorInfo->cumStartTime; - cumReadingConv = pwrMonitorInfo->cumReading; - maxPeakStartTimeConv = pwrMonitorInfo->maxPeakStartTime; - ampPeakTimeConv = pwrMonitorInfo->ampPeakTime; - ampReadingConv = pwrMonitorInfo->ampReading; - wattPeakTimeConv = pwrMonitorInfo->wattPeakTime; - wattReadingConv = pwrMonitorInfo->wattReading; -# endif + cumStartTime = ipmi32toh(&pwrMonitorInfo->cumStartTime); + cumReading = ipmi32toh(&pwrMonitorInfo->cumReading); + maxPeakStartTime = ipmi32toh(&pwrMonitorInfo->maxPeakStartTime); + ampPeakTime = ipmi32toh(&pwrMonitorInfo->ampPeakTime); + ampReading = ipmi16toh(&pwrMonitorInfo->ampReading); + wattPeakTime = ipmi32toh(&pwrMonitorInfo->wattPeakTime); + wattReading = ipmi16toh(&pwrMonitorInfo->wattReading); - ipmi_time_to_str(cumStartTimeConv, cumStartTime); - ipmi_time_to_str(maxPeakStartTimeConv, maxPeakStartTime); - ipmi_time_to_str(ampPeakTimeConv, ampPeakTime); - ipmi_time_to_str(wattPeakTimeConv, wattPeakTime); - ipmi_time_to_str(bmctimeconv, bmctime); - - remainder = (cumReadingConv % 1000); - cumReadingConv = cumReadingConv / 1000; + remainder = (cumReading % 1000); + cumReading = cumReading / 1000; remainder = (remainder + 50) / 100; - ampReading = ampReadingConv; - ampReadingRemainder = ampReading%10; - ampReading = ampReading/10; - - wattReading = wattReadingConv; + ampReadingRemainder = ampReading % 10; + ampReading = ampReading / 10; printf("Power Tracking Statistics\n"); printf("Statistic : Cumulative Energy Consumption\n"); - printf("Start Time : %s", cumStartTime); - printf("Finish Time : %s", bmctime); - printf("Reading : %d.%d kWh\n\n", cumReadingConv, remainder); + printf("Start Time : %s", ipmi_timestamp_numeric(cumStartTime)); + printf("Finish Time : %s", ipmi_timestamp_numeric(bmctime)); + printf("Reading : %d.%d kWh\n\n", cumReading, remainder); printf("Statistic : System Peak Power\n"); - printf("Start Time : %s", maxPeakStartTime); - printf("Peak Time : %s", wattPeakTime); + printf("Start Time : %s", ipmi_timestamp_numeric(maxPeakStartTime)); + printf("Peak Time : %s", ipmi_timestamp_numeric(wattPeakTime)); printf("Peak Reading : %d W\n\n", wattReading); printf("Statistic : System Peak Amperage\n"); - printf("Start Time : %s", maxPeakStartTime); - printf("Peak Time : %s", ampPeakTime); + printf("Start Time : %s", ipmi_timestamp_numeric(maxPeakStartTime)); + printf("Peak Time : %s", ipmi_timestamp_numeric(ampPeakTime)); printf("Peak Reading : %d.%d A\n", ampReading, ampReadingRemainder); return 0; } @@ -3394,12 +3344,7 @@ ipmi_get_minpower_consmpt_history(struct ipmi_intf * intf, static int ipmi_print_power_consmpt_history(struct ipmi_intf * intf, int unit) { - char timestr[30]; - uint32_t lastminutepeakpower; - uint32_t lasthourpeakpower; - uint32_t lastdaypeakpower; - uint32_t lastweekpeakpower; - uint64_t tempbtuphrconv; + uint64_t tmp; int rc = 0; IPMI_AVGPOWER_CONSUMP_HISTORY avgpower; @@ -3430,95 +3375,85 @@ ipmi_print_power_consmpt_history(struct ipmi_intf * intf, int unit) "Last Day Last Week\n\n"); if (unit == btuphr) { printf("Average Power Consumption "); - tempbtuphrconv = watt_to_btuphr_conversion(avgpower.lastminutepower); - printf("%4" PRId64 " BTU/hr ", tempbtuphrconv); - tempbtuphrconv = watt_to_btuphr_conversion(avgpower.lasthourpower); - printf("%4" PRId64 " BTU/hr ", tempbtuphrconv); - tempbtuphrconv = watt_to_btuphr_conversion(avgpower.lastdaypower); - printf("%4" PRId64 " BTU/hr ", tempbtuphrconv); - tempbtuphrconv = watt_to_btuphr_conversion(avgpower.lastweakpower); - printf("%4" PRId64 " BTU/hr\n", tempbtuphrconv); + tmp = watt_to_btuphr_conversion(avgpower.lastminutepower); + printf("%4" PRId64 " BTU/hr ", tmp); + tmp = watt_to_btuphr_conversion(avgpower.lasthourpower); + printf("%4" PRId64 " BTU/hr ", tmp); + tmp = watt_to_btuphr_conversion(avgpower.lastdaypower); + printf("%4" PRId64 " BTU/hr ", tmp); + tmp = watt_to_btuphr_conversion(avgpower.lastweakpower); + printf("%4" PRId64 " BTU/hr\n", tmp); printf("Max Power Consumption "); - tempbtuphrconv = watt_to_btuphr_conversion(stPeakpower.lastminutepower); - printf("%4" PRId64 " BTU/hr ", tempbtuphrconv); - tempbtuphrconv = watt_to_btuphr_conversion(stPeakpower.lasthourpower); - printf("%4" PRId64 " BTU/hr ", tempbtuphrconv); - tempbtuphrconv = watt_to_btuphr_conversion(stPeakpower.lastdaypower); - printf("%4" PRId64 " BTU/hr ", tempbtuphrconv); - tempbtuphrconv = watt_to_btuphr_conversion(stPeakpower.lastweakpower); - printf("%4" PRId64 " BTU/hr\n", tempbtuphrconv); + tmp = watt_to_btuphr_conversion(stPeakpower.lastminutepower); + printf("%4" PRId64 " BTU/hr ", tmp); + tmp = watt_to_btuphr_conversion(stPeakpower.lasthourpower); + printf("%4" PRId64 " BTU/hr ", tmp); + tmp = watt_to_btuphr_conversion(stPeakpower.lastdaypower); + printf("%4" PRId64 " BTU/hr ", tmp); + tmp = watt_to_btuphr_conversion(stPeakpower.lastweakpower); + printf("%4" PRId64 " BTU/hr\n", tmp); printf("Min Power Consumption "); - tempbtuphrconv = watt_to_btuphr_conversion(stMinpower.lastminutepower); - printf("%4" PRId64 " BTU/hr ", tempbtuphrconv); - tempbtuphrconv = watt_to_btuphr_conversion(stMinpower.lasthourpower); - printf("%4" PRId64 " BTU/hr ", tempbtuphrconv); - tempbtuphrconv = watt_to_btuphr_conversion(stMinpower.lastdaypower); - printf("%4" PRId64 " BTU/hr ", tempbtuphrconv); - tempbtuphrconv = watt_to_btuphr_conversion(stMinpower.lastweakpower); - printf("%4" PRId64 " BTU/hr\n\n", tempbtuphrconv); + tmp = watt_to_btuphr_conversion(stMinpower.lastminutepower); + printf("%4" PRId64 " BTU/hr ", tmp); + tmp = watt_to_btuphr_conversion(stMinpower.lasthourpower); + printf("%4" PRId64 " BTU/hr ", tmp); + tmp = watt_to_btuphr_conversion(stMinpower.lastdaypower); + printf("%4" PRId64 " BTU/hr ", tmp); + tmp = watt_to_btuphr_conversion(stMinpower.lastweakpower); + printf("%4" PRId64 " BTU/hr\n\n", tmp); } else { printf("Average Power Consumption "); - tempbtuphrconv = (avgpower.lastminutepower); - printf("%4" PRId64 " W ", tempbtuphrconv); - tempbtuphrconv = (avgpower.lasthourpower); - printf("%4" PRId64 " W ", tempbtuphrconv); - tempbtuphrconv = (avgpower.lastdaypower); - printf("%4" PRId64 " W ", tempbtuphrconv); - tempbtuphrconv=(avgpower.lastweakpower); - printf("%4" PRId64 " W \n", tempbtuphrconv); + tmp = avgpower.lastminutepower; + printf("%4" PRId64 " W ", tmp); + tmp = avgpower.lasthourpower; + printf("%4" PRId64 " W ", tmp); + tmp = avgpower.lastdaypower; + printf("%4" PRId64 " W ", tmp); + tmp = avgpower.lastweakpower; + printf("%4" PRId64 " W \n", tmp); printf("Max Power Consumption "); - tempbtuphrconv = (stPeakpower.lastminutepower); - printf("%4" PRId64 " W ", tempbtuphrconv); - tempbtuphrconv = (stPeakpower.lasthourpower); - printf("%4" PRId64 " W ", tempbtuphrconv); - tempbtuphrconv = (stPeakpower.lastdaypower); - printf("%4" PRId64 " W ", tempbtuphrconv); - tempbtuphrconv = (stPeakpower.lastweakpower); - printf("%4" PRId64 " W \n", tempbtuphrconv); + tmp = stPeakpower.lastminutepower; + printf("%4" PRId64 " W ", tmp); + tmp = stPeakpower.lasthourpower; + printf("%4" PRId64 " W ", tmp); + tmp = stPeakpower.lastdaypower; + printf("%4" PRId64 " W ", tmp); + tmp = stPeakpower.lastweakpower; + printf("%4" PRId64 " W \n", tmp); printf("Min Power Consumption "); - tempbtuphrconv = (stMinpower.lastminutepower); - printf("%4" PRId64 " W ", tempbtuphrconv); - tempbtuphrconv = (stMinpower.lasthourpower); - printf("%4" PRId64 " W ", tempbtuphrconv); - tempbtuphrconv = (stMinpower.lastdaypower); - printf("%4" PRId64 " W ", tempbtuphrconv); - tempbtuphrconv = (stMinpower.lastweakpower); - printf("%4" PRId64 " W \n\n", tempbtuphrconv); + tmp = stMinpower.lastminutepower; + printf("%4" PRId64 " W ", tmp); + tmp = stMinpower.lasthourpower; + printf("%4" PRId64 " W ", tmp); + tmp = stMinpower.lastdaypower; + printf("%4" PRId64 " W ", tmp); + tmp = stMinpower.lastweakpower; + printf("%4" PRId64 " W \n\n", tmp); } - lastminutepeakpower = stPeakpower.lastminutepowertime; - lasthourpeakpower = stPeakpower.lasthourpowertime; - lastdaypeakpower = stPeakpower.lastdaypowertime; - lastweekpeakpower = stPeakpower.lastweekpowertime; - printf("Max Power Time\n"); - ipmi_time_to_str(lastminutepeakpower, timestr); - printf("Last Minute : %s",timestr); - ipmi_time_to_str(lasthourpeakpower, timestr); - printf("Last Hour : %s",timestr); - ipmi_time_to_str(lastdaypeakpower, timestr); - printf("Last Day : %s",timestr); - ipmi_time_to_str(lastweekpeakpower, timestr); - printf("Last Week : %s",timestr); - - lastminutepeakpower=stMinpower.lastminutepowertime; - lasthourpeakpower=stMinpower.lasthourpowertime; - lastdaypeakpower=stMinpower.lastdaypowertime; - lastweekpeakpower=stMinpower.lastweekpowertime; + printf("Last Minute : %s", + ipmi_timestamp_numeric(stPeakpower.lastminutepowertime)); + printf("Last Hour : %s", + ipmi_timestamp_numeric(stPeakpower.lasthourpowertime)); + printf("Last Day : %s", + ipmi_timestamp_numeric(stPeakpower.lastdaypowertime)); + printf("Last Week : %s", + ipmi_timestamp_numeric(stPeakpower.lastweekpowertime)); printf("Min Power Time\n"); - ipmi_time_to_str(lastminutepeakpower, timestr); - printf("Last Minute : %s", timestr); - ipmi_time_to_str(lasthourpeakpower, timestr); - printf("Last Hour : %s", timestr); - ipmi_time_to_str(lastdaypeakpower, timestr); - printf("Last Day : %s", timestr); - ipmi_time_to_str(lastweekpeakpower, timestr); - printf("Last Week : %s", timestr); + printf("Last Minute : %s", + ipmi_timestamp_numeric(stMinpower.lastminutepowertime)); + printf("Last Hour : %s", + ipmi_timestamp_numeric(stMinpower.lasthourpowertime)); + printf("Last Day : %s", + ipmi_timestamp_numeric(stMinpower.lastdaypowertime)); + printf("Last Week : %s", + ipmi_timestamp_numeric(stMinpower.lastweekpowertime)); return rc; } /* diff --git a/lib/ipmi_ekanalyzer.c b/lib/ipmi_ekanalyzer.c index 2a91b03..b4fedaa 100644 --- a/lib/ipmi_ekanalyzer.c +++ b/lib/ipmi_ekanalyzer.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -2415,13 +2416,12 @@ ipmi_ek_display_fru_header_detail(char *filename) FILE *input_file; size_t file_offset = 0; struct fru_header header; - time_t tval; + time_t ts; int ret = 0; unsigned char data = 0; unsigned char lan_code = 0; unsigned char mfg_date[SIZE_MFG_DATE]; unsigned int board_length = 0; - struct tm *strtm; input_file = fopen(filename, "r"); if (!input_file) { @@ -2544,36 +2544,36 @@ ipmi_ek_display_fru_header_detail(char *filename) fclose(input_file); return (-1); } - tval = ((mfg_date[2] << 16) + (mfg_date[1] << 8) - + (mfg_date[0])); - tval = tval * 60; - tval = tval + secs_from_1970_1996; - if(time_in_utc) - strtm = gmtime(&tval); - else - strtm = localtime(&tval); - printf("Board Mfg Date: %ld, %s", tval, asctime(strtm)); + + ts = ipmi_fru2time_t(mfg_date); + printf("Board Mfg Date: %ld, %s\n", ts, ipmi_timestamp_numeric(ts)); board_length -= SIZE_MFG_DATE; + /* Board Mfg */ file_offset = ipmi_ek_display_board_info_area( input_file, "Board Manufacture Data", &board_length); ret = fseek(input_file, file_offset, SEEK_SET); + /* Board Product */ file_offset = ipmi_ek_display_board_info_area( input_file, "Board Product Name", &board_length); ret = fseek(input_file, file_offset, SEEK_SET); + /* Board Serial */ file_offset = ipmi_ek_display_board_info_area( input_file, "Board Serial Number", &board_length); ret = fseek(input_file, file_offset, SEEK_SET); + /* Board Part */ file_offset = ipmi_ek_display_board_info_area( input_file, "Board Part Number", &board_length); ret = fseek(input_file, file_offset, SEEK_SET); + /* FRU file ID */ file_offset = ipmi_ek_display_board_info_area( input_file, "FRU File ID", &board_length); ret = fseek(input_file, file_offset, SEEK_SET); + /* Additional Custom Mfg. */ file_offset = ipmi_ek_display_board_info_area( input_file, "Custom", &board_length); diff --git a/lib/ipmi_fru.c b/lib/ipmi_fru.c index fdfa2a7..2cbcf83 100644 --- a/lib/ipmi_fru.c +++ b/lib/ipmi_fru.c @@ -38,6 +38,7 @@ #include #include #include /* IANA id strings */ +#include #include #include @@ -997,9 +998,8 @@ fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru, uint8_t * fru_data; uint32_t fru_len; uint32_t i; - time_t tval; + time_t ts; uint8_t tmp[2]; - struct tm *strtm; fru_len = 0; @@ -1034,14 +1034,8 @@ fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru, */ i = 3; - tval=((fru_data[i+2] << 16) + (fru_data[i+1] << 8) + (fru_data[i])); - tval=tval * 60; - tval=tval + secs_from_1970_1996; - if(time_in_utc) - strtm = gmtime(&tval); - else - strtm = localtime(&tval); - printf(" Board Mfg Date : %s", asctime(strtm)); + ts = ipmi_fru2time_t(&fru_data[i]); + printf(" Board Mfg Date : %s\n", ipmi_timestamp_string(ts)); i += 3; /* skip mfg. date time */ fru_area = get_fru_area_str(fru_data, &i); diff --git a/lib/ipmi_mc.c b/lib/ipmi_mc.c index fe9dbda..e0b3ce6 100644 --- a/lib/ipmi_mc.c +++ b/lib/ipmi_mc.c @@ -47,6 +47,7 @@ #include #include #include +#include extern int verbose; @@ -731,8 +732,6 @@ ipmi_mc_print_guid(struct ipmi_intf *intf, ipmi_guid_mode_t guid_mode) [GUID_DUMP] = "Unknown (data dumped)" }; - char tbuf[40] = { 0 }; - struct tm *tm; int rc; rc = _ipmi_mc_get_guid(intf, (ipmi_guid_t *)guid_data); @@ -776,12 +775,7 @@ ipmi_mc_print_guid(struct ipmi_intf *intf, ipmi_guid_mode_t guid_mode) printf(" (%d)\n", GUID_VERSION((int)guid.time_hi_and_version)); break; case GUID_VERSION_TIME: - if(time_in_utc) - tm = gmtime(&guid.time); - else - tm = localtime(&guid.time); - strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", tm); - printf("\nTimestamp : %s\n", tbuf); + printf("\nTimestamp : %s\n", ipmi_timestamp_numeric(guid.time)); break; default: printf("\n"); diff --git a/lib/ipmi_pef.c b/lib/ipmi_pef.c index e950c81..db7446f 100644 --- a/lib/ipmi_pef.c +++ b/lib/ipmi_pef.c @@ -42,6 +42,7 @@ #include #include #include +#include #include extern int verbose; @@ -1193,8 +1194,6 @@ ipmi_pef2_get_status(struct ipmi_intf *intf) struct ipmi_rs *rsp; struct ipmi_rq req; struct pef_cfgparm_selector psel; - char tbuf[40]; - uint32_t timei; time_t ts; memset(&req, 0, sizeof(req)); @@ -1206,15 +1205,9 @@ ipmi_pef2_get_status(struct ipmi_intf *intf) "Last S/W processed ID"); return (-1); } - memcpy(&timei, rsp->data, sizeof(timei)); -#if WORDS_BIGENDIAN - timei = BSWAP_32(timei); -#endif - ts = (time_t)timei; - strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", gmtime(&ts)); - - ipmi_pef_print_str("Last SEL addition", tbuf); + ts = ipmi32toh(rsp->data); + ipmi_pef_print_str("Last SEL addition", ipmi_timestamp_numeric(ts)); ipmi_pef_print_2xd("Last SEL record ID", rsp->data[5], rsp->data[4]); ipmi_pef_print_2xd("Last S/W processed ID", rsp->data[7], rsp->data[6]); ipmi_pef_print_2xd("Last BMC processed ID", rsp->data[9], rsp->data[8]); diff --git a/lib/ipmi_sdr.c b/lib/ipmi_sdr.c index 2798b72..3a53e0c 100644 --- a/lib/ipmi_sdr.c +++ b/lib/ipmi_sdr.c @@ -52,6 +52,7 @@ #include #include #include +#include #if HAVE_CONFIG_H # include @@ -4209,24 +4210,6 @@ ipmi_sdr_get_info(struct ipmi_intf *intf, return 0; } -/* ipmi_sdr_timestamp - return string from timestamp value - * - * @stamp: 32bit timestamp - * - * returns pointer to static buffer - */ -static char * -ipmi_sdr_timestamp(time_t stamp) -{ - static char tbuf[40]; - time_t s = (time_t) stamp; - memset(tbuf, 0, 40); - if (stamp) - strftime(tbuf, sizeof (tbuf), "%m/%d/%Y %H:%M:%S", - gmtime(&s)); - return tbuf; -} - /* * ipmi_sdr_print_info * @@ -4278,7 +4261,7 @@ ipmi_sdr_print_info(struct ipmi_intf *intf) { timestamp = ipmi32toh(sdr_repository_info .most_recent_addition_timestamp); - printf("%s\n", ipmi_sdr_timestamp(timestamp)); + printf("%s\n", ipmi_timestamp_numeric(timestamp)); } else { printf("NA\n"); @@ -4288,7 +4271,7 @@ ipmi_sdr_print_info(struct ipmi_intf *intf) if(sdr_repository_info.delete_sdr_supported) { timestamp = ipmi32toh(sdr_repository_info .most_recent_erase_timestamp); - printf("%s\n", ipmi_sdr_timestamp(timestamp)); + printf("%s\n", ipmi_timestamp_numeric(timestamp)); } else { printf("NA\n"); diff --git a/lib/ipmi_sel.c b/lib/ipmi_sel.c index a9ef233..f7472b0 100644 --- a/lib/ipmi_sel.c +++ b/lib/ipmi_sel.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,7 @@ #include #include #include +#include static int sel_extended = 0; static int sel_oem_nrecs = 0; @@ -236,34 +238,6 @@ ipmi_get_event_type(uint8_t code) return "Reserved"; } -static char * -ipmi_sel_timestamp(uint32_t stamp) -{ - static char tbuf[40]; - time_t s = (time_t)stamp; - memset(tbuf, 0, 40); - strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", gmtime(&s)); - return tbuf; -} - -static char * -ipmi_sel_timestamp_date(uint32_t stamp) -{ - static char tbuf[11]; - time_t s = (time_t)stamp; - strftime(tbuf, sizeof(tbuf), "%m/%d/%Y", gmtime(&s)); - return tbuf; -} - -static char * -ipmi_sel_timestamp_time(uint32_t stamp) -{ - static char tbuf[9]; - time_t s = (time_t)stamp; - strftime(tbuf, sizeof(tbuf), "%H:%M:%S", gmtime(&s)); - return tbuf; -} - static char * hex2ascii (uint8_t * hexChars, uint8_t numBytes) { @@ -1592,14 +1566,14 @@ ipmi_sel_get_info(struct ipmi_intf * intf) printf("Last Add Time : Not Available\n"); else printf("Last Add Time : %s\n", - ipmi_sel_timestamp(buf2long(rsp->data + 5))); + ipmi_timestamp_numeric(buf2long(rsp->data + 5))); if ((!memcmp(rsp->data + 9, &fs, 4)) || (!memcmp(rsp->data + 9, &zeros, 4))) printf("Last Del Time : Not Available\n"); else printf("Last Del Time : %s\n", - ipmi_sel_timestamp(buf2long(rsp->data + 9))); + ipmi_timestamp_numeric(buf2long(rsp->data + 9))); printf("Overflow : %s\n", @@ -1837,18 +1811,19 @@ ipmi_sel_print_std_entry(struct ipmi_intf * intf, struct sel_event_record * evt) } else { if (evt->record_type < 0xc0) - printf("%s", ipmi_sel_timestamp_date(evt->sel_type.standard_type.timestamp)); + printf("%s", ipmi_timestamp_date(evt->sel_type.standard_type.timestamp)); else - printf("%s", ipmi_sel_timestamp_date(evt->sel_type.oem_ts_type.timestamp)); + printf("%s", ipmi_timestamp_date(evt->sel_type.oem_ts_type.timestamp)); + if (csv_output) printf(","); else printf(" | "); - + if (evt->record_type < 0xc0) - printf("%s", ipmi_sel_timestamp_time(evt->sel_type.standard_type.timestamp)); + printf("%s", ipmi_timestamp_time(evt->sel_type.standard_type.timestamp)); else - printf("%s", ipmi_sel_timestamp_time(evt->sel_type.oem_ts_type.timestamp)); + printf("%s", ipmi_timestamp_time(evt->sel_type.oem_ts_type.timestamp)); if (csv_output) printf(","); @@ -2055,11 +2030,11 @@ ipmi_sel_print_std_entry_verbose(struct ipmi_intf * intf, struct sel_event_recor { printf(" Timestamp : "); if (evt->record_type < 0xc0) - printf("%s %s", ipmi_sel_timestamp_date(evt->sel_type.standard_type.timestamp), - ipmi_sel_timestamp_time(evt->sel_type.standard_type.timestamp)); + printf("%s %s", ipmi_timestamp_date(evt->sel_type.standard_type.timestamp), + ipmi_timestamp_time(evt->sel_type.standard_type.timestamp)); else - printf("%s %s", ipmi_sel_timestamp_date(evt->sel_type.oem_ts_type.timestamp), - ipmi_sel_timestamp_time(evt->sel_type.oem_ts_type.timestamp)); + printf("%s %s", ipmi_timestamp_date(evt->sel_type.oem_ts_type.timestamp), + ipmi_timestamp_time(evt->sel_type.oem_ts_type.timestamp)); printf("\n"); } @@ -2145,8 +2120,8 @@ ipmi_sel_print_extended_entry_verbose(struct ipmi_intf * intf, struct sel_event_ if (evt->record_type < 0xe0) { printf(" Timestamp : "); - printf("%s %s\n", ipmi_sel_timestamp_date(evt->sel_type.standard_type.timestamp), - ipmi_sel_timestamp_time(evt->sel_type.standard_type.timestamp)); + printf("%s %s\n", ipmi_timestamp_date(evt->sel_type.standard_type.timestamp), + ipmi_timestamp_time(evt->sel_type.standard_type.timestamp)); } @@ -2725,8 +2700,6 @@ ipmi_sel_get_time(struct ipmi_intf * intf) { struct ipmi_rs * rsp; struct ipmi_rq req; - static char tbuf[40]; - uint32_t timei; time_t time; memset(&req, 0, sizeof(req)); @@ -2749,15 +2722,8 @@ ipmi_sel_get_time(struct ipmi_intf * intf) return -1; } - memcpy(&timei, rsp->data, 4); -#if WORDS_BIGENDIAN - time = (time_t)(BSWAP_32(timei)); -#else - time = (time_t)timei; -#endif - - strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", gmtime(&time)); - printf("%s\n", tbuf); + time = ipmi32toh(rsp->data); + printf("%s\n", ipmi_timestamp_numeric(time)); return 0; } @@ -2773,12 +2739,11 @@ ipmi_sel_get_time(struct ipmi_intf * intf) static int ipmi_sel_set_time(struct ipmi_intf * intf, const char * time_string) { - struct ipmi_rs * rsp; - struct ipmi_rq req; - struct tm tm = {0}; - time_t t; - uint32_t timei; - const char * time_format = "%m/%d/%Y %H:%M:%S"; + struct ipmi_rs *rsp; + struct ipmi_rq req; + struct tm tm = {0}; + time_t t; + const char *time_format = "%x %X"; /* Use locale-defined format */ memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_STORAGE; @@ -2787,57 +2752,43 @@ ipmi_sel_set_time(struct ipmi_intf * intf, const char * time_string) /* See if user requested set to current client system time */ if (strncasecmp(time_string, "now", 3) == 0) { t = time(NULL); + /* + * Now we have local time in t, but BMC requires UTC + */ + t = ipmi_localtime2utc(t); } else { - /* Now how do we get our time_t from our ascii version? */ - if (strptime(time_string, time_format, &tm) == 0) { + bool error = true; /* Assume the string is invalid */ + /* Now let's extract time_t from the supplied string */ + if (!strptime(time_string, time_format, &tm)) { + tm.tm_isdst = (-1); /* look up DST information */ + t = mktime(&tm); + if (t >= 0) { + /* Surprisingly, the user hasn't mistaken ;) */ + error = false; + } + } + + if (error) { lprintf(LOG_ERR, "Specified time could not be parsed"); return -1; } - tm.tm_isdst = (-1); /* look up DST information */ - t = mktime(&tm); - if (t < 0) { - lprintf(LOG_ERR, "Specified time could not be parsed"); - return -1; + + /* + * If `-c` wasn't specified then t we've just got is in local timesone + */ + if (!time_in_utc) { + t = ipmi_localtime2utc(t); } } - { - //modify UTC time to local time expressed in number of seconds from 1/1/70 0:0:0 1970 GMT - struct tm * tm_tmp = {0}; - int gt_year,gt_yday,gt_hour,gt_min,lt_year,lt_yday,lt_hour,lt_min; - int delta_hour; - tm_tmp=gmtime(&t); - gt_year=tm_tmp->tm_year; - gt_yday=tm_tmp->tm_yday; - gt_hour=tm_tmp->tm_hour; - gt_min=tm_tmp->tm_min; - memset(&*tm_tmp, 0, sizeof(struct tm)); - if(time_in_utc) - tm_tmp=gmtime(&t); - else - tm_tmp=localtime(&t); - lt_year=tm_tmp->tm_year; - lt_yday=tm_tmp->tm_yday; - lt_hour=tm_tmp->tm_hour; - lt_min=tm_tmp->tm_min; - delta_hour=lt_hour - gt_hour; - if ( (lt_year > gt_year) || ((lt_year == gt_year) && (lt_yday > gt_yday)) ) - delta_hour += 24; - if ( (lt_year < gt_year) || ((lt_year == gt_year) && (lt_yday < gt_yday)) ) - delta_hour -= 24; + /* + * At this point `t` is UTC. Convert it to LE and send. + */ - t += (delta_hour * 60 * 60) + (lt_min - gt_min) * 60; - } - - timei = (uint32_t)t; - req.msg.data = (uint8_t *)&timei; + htoipmi32(t, req.msg.data); req.msg.data_len = 4; -#if WORDS_BIGENDIAN - timei = BSWAP_32(timei); -#endif - rsp = intf->sendrecv(intf, &req); if (!rsp || rsp->ccode) { lprintf(LOG_ERR, "Set SEL Time command failed: %s", diff --git a/lib/ipmi_time.c b/lib/ipmi_time.c new file mode 100644 index 0000000..f2e01be --- /dev/null +++ b/lib/ipmi_time.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2018 Alexander Amelkin. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the copyright holder, nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * THE COPYRIGHT HOLDER AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * THE COPYRIGHT HOLDER OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, + * PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE + * THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS + * SOFTWARE, EVEN IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. + */ + +#include +#include +#include +#include /* snprintf */ + +#if HAVE_CONFIG_H +# include +#endif + +#include + +bool time_in_utc; /* Set by '-Z' command line option */ + +time_t +ipmi_localtime2utc(time_t local) +{ + struct tm tm; + gmtime_r(&local, &tm); + tm.tm_isdst = (-1); + return mktime(&tm); +} + +/** + * @brief Convert a timestamp to a formatted string, + * considering the '-Z' option. Acts as if tzset() was called. + * + * @param[out] s The output string buffer + * @param[in] max The size of the output string buffer including the + * terminating null byte + * @param[in] format The format string, as in strftime(), ignored for + * special timestamp values as per section 37.1 of + * IPMI v2.0 specification rev 1.1. + * @param[in] stamp The time stamp to convert + * + * @returns the number of bytes written to s or 0, see strftime() + */ +size_t +ipmi_strftime(char *s, int max, const char *format, time_t stamp) +{ + struct tm tm; + + if (IPMI_TIME_UNSPECIFIED == stamp) { + return snprintf(s, max, "Unknown"); + } + else if (stamp <= IPMI_TIME_INIT_DONE) { + /* Timestamp is relative to BMC start, no GMT offset */ + gmtime_r(&stamp, &tm); + + return strftime(s, max, format, &tm); + } + + if (time_in_utc || ipmi_timestamp_is_special(stamp)) { + /* + * The user wants the time reported in UTC or the stamp represents the + * number of seconds since system power on. In any case, don't apply + * the timezone offset. + */ + gmtime_r(&stamp, &tm); + daylight = -1; + } else { + /* + * The user wants the time reported in local time zone. + */ + localtime_r(&stamp, &tm); + } + return strftime(s, max, format, &tm); +} + +/** + * @brief Convert a timestamp to string, considering the '-Z' option. + * Similar to asctime_r(), but takes time_t instead of struct tm, + * and the string is in form "Wed Jun 30 21:49:08 1993 TZD" without + * the new line at the end. + * + * @param[in] stamp The timestamp to convert + * @param[out] outbuf The buffer to write the string to. + * @param[in] len The maximum length of the output buffer. + * Recommended size is IPMI_ASCTIME_SZ. + * + * @returns outbuf + */ +char * +ipmi_asctime_r(const time_t stamp, ipmi_datebuf_t outbuf) +{ + const char *format = "%c %Z"; + if (ipmi_timestamp_is_special(stamp)) { + if (stamp < SECONDS_A_DAY) { + format = "S+%H:%M:%S"; + } + /* + * IPMI_TIME_INIT_DONE is over 17 years. This should never + * happen normally, but we'll support this anyway. + */ + else { + format = "S+%yy %jd %H:%M:%S"; + } + } + + ipmi_strftime(outbuf, IPMI_ASCTIME_SZ, format, stamp); + return outbuf; +} + +char * +ipmi_timestamp_fmt(uint32_t stamp, const char *fmt) +{ + /* + * It's assumed that supplied 'fmt' is never longer + * than IPMI_ASCTIME_SZ + */ + static ipmi_datebuf_t datebuf; + ipmi_strftime(datebuf, sizeof(datebuf), fmt, stamp); + return datebuf; +} + +char * +ipmi_timestamp_string(uint32_t stamp) +{ + const char *format = "%c %Z"; + if (!ipmi_timestamp_is_valid(stamp)) { + return "Unspecified"; + } + + if (ipmi_timestamp_is_special(stamp)) { + if (stamp < SECONDS_A_DAY) { + format = "S+ %H:%M:%S"; + } + /* + * IPMI_TIME_INIT_DONE is over 17 years. This should never + * happen normally, but we'll support this anyway. + */ + else { + format = "S+ %y years %j days %H:%M:%S"; + } + } + return ipmi_timestamp_fmt(stamp, format); +} + +char * +ipmi_timestamp_numeric(uint32_t stamp) +{ + const char *format = "%x %X %Z"; + if (!ipmi_timestamp_is_valid(stamp)) { + return "Unspecified"; + } + + if (ipmi_timestamp_is_special(stamp)) { + if (stamp < SECONDS_A_DAY) { + format = "S+ %H:%M:%S"; + } + /* + * IPMI_TIME_INIT_DONE is over 17 years. This should never + * happen normally, but we'll support this anyway. + */ + else { + format = "S+ %y/%j %H:%M:%S"; + } + } + return ipmi_timestamp_fmt(stamp, format); +} + +char * +ipmi_timestamp_date(uint32_t stamp) +{ + const char *format = "%x"; + if (!ipmi_timestamp_is_valid(stamp)) { + return "Unspecified"; + } + + if (ipmi_timestamp_is_special(stamp)) { + format = "S+ %y/%j"; + } + return ipmi_timestamp_fmt(stamp, format); +} + +char * +ipmi_timestamp_time(uint32_t stamp) +{ + if (!ipmi_timestamp_is_valid(stamp)) { + return "Unspecified"; + } + + /* Format is the same for both normal and special timestamps */ + return ipmi_timestamp_fmt(stamp, "%X %Z"); +} diff --git a/src/ipmievd.c b/src/ipmievd.c index fefeb4a..8fbef41 100644 --- a/src/ipmievd.c +++ b/src/ipmievd.c @@ -88,7 +88,6 @@ char pidfile[64]; /* global variables */ int verbose = 0; int csv_output = 0; -int time_in_utc = 0; uint16_t selwatch_count = 0; /* number of entries in the SEL */ uint16_t selwatch_lastid = 0; /* current last entry in the SEL */ int selwatch_pctused = 0; /* current percent usage in the SEL */ diff --git a/src/ipmitool.c b/src/ipmitool.c index d1fa683..3ee8b50 100644 --- a/src/ipmitool.c +++ b/src/ipmitool.c @@ -80,9 +80,7 @@ extern int ipmi_set_main(struct ipmi_intf * intf, int argc, char ** argv); extern int ipmi_exec_main(struct ipmi_intf * intf, int argc, char ** argv); extern int ipmi_lan6_main(struct ipmi_intf *intf, int argc, char **argv); - int csv_output = 0; -int time_in_utc = 0; int verbose = 0; struct ipmi_cmd ipmitool_cmd_list[] = {