1 /*** dt-io-zone.c -- abstract from raw zone interface
2 *
3 * Copyright (C) 2010-2016 Sebastian Freundt
4 *
5 * Author: Sebastian Freundt <freundt@ga-group.nl>
6 *
7 * This file is part of dateutils.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of the author nor the names of any contributors
21 * may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
34 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 ***/
37 #if defined HAVE_CONFIG_H
38 # include "config.h"
39 #endif /* HAVE_CONFIG_H */
40 #include <string.h>
41 #include "tzmap.h"
42 #include "dt-io.h"
43 #include "dt-io-zone.h"
44 #include "alist.h"
45
46 #if defined TZMAP_DIR
47 static const char tmdir[] = TZMAP_DIR;
48 #else /* !TZMAP_DIR */
49 static const char tmdir[] = ".";
50 #endif /* TZMAP_DIR */
51 #define TZMAP_SUF ".tzmcc"
52
53 static size_t
xstrlncpy(char * restrict dst,size_t dsz,const char * src,size_t ssz)54 xstrlncpy(char *restrict dst, size_t dsz, const char *src, size_t ssz)
55 {
56 if (ssz > dsz) {
57 ssz = dsz - 1U;
58 }
59 memcpy(dst, src, ssz);
60 dst[ssz] = '\0';
61 return ssz;
62 }
63
64 static size_t
xstrlcpy(char * restrict dst,const char * src,size_t dsz)65 xstrlcpy(char *restrict dst, const char *src, size_t dsz)
66 {
67 size_t ssz = strlen(src);
68 if (ssz > dsz) {
69 ssz = dsz - 1U;
70 }
71 memcpy(dst, src, ssz);
72 dst[ssz] = '\0';
73 return ssz;
74 }
75
76
77 /* extended zone handling, tzmaps and stuff */
78 #if !defined PATH_MAX
79 # define PATH_MAX 256U
80 #endif /* !PATH_MAX */
81
82 static struct alist_s zones[1U];
83 static struct alist_s tzmaps[1U];
84
85 static tzmap_t
find_tzmap(const char * mnm,size_t mnz)86 find_tzmap(const char *mnm, size_t mnz)
87 {
88 static const char tzmap_suffix[] = TZMAP_SUF;
89 char tzmfn[PATH_MAX];
90 char *tp = tzmfn;
91 size_t tz = sizeof(tzmfn);
92 const char *p;
93 size_t z;
94
95 /* prefer TZMAP_DIR */
96 if ((p = getenv("TZMAP_DIR")) != NULL) {
97 z = xstrlcpy(tp, p, tz);
98 } else {
99 z = xstrlncpy(tp, tz, tmdir, sizeof(tmdir) - 1U);
100 }
101 tp += z, tz -= z;
102 *tp++ = '/', tz--;
103
104 /* try and find it the hard way */
105 xstrlncpy(tp, tz, mnm, mnz);
106 tp += mnz, tz -= mnz;
107 xstrlncpy(tp, tz, tzmap_suffix, sizeof(tzmap_suffix) - 1U);
108
109 /* try and open the thing, then try and look up SPEC */
110 return tzm_open(tzmfn);
111 }
112
113 static zif_t
__io_zone(const char * spec)114 __io_zone(const char *spec)
115 {
116 zif_t res;
117
118 /* try looking up SPEC first */
119 if ((res = alist_assoc(zones, spec)) == NULL) {
120 /* open 'im */
121 if ((res = zif_open(spec)) != NULL) {
122 /* cache 'im */
123 alist_put(zones, spec, res);
124 }
125 }
126 return res;
127 }
128
129 zif_t
dt_io_zone(const char * spec)130 dt_io_zone(const char *spec)
131 {
132 char *p;
133
134 if (spec == NULL) {
135 /* safety net */
136 return NULL;
137 }
138 /* see if SPEC is a MAP:KEY */
139 if ((p = strchr(spec, ':')) != NULL) {
140 char tzmfn[PATH_MAX];
141 tzmap_t tzm;
142
143 xstrlncpy(tzmfn, sizeof(tzmfn), spec, p - spec);
144
145 /* check tzmaps alist first */
146 if ((tzm = alist_assoc(tzmaps, tzmfn)) != NULL) {
147 ;
148 } else if ((tzm = find_tzmap(tzmfn, p - spec)) != NULL) {
149 /* cache the instance */
150 alist_put(tzmaps, tzmfn, tzm);
151 } else {
152 error("\
153 Cannot find `%s" TZMAP_SUF "' in the tzmaps search path\n\
154 Set TZMAP_DIR environment variable to where " TZMAP_SUF " files reside", tzmfn);
155 return NULL;
156 }
157 /* look up key bit in tzmap and use that if found */
158 if ((spec = tzm_find(tzm, ++p)) == NULL) {
159 return NULL;
160 }
161 }
162 return __io_zone(spec);
163 }
164
165 void
dt_io_clear_zones(void)166 dt_io_clear_zones(void)
167 {
168 if (tzmaps->data != NULL) {
169 for (acons_t c; (c = alist_next(tzmaps)).val;) {
170 tzm_close(c.val);
171 }
172 free_alist(tzmaps);
173 }
174 if (zones->data != NULL) {
175 for (acons_t c; (c = alist_next(zones)).val;) {
176 zif_close(c.val);
177 }
178 free_alist(zones);
179 }
180 return;
181 }
182
183 /* dt-io-zone.c ends here */
184