1109998Smarkm/* crypto/o_time.c -*- mode:C; c-file-style: "eay" -*- */
2296465Sdelphij/*
3296465Sdelphij * Written by Richard Levitte (richard@levitte.org) for the OpenSSL project
4296465Sdelphij * 2001.
5109998Smarkm */
6109998Smarkm/* ====================================================================
7109998Smarkm * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
8109998Smarkm *
9109998Smarkm * Redistribution and use in source and binary forms, with or without
10109998Smarkm * modification, are permitted provided that the following conditions
11109998Smarkm * are met:
12109998Smarkm *
13109998Smarkm * 1. Redistributions of source code must retain the above copyright
14296465Sdelphij *    notice, this list of conditions and the following disclaimer.
15109998Smarkm *
16109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
17109998Smarkm *    notice, this list of conditions and the following disclaimer in
18109998Smarkm *    the documentation and/or other materials provided with the
19109998Smarkm *    distribution.
20109998Smarkm *
21109998Smarkm * 3. All advertising materials mentioning features or use of this
22109998Smarkm *    software must display the following acknowledgment:
23109998Smarkm *    "This product includes software developed by the OpenSSL Project
24109998Smarkm *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25109998Smarkm *
26109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27109998Smarkm *    endorse or promote products derived from this software without
28109998Smarkm *    prior written permission. For written permission, please contact
29109998Smarkm *    licensing@OpenSSL.org.
30109998Smarkm *
31109998Smarkm * 5. Products derived from this software may not be called "OpenSSL"
32109998Smarkm *    nor may "OpenSSL" appear in their names without prior written
33109998Smarkm *    permission of the OpenSSL Project.
34109998Smarkm *
35109998Smarkm * 6. Redistributions of any form whatsoever must retain the following
36109998Smarkm *    acknowledgment:
37109998Smarkm *    "This product includes software developed by the OpenSSL Project
38109998Smarkm *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39109998Smarkm *
40109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43109998Smarkm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
52109998Smarkm * ====================================================================
53109998Smarkm *
54109998Smarkm * This product includes cryptographic software written by Eric Young
55109998Smarkm * (eay@cryptsoft.com).  This product includes software written by Tim
56109998Smarkm * Hudson (tjh@cryptsoft.com).
57109998Smarkm *
58109998Smarkm */
59109998Smarkm
60109998Smarkm#include <openssl/e_os2.h>
61109998Smarkm#include <string.h>
62109998Smarkm#include "o_time.h"
63109998Smarkm
64109998Smarkm#ifdef OPENSSL_SYS_VMS
65109998Smarkm# include <libdtdef.h>
66109998Smarkm# include <lib$routines.h>
67109998Smarkm# include <lnmdef.h>
68109998Smarkm# include <starlet.h>
69109998Smarkm# include <descrip.h>
70109998Smarkm# include <stdlib.h>
71109998Smarkm#endif
72109998Smarkm
73109998Smarkmstruct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result)
74296465Sdelphij{
75296465Sdelphij    struct tm *ts = NULL;
76109998Smarkm
77120631Snectar#if defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_SYS_OS2) && !defined(__CYGWIN32__) && (!defined(OPENSSL_SYS_VMS) || defined(gmtime_r)) && !defined(OPENSSL_SYS_MACOSX) && !defined(OPENSSL_SYS_SUNOS)
78296465Sdelphij    /*
79296465Sdelphij     * should return &data, but doesn't on some systems, so we don't even
80296465Sdelphij     * look at the return value
81296465Sdelphij     */
82296465Sdelphij    gmtime_r(timer, result);
83296465Sdelphij    ts = result;
84109998Smarkm#elif !defined(OPENSSL_SYS_VMS)
85296465Sdelphij    ts = gmtime(timer);
86296465Sdelphij    if (ts == NULL)
87296465Sdelphij        return NULL;
88120631Snectar
89296465Sdelphij    memcpy(result, ts, sizeof(struct tm));
90296465Sdelphij    ts = result;
91109998Smarkm#endif
92109998Smarkm#ifdef OPENSSL_SYS_VMS
93296465Sdelphij    if (ts == NULL) {
94296465Sdelphij        static $DESCRIPTOR(tabnam, "LNM$DCL_LOGICAL");
95296465Sdelphij        static $DESCRIPTOR(lognam, "SYS$TIMEZONE_DIFFERENTIAL");
96296465Sdelphij        char logvalue[256];
97296465Sdelphij        unsigned int reslen = 0;
98296465Sdelphij        struct {
99296465Sdelphij            short buflen;
100296465Sdelphij            short code;
101296465Sdelphij            void *bufaddr;
102296465Sdelphij            unsigned int *reslen;
103296465Sdelphij        } itemlist[] = {
104296465Sdelphij            {
105296465Sdelphij                0, LNM$_STRING, 0, 0
106296465Sdelphij            },
107296465Sdelphij            {
108296465Sdelphij                0, 0, 0, 0
109296465Sdelphij            },
110296465Sdelphij        };
111296465Sdelphij        int status;
112296465Sdelphij        time_t t;
113109998Smarkm
114296465Sdelphij        /* Get the value for SYS$TIMEZONE_DIFFERENTIAL */
115296465Sdelphij        itemlist[0].buflen = sizeof(logvalue);
116296465Sdelphij        itemlist[0].bufaddr = logvalue;
117296465Sdelphij        itemlist[0].reslen = &reslen;
118296465Sdelphij        status = sys$trnlnm(0, &tabnam, &lognam, 0, itemlist);
119296465Sdelphij        if (!(status & 1))
120296465Sdelphij            return NULL;
121296465Sdelphij        logvalue[reslen] = '\0';
122109998Smarkm
123296465Sdelphij        t = *timer;
124142425Snectar
125142425Snectar/* The following is extracted from the DEC C header time.h */
126296465Sdelphij        /*
127296465Sdelphij         **  Beginning in OpenVMS Version 7.0 mktime, time, ctime, strftime
128296465Sdelphij         **  have two implementations.  One implementation is provided
129296465Sdelphij         **  for compatibility and deals with time in terms of local time,
130296465Sdelphij         **  the other __utc_* deals with time in terms of UTC.
131296465Sdelphij         */
132296465Sdelphij        /*
133296465Sdelphij         * We use the same conditions as in said time.h to check if we should
134296465Sdelphij         * assume that t contains local time (and should therefore be
135296465Sdelphij         * adjusted) or UTC (and should therefore be left untouched).
136296465Sdelphij         */
137296465Sdelphij# if __CRTL_VER < 70000000 || defined _VMS_V6_SOURCE
138296465Sdelphij        /* Get the numerical value of the equivalence string */
139296465Sdelphij        status = atoi(logvalue);
140109998Smarkm
141296465Sdelphij        /* and use it to move time to GMT */
142296465Sdelphij        t -= status;
143296465Sdelphij# endif
144109998Smarkm
145296465Sdelphij        /* then convert the result to the time structure */
146142425Snectar
147296465Sdelphij        /*
148296465Sdelphij         * Since there was no gmtime_r() to do this stuff for us, we have to
149296465Sdelphij         * do it the hard way.
150296465Sdelphij         */
151296465Sdelphij        {
152296465Sdelphij            /*-
153296465Sdelphij             * The VMS epoch is the astronomical Smithsonian date,
154296465Sdelphij               if I remember correctly, which is November 17, 1858.
155296465Sdelphij               Furthermore, time is measure in thenths of microseconds
156296465Sdelphij               and stored in quadwords (64 bit integers).  unix_epoch
157296465Sdelphij               below is January 1st 1970 expressed as a VMS time.  The
158296465Sdelphij               following code was used to get this number:
159109998Smarkm
160296465Sdelphij               #include <stdio.h>
161296465Sdelphij               #include <stdlib.h>
162296465Sdelphij               #include <lib$routines.h>
163296465Sdelphij               #include <starlet.h>
164109998Smarkm
165296465Sdelphij               main()
166296465Sdelphij               {
167296465Sdelphij                 unsigned long systime[2];
168296465Sdelphij                 unsigned short epoch_values[7] =
169296465Sdelphij                   { 1970, 1, 1, 0, 0, 0, 0 };
170109998Smarkm
171296465Sdelphij                 lib$cvt_vectim(epoch_values, systime);
172109998Smarkm
173296465Sdelphij                 printf("%u %u", systime[0], systime[1]);
174296465Sdelphij               }
175296465Sdelphij            */
176296465Sdelphij            unsigned long unix_epoch[2] = { 1273708544, 8164711 };
177296465Sdelphij            unsigned long deltatime[2];
178296465Sdelphij            unsigned long systime[2];
179296465Sdelphij            struct vms_vectime {
180296465Sdelphij                short year, month, day, hour, minute, second, centi_second;
181296465Sdelphij            } time_values;
182296465Sdelphij            long operation;
183109998Smarkm
184296465Sdelphij            /*
185296465Sdelphij             * Turn the number of seconds since January 1st 1970 to an
186296465Sdelphij             * internal delta time. Note that lib$cvt_to_internal_time() will
187296465Sdelphij             * assume that t is signed, and will therefore break on 32-bit
188296465Sdelphij             * systems some time in 2038.
189296465Sdelphij             */
190296465Sdelphij            operation = LIB$K_DELTA_SECONDS;
191296465Sdelphij            status = lib$cvt_to_internal_time(&operation, &t, deltatime);
192109998Smarkm
193296465Sdelphij            /*
194296465Sdelphij             * Add the delta time with the Unix epoch and we have the current
195296465Sdelphij             * UTC time in internal format
196296465Sdelphij             */
197296465Sdelphij            status = lib$add_times(unix_epoch, deltatime, systime);
198109998Smarkm
199296465Sdelphij            /* Turn the internal time into a time vector */
200296465Sdelphij            status = sys$numtim(&time_values, systime);
201109998Smarkm
202296465Sdelphij            /* Fill in the struct tm with the result */
203296465Sdelphij            result->tm_sec = time_values.second;
204296465Sdelphij            result->tm_min = time_values.minute;
205296465Sdelphij            result->tm_hour = time_values.hour;
206296465Sdelphij            result->tm_mday = time_values.day;
207296465Sdelphij            result->tm_mon = time_values.month - 1;
208296465Sdelphij            result->tm_year = time_values.year - 1900;
209109998Smarkm
210296465Sdelphij            operation = LIB$K_DAY_OF_WEEK;
211296465Sdelphij            status = lib$cvt_from_internal_time(&operation,
212296465Sdelphij                                                &result->tm_wday, systime);
213296465Sdelphij            result->tm_wday %= 7;
214109998Smarkm
215296465Sdelphij            operation = LIB$K_DAY_OF_YEAR;
216296465Sdelphij            status = lib$cvt_from_internal_time(&operation,
217296465Sdelphij                                                &result->tm_yday, systime);
218296465Sdelphij            result->tm_yday--;
219109998Smarkm
220296465Sdelphij            result->tm_isdst = 0; /* There's no way to know... */
221109998Smarkm
222296465Sdelphij            ts = result;
223296465Sdelphij        }
224296465Sdelphij    }
225109998Smarkm#endif
226296465Sdelphij    return ts;
227296465Sdelphij}
228