![]() |
![]() HP OpenVMS Systemsask the wizard |
![]() |
The Question is: Dear Wizard, We have a client program written in C that utilizes times to determine connection states. The code uses ctime and sys$getim for these calculations. Every so often, we will get a date "17-NOV-1858 00:00:00.00" and others with a completely irrelevant time " 17-NOV-1858 00:02:01.45". This prompted us to write a simplistic program that basicaaly makes a CTIME and SYS$GETTIM call every 5 seconds and writes output to a log file (Code enclosed for your reference). Our question is why do we periodically get the ba se date (or variation of)returned? --------------------------------------- #include <stdio.h> #include <ctype.h> #include <time.h> #include <string.h> #include <stdlib.h> #include <starlet.h> #include "procinfo.h" #include "vmsdt.h" #include <lib$routines.h> #include <unistd.h> int main void float seconds = 5.0; char command[256]; char timeBuffer[80]; char *p; VMSDateTime today = {0,0}; int returnStatus; VMSDateTime datetime; char m_buffer[80]; unsigned short length; Descriptor oBufferD = {25, 0, m_buffer}; FILE *fp = fopen("dtmmon:Time_Stamp_File.log","w","shr=get"); time_t now ; /* Get the current date time */ one_more_time: now = time(0); /* Get the current date time */ strcpy(timeBuffer, ctime(&now)); /* Put it in the buffer in human readable form */ p = strchr(timeBuffer,'\n'); /* Find the end of line */ if (p != NULL) /* And if it is found */ { *p = ' '; /* Replace it by a space */ } timeBuffer[19] = '\0'; /* Remove the year */ fprintf(fp," \n"); fprintf(fp,"Time using ctime(0) - %s \n",timeBuffer + 4); /* and timestamp the output */ returnStatus = sys$gettim(today); if (returnStatus == SS$_NORMAL) { strncpy(datetime, today, 8); returnStatus = sys$asctim(&length,&oBufferD,datetime,0); if (returnStatus == SS$_NORMAL) { m_buffer[length] = '\0'; fprintf(fp,"Time using sys$gettim - %s \n ",m_buffer); if ((strstr(&m_buffer[0],"17-NOV-1858")) != NULL) { sprintf (command,"mail nl:[].; peoples/subj=\"Base Date Detected"); system (command); } } else { fprintf(fp,"Bad Status return from sys$asctim - %d \n ",returnStatus); } } else { fprintf(fp,"Bad Status return from sys$gettim - %d \n ",returnStatus); } fsync(fileno(fp)); lib$wait (&seconds); goto one_more_time; --------------------------------------- This is a snipit of the log we are creating... Time using ctime(0) - Apr 13 12:49:22 Time using sys$gettim - 13-APR-2004 11:49:22.04 Time using ctime(0) - Apr 13 12:49:27 Time using sys$gettim - 13-APR-2004 11:49:27.04 Time using ctime(0) - Apr 13 12:49:32 Time using sys$gettim - 13-APR-2004 11:49:32.04 Time using ctime(0) - Apr 13 12:49:37 Time using sys$gettim - 17-NOV-1858 00:00:00.00 Time using ctime(0) - Apr 13 12:49:42 Time using sys$gettim - 13-APR-2004 11:49:42.22 Time using ctime(0) - Apr 13 12:49:47 Time using sys$gettim - 13-APR-2004 11:49:47.22 Time using ctime(0) - Apr 13 12:49:52 Time using sys$gettim - 13-APR-2004 11:49:52.23 Time using ctime(0) - Apr 13 12:49:57 Time using sys$gettim - 13-APR-2004 11:49:57.23 --------------------------------------- Thanks in advance Wizard... The Answer is : The central problem is in the following C statement: strncpy(datetime, today, 8); strncpy copies up to, but not including the null terminator of the source string for a maximum of 8 characters. If the length of the source string (today, here) is less than that of the target (datetime, here), then the target string will have a null and (usually) some bytes left over from the stack or the previous contents of datetime variable. Should the time contain a null byte (which can certainly happen, and with some frequency), or should there be no null at the end of the today string, then the str-class functions can copy too little or too much data. strncpy does limit the amount of data that can be transfered, but strcpy can sometimes copy rather more data than intended or can fail outright when the source string is not properly null-terminated. str-class functions can also fail with data referenced by string descriptors, as the strings involved are not necessarily null-terminated. memcpy would be preferable for a copy of binary data, or the use of the long long or __int64 construct and an assignment statement can be of interest for those configurations and compilers that support it. All OpenVMS C compilers also support a pair of longwords in an array, and the assignment of same. 17-Nov-1858 is the system base date, as referenced in the OpenVMS FAQ. The system base date in native time quadword format is a quadword zero. Additional details and related background are included in the FAQ. For new applications or non-trivial-scale updates to existing applications, the OpenVMS Wizard would encourage use of UTC services or UTC C library calls. Native time has limitations around the Timezone Differential Factor (TDF) and timezones. C native time has limitations around the scale of the longword, as common C calls use the number of seconds since 1980 and this value will obviously overflow circa 2038 and quite possibly sooner depending on the manipulations and the use of signed values. The OpenVMS Wizard will discourage the use of the localtime as a key value for a transaction long or indexed file, as it is not unique (beyond the ganularity of the system clock ticks) and (with daylight savings) may not be a uniformly and perpetually increasing value. For applications that use localtime, the TDF change event available in recent OpenVMS releases can also be of interest. This event allows applications to be notified whenthe daylight savings time switch (to or from standard time) occurs. For discussions of time and for discussions of common C coding mistakes, please see the OpeNVMS FAQ. Also please see the discussions of common coding mistakes here in topic (1661) and other topics referenced there. (In the experience of the OpenVMS Wizard, time and timekeeping is far more interesting and involved and detailed than it might initially appear, and null bytes latent within the native quadword time value are just one small aspect of time and timekeeping.) Depending on the declaration of Descriptor used within the application, there may well be an additional bug. Use of descrip.h and the $DESCRIPTOR macro and.or the dsc structures and constants is more commonly expected. In particular, please see the discussions of string descriptors and of padding within the OpenVMS FAQ. You can also default the quadword time argument to sys$asctim, and get it to return the current system time in ASCII format. Various of the example can be completely eliminated, in other words. For example, the following uses the current time: ReturnStatus = sys$asctim( NULL, OutputBufferDsc, NULL, 0 ); Also note that the internal implementations of C and OpenVMS timekeeping -- while based on the same internal values -- can and do differ. In particular, please see the off-by-an-hour discussion in the OpenVMS FAQ. OpenVMS Freeware V5.0 directory srh_examples examples include dsbd.c and various other time-calling examples located there, as well as various examples in the Programming Concepts Manual and in the C programming documentation. There are also pointers to available examples located in the FAQ.
|